Что микросравнивает?

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

  • Что означает и что это не означает?
  • Каковы некоторые примеры того, что и не микросравнивает?
  • Каковы опасности микросравнить и как Вы избегаете его?
    • (или действительно ли это - хорошая вещь?)
58
задан polygenelubricants 16 May 2010 в 05:41
поделиться

5 ответов

Он означает именно то, что написано на жестяной банке - измерение производительности чего-то "маленького", например, системного вызова ядра операционной системы.

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

Мы должны забыть о малой эффективности, скажем, в 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 приложений, которые вы открываете чаще всего, и предварительно загрузить код приложения в память при загрузке компьютера!

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

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

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

.
69
ответ дан 24 November 2019 в 19:03
поделиться

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

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

-1
ответ дан 24 November 2019 в 19:03
поделиться

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

1
ответ дан 24 November 2019 в 19:03
поделиться
  • Что это значит и что не значит?

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

  • Каковы примеры того, что является и не является микробенчмаркингом?

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

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

  • Каковы опасности микробенчмаркинга и как их избежать?

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

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

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

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

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

4
ответ дан 24 November 2019 в 19:03
поделиться

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

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

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

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

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

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


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

6
ответ дан 24 November 2019 в 19:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: