Что такое микробенчмаркинг?

Я слышал, что этот термин используется, но я не совсем уверен, что он означает, поэтому:

  • Что это означает, а что НЕ?
  • Какие примеры микробенчмаркинга ЕСТЬ и НЕ НЕТ?
  • What are the dangers of microbenchmarking and how do you avoid it?
    • (or is it a good thing?)

person polygenelubricants    schedule 16.05.2010    source источник
comment
Мне пора спать, поэтому вот просто глупый комментарий со ссылкой, чтобы вы начали читать материал: java.sun.com/docs/hotspot/HotSpotFAQ.html (проверьте главы сравнительного анализа внизу оглавления).   -  person BalusC    schedule 16.05.2010
comment
Всего 1 миллионная полезность, как бенчмаркинг :-)   -  person Stephen C    schedule 16.05.2010
comment
code.google.com/p/caliper/wiki/JavaMicrobenchmarks   -  person polygenelubricants    schedule 29.05.2010


Ответы (6)


Это означает именно то, что написано на консервной банке - это измерение производительности чего-то «маленького», например, системного вызова ядра операционной системы.

Опасность состоит в том, что люди могут использовать любые результаты микробенчмаркинга, чтобы диктовать оптимизацию. И как все мы знаем:

Мы должны забыть о небольшой эффективности, скажем, примерно в 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
comment
Хороший комментарий, хотя Кнут имел в виду, что преждевременное рассмотрение оптимизаций не должно влиять на ДИЗАЙН (а не диктовать оптимизацию). Учет дизайна результатов ранних тестов часто приводит к негибкому дизайну. en.wikipedia.org/wiki/Program_optimization - person Eric J.; 16.05.2010
comment
Верно, но я могу добавить, что то, как кто-то оптимизирует программу, может повлиять на ее дизайн. Я пытаюсь объяснить, что микробенчмаркинг редко дает полезную информацию. - person In silico; 16.05.2010
comment
Должны ли эти программы действительно печатать накладные расходы, когда печатаются не накладные расходы, а все время на итерацию? - person Thomas Padron-McCarthy; 16.05.2010
comment
Я изменил его на Time elapsed for <whatever>, что, я полагаю, является более точным термином для того, что мы измеряем. Но с помощью микробенчмарков то, что вы измеряете, может не иметь ничего общего с самим кодом! - person In silico; 16.05.2010
comment
На самом деле Кнут имел в виду оптимизацию производительности, сделанную с очень небольшим пониманием работы программного обеспечения. - person William Louth; 25.05.2010
comment
увидеть, что файл открывается очень часто, поэтому он может предварительно загрузить его. Метаданные файла будут оставаться горячими в кеше VFS сразу после его открытия / закрытия для любой реальной ОС. Ему не нужно обнаруживать какой-либо специальный шаблон или что-то еще, просто он работает как обычный псевдо-LRU-кеш для метаданных файловой системы (например, кеш VFS Linux) и данных (кэш страниц). В этом нет ничего удивительного или особенного. Это хорошо известный факт, что, например, time find /usr/lib > /dev/null бежит во второй раз на путь быстрее. - person Peter Cordes; 03.09.2016

Определения микротеста нет, но когда я его использую, я имею в виду небольшой искусственный тест, предназначенный для проверки производительности некоторого конкретного аппаратного 1 или языковой функции. Напротив, лучший тест - это реальная программа, предназначенная для выполнения реальной задачи. (Проводить жесткую грань между двумя случаями бессмысленно, ИМО, и я не буду пытаться.)

Опасность микробенчмаркинга заключается в том, что легко написать тест, который дает результаты, которые полностью вводят в заблуждение. Вот некоторые распространенные ловушки микро-тестов Java:

  • написание кода, который компилятор может определить, бесполезно, и поэтому полностью оптимизировать,
  • не принимая во внимание "комковатую" природу управления памятью Java, и
  • без учета эффектов запуска JVM; например время, необходимое для загрузки и JIT-компиляции классов, и (наоборот) ускорение выполнения, которое происходит после JIT-компиляции методов.

Однако даже после того, как вы решите вышеперечисленные проблемы, существует системная проблема с тестированием производительности, которую невозможно решить. Код и поведение теста обычно мало связаны с тем, что вас действительно волнует; т.е. как ваше приложение будет работать. Существует слишком много «скрытых переменных», чтобы вы могли сделать выводы, начиная с эталонного теста и заканчивая типичными программами, не говоря уже о вашей программе.

По этим причинам мы регулярно советуем НЕ тратить время на микротест. Вместо этого лучше писать простой и естественный код и использовать профилировщик для определения областей, которые необходимо оптимизировать вручную. Интересно, что обычно оказывается, что наиболее значительные проблемы с производительностью в реальных приложениях возникают из-за плохого проектирования структур данных и алгоритмов (включая узкие места, связанные с сетью, базами данных и потоковой передачи), а не из-за того, что типичные микротесты пытаются решить. контрольная работа.

@BalusC предоставил отличную ссылку на материалы по этой теме в FAQ по Hotspot страница. А вот ссылка на технический документ IBM от Брайана Гетца.


1 - Эксперты даже не стали бы пытаться проводить тестирование оборудования на Java. Между байт-кодами и оборудованием происходит слишком много «сложных вещей», чтобы сделать правильные / полезные выводы об оборудовании из необработанных результатов. Вам будет лучше использовать язык, более близкий к аппаратному обеспечению; например C или даже код сборки.

person Stephen C    schedule 16.05.2010
comment
1-й абзац: микробенчмаркинг не хуже и не лучше. Это просто полезно для разных вещей. Если вы хотите узнать задержку использования загрузки кэша L1D для конкретной модели ЦП, вы используете микротест вместо того, чтобы пытаться почерпнуть эту информацию из частоты кадров Crysis, SPECint2006 и любых других тестов, не относящихся к микропрограммам. Вы бы использовали это число, если бы настраивали какую-то другую функцию, которая часто отслеживает указатели в небольшом наборе данных, чтобы сделать обоснованное предположение о том, была ли задержка использования нагрузки L1D основным узким местом , или если бы вместо этого можно было настроить что-то другое. - person Peter Cordes; 03.09.2016
comment
Тем не менее, микробенчмаркинг отдельных языковых конструкций на языках высокого уровня с помощью оптимизирующих компиляторов обычно является полной подделкой. Если вы посмотрите на asm, разница в том, как компилятор создает цикл с for() против do{}while() или if() против x ? y : z (и какой из них лучше), обычно зависит от окружающего кода, а не от языковой конструкции. - person Peter Cordes; 03.09.2016
comment
(Думаю, когда я комментировал пару лет назад, я не заметил, что вопрос был помечен как Java. Да, согласился, что вы не можете использовать Java, чтобы узнать об оборудовании, только чтобы узнать, как ваша JVM работает на вашем оборудовании. И сделать микробенчмаркинг небольшая часть более крупной функции может привести к ее оптимизации по-другому, особенно с использованием информации о профилировании, доступной во время выполнения ... Так что да, 100% согласны, микробенчмаркинг Java, вероятно, не лучший план, даже с использованием чего-то вроде JMH, что делает его несколько достижимый.) - person Peter Cordes; 08.05.2019

В книге «Производительность Java: полное руководство» есть это определение и пример микробенчмарков:

  1. Микробенчмарки

    Микробенчмарк - это тест, предназначенный для измерения производительности очень небольшого устройства: времени для вызова синхронизированного метода по сравнению с несинхронизированным методом; накладные расходы на создание потока по сравнению с использованием пула потоков; время выполнения одного арифметического алгоритма по сравнению с альтернативной реализацией; и так далее.

    Микробенчмарки могут показаться хорошей идеей, но их очень сложно написать правильно. Рассмотрим следующий код, который представляет собой попытку написать микробенчмарк, который проверяет производительность различных реализаций метода вычисления 50-го числа Фибоначчи:

public void doTest(){
double l;
long then = System.currentTimeMillis();

for(int i = 0; i < nLoops; i++){
 l = fibImpl1(50);
}

long now = system.currentTimeMillis();
System.out.println("Elapsed time: " + (now - then))

}

...

private double fibImpl1(int n){
if(n < 0) throw new IllegalArgumentException("Must be > 0");
if(n == 0) return 0d;
if(n == 1) return 1d;
double d = fibImpl1(n - 2) + fibImpl(n - 1);
if(Double.isInfinited(d)) throw new ArithmeticException("Overflow");
return d;
}

Микробенчмарки должны использовать их результаты.

Самая большая проблема с этим кодом заключается в том, что он никогда не меняет состояние программы. Поскольку результат вычисления Фибоначчи никогда не используется, компилятор может отказаться от этого вычисления. Умный компилятор (включая текущие компиляторы Java 7 и 8) в конечном итоге выполнит этот код:

long then = System.currentTimeMillis();
long now = System.currentTimeMillis();
System.out.println("Elapsed time: " + (now - then));

В результате прошедшее время будет всего несколько миллисекунд, независимо от реализации метода Фибоначчи или количества раз, которое предполагается выполнить цикл.

Есть способ обойти эту конкретную проблему: убедиться, что каждый результат читается, а не просто записывается. На практике изменение определения l с локальной переменной на переменную экземпляра (объявленную с ключевым словом volatile) позволит измерить производительность метода.

person castilloRT    schedule 03.09.2016
comment
Практически всегда нужно смотреть на вывод оптимизирующего компилятора на языке ассемблера, чтобы убедиться, что ваш микробенчмарк действительно измеряет то, что вы планировали. Очень легко оптимизировать то, что вы не планировали. Я определенно согласен с тем, что их сложно написать правильно. Так много вопросов о производительности в SO получают комментарии вроде: почему бы не измерить это самостоятельно? - person Peter Cordes; 03.09.2016

  • Что это означает, а что НЕ?

Я бы сказал, что микротест - это просто измерение чего-то крошечного. Tiny, вероятно, зависит от контекста, но обычно на уровне отдельного системного вызова или чего-то подобного. Бенчмаркинг относится ко всему вышеперечисленному.

  • Какие примеры микробенчмаркинга ЕСТЬ и НЕ НЕТ?

В этой (заархивированной) статье перечислены измерение времени системного вызова getpid () и измерение времени для копирования памяти с помощью memcpy () в качестве примеров микробенчмаркинга.

Любое измерение реализации алгоритма и т. Д. Не будет считаться микробенчмаркингом. В частности, отчеты о результатах, в которых перечислены задачи с уменьшающимся временем выполнения, вероятно, редко считаются микробенчмаркингом.

  • В чем опасность микробенчмаркинга и как его избежать?

Очевидная опасность состоит в том, что это соблазняет разработчиков оптимизировать неправильные части программы. Другая опасность заключается в том, что, как известно, трудно точно измерить что-то маленькое. Самый простой способ избежать этого, вероятно, - просто получить хорошее представление о том, где больше всего времени проводится в программе.

Обычно люди говорят, что не проводите микробенчмаркинг, но, вероятно, имеют в виду, что не принимайте оптимизационные решения на основе микротестов.

  • (или это хорошо?)

Само по себе это совсем не плохо, как другие здесь, и многие веб-страницы, кажется, предполагают. В нем есть свои места. Я работаю с переписыванием программ и переплетением аспектов времени выполнения и т. Д. Обычно мы публикуем микротесты наших добавленных инструкций не для направления каких-либо оптимизаций, а для того, чтобы убедиться, что наш дополнительный код практически не влияет на выполнение переписанной программы.

Однако это искусство, особенно в контексте виртуальной машины с JIT, временем прогрева и т. Д. Хорошо описанный подход для Java описан здесь (архив).

person aioobe    schedule 16.05.2010
comment
Re: разминка и т.д. Процессоры и операционные системы. - person Peter Cordes; 20.11.2020

Вот несколько хороших статей Брайана Гетца, объясняющих, почему (микро) бенчмаркинг особенно сложен в Java:

person Jesper    schedule 16.05.2010

Я не думаю, что микробенчмаркинг стоит того. Я думаю, что эффективный бенчмаркинг стоит потраченного времени.

Вообще говоря, микробенчмаркинг (как говорится в in silico) пытается измерить производительность некоторой очень детализированной задачи, которую сложно выполнить хорошо и обычно бессмысленно в контексте реальных проблем с производительностью.

person Dan Davies Brackett    schedule 16.05.2010
comment
Итак, вы действуете в соответствии с определением, что микробенчмаркинг бесполезен, верно? У меня тоже такое впечатление, но я просто не хотел ничего исключать, и это действительно может быть полезно в некоторых сценариях, о которых мне нужно будет заботиться. - person polygenelubricants; 16.05.2010
comment
Микротест включен в набор инструментов инженеров по производительности. К сожалению, большинство инженеров не являются инженерами по производительности, что означает, что вы получаете ошибочные тесты и результаты. Хороший микротест может выявить удельные затраты на различные операции, которые могут лучше служить анализу, когда полные тесты не являются репрезентативными для вашего программного обеспечения и модели выполнения системы. - person William Louth; 25.05.2010