Статистические профилировщики:
Пример использования perf:
perf stat -e cycles,instructions,cache-misses ./my_program
Библиотеки:
Пример Google Benchmark:
#include <benchmark/benchmark.h>
static void BM_StringCreation(benchmark::State& state) {
for (auto _ : state) {
std::string empty_string;
benchmark::DoNotOptimize(empty_string);
}
}
BENCHMARK(BM_StringCreation);
BENCHMARK_MAIN();
Техники:
Рекомендации:
Подходы:
// Плохо: накладные расходы на вызов clock()
start = clock();
function_to_measure();
end = clock();
// Лучше: многократный вызов в цикле
start = high_resolution_clock::now();
for (int i = 0; i < N; ++i) {
function_to_measure();
}
end = high_resolution_clock::now();
avg_time = (end - start)/N;
Ключевые метрики:
Пример считывания через Linux perf:
perf stat -e cycles,instructions,cache-references,cache-misses ./app
template <typename Func>
auto measure(Func&& f) {
warmup_run(); // Прогрев кэша
auto start = high_resolution_clock::now();
auto result = f();
auto end = high_resolution_clock::now();
benchmark::DoNotOptimize(result); // Запрет оптимизаций
return std::make_pair(result, end - start);
}
Для точных низкоуровневых замеров:
inline uint64_t rdtsc() {
uint32_t lo, hi;
asm volatile (
"rdtsc" : "=a" (lo), "=d" (hi)
);
return ((uint64_t)hi << 32) | lo;
}
void measure_rdtsc() {
const uint64_t start = rdtsc();
critical_code();
const uint64_t end = rdtsc();
const uint64_t cycles = end - start;
}
Техники:
Необходимые метрики:
Пример с Google Benchmark:
BENCHMARK(BM_Test)
->ComputeStatistics("max", [](const std::vector<double>& v) {
return *std::max_element(v.begin(), v.end());
})
->Repetitions(10)
->DisplayAggregatesOnly();
Проблемные места:
Решение:
// Запрет оптимизации для переменных
benchmark::DoNotOptimize(value);
// Запрет реордеринга операций
benchmark::ClobberMemory();
Техники:
Ключевые методики измерения производительности:
Для получения достоверных результатов:
Помните: "Мы не можем оптимизировать то, что не можем измерить" (А. Кэй). Качественные замеры - основа эффективной оптимизации.