Это означает именно то, что написано на консервной банке - это измерение производительности чего-то «маленького», например, системного вызова ядра операционной системы.
Опасность состоит в том, что люди могут использовать любые результаты микробенчмаркинга, чтобы диктовать оптимизацию. И как все мы знаем:
Мы должны забыть о небольшой эффективности, скажем, примерно в 97% случаев: преждевременная оптимизация - корень всех зол », - Дональд Кнут
Результат микротестов может быть искажен по многим причинам. Оптимизация компилятора - одна из них. Если измеряемая операция занимает так мало времени, что все, что вы используете для измерения, занимает больше времени, чем сама операция, ваши микротесты также будут искажены.
Например, кто-то может провести микробенчмарк накладных расходов for
циклов:
void TestForLoop()
{
time start = GetTime();
for(int i = 0; i < 1000000000; ++i)
{
}
time elapsed = GetTime() - start;
time elapsedPerIteration = elapsed / 1000000000;
printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
}
Очевидно, компиляторы могут видеть, что цикл абсолютно ничего не делает и вообще не генерирует никакого кода для цикла. Таким образом, значение elapsed
и elapsedPerIteration
практически бесполезно.
Даже если цикл что-то делает:
void TestForLoop()
{
int sum = 0;
time start = GetTime();
for(int i = 0; i < 1000000000; ++i)
{
++sum;
}
time elapsed = GetTime() - start;
time elapsedPerIteration = elapsed / 1000000000;
printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
}
Компилятор может увидеть, что переменная sum
не будет использоваться ни для чего, и оптимизирует ее, а также оптимизирует цикл for. Но ждать! Что, если мы сделаем это:
void TestForLoop()
{
int sum = 0;
time start = GetTime();
for(int i = 0; i < 1000000000; ++i)
{
++sum;
}
time elapsed = GetTime() - start;
time elapsedPerIteration = elapsed / 1000000000;
printf("Time elapsed for each iteration: %d\n", elapsedPerIteration);
printf("Sum: %d\n", sum); // Added
}
Компилятор может быть достаточно умен, чтобы понять, что sum
всегда будет постоянным значением, и оптимизировать все это. Многие были бы удивлены возможностями оптимизации компиляторов в наши дни.
Но как насчет того, что компиляторы не могут оптимизировать?
void TestFileOpenPerformance()
{
FILE* file = NULL;
time start = GetTime();
for(int i = 0; i < 1000000000; ++i)
{
file = fopen("testfile.dat");
fclose(file);
}
time elapsed = GetTime() - start;
time elapsedPerIteration = elapsed / 1000000000;
printf("Time elapsed for each file open: %d\n", elapsedPerIteration);
}
Даже это бесполезный тест! Операционная система может видеть, что файл открывается очень часто, поэтому может предварительно загрузить его в память для повышения производительности. Практически все операционные системы делают это. То же самое происходит, когда вы открываете приложения - операционные системы могут определить ~ 5 приложений, которые вы открываете чаще всего, и предварительно загрузить код приложения в память при загрузке компьютера!
Фактически, в игру вступает бесчисленное множество переменных: местоположение ссылки (например, массивы или связанные списки), влияние кешей и пропускной способности памяти, встраивание компилятора, реализация компилятора, переключатели компилятора, количество ядер процессора, оптимизация на уровне процессора. , планировщики операционных систем, фоновые процессы операционной системы и т. д.
Так что во многих случаях микробенчмаркинг не совсем полезный показатель. Это определенно не заменяет тесты производительности всей программы четко определенными тестовыми примерами (профилирование). Сначала напишите читаемый код, затем профилируйте, чтобы увидеть, что нужно сделать, если таковые имеются.
Я хотел бы подчеркнуть, что микробенчмарки не являются злом сами по себе, но их нужно использовать осторожно (это верно для многих других вещей, связанных с компьютерами)
person
Community
schedule
16.05.2010