Pull to refresh

Comments 69

Как вы замеряете время в своих бенчмарках?

Регулярное тестирование замеряет с помощью программы time. Если выявляется регрессия, то собираются счётчики CPU_CLK_UNHALTED.THREAD.
Как вы замеряете время в своих бенчмарках?

perf stat

Зачем в виндовом коде следующий фрагмент:
        if ( FileTimeToSystemTime( &userTime, &userSystemTime ) != -1 )
            return (double)userSystemTime.wHour * 3600.0 +
                (double)userSystemTime.wMinute * 60.0 +
                (double)userSystemTime.wSecond +
                (double)userSystemTime.wMilliseconds / 1000.0;

Почему не просто
        ULARGE_INTEGER li = {{userTime.dwLowDateTime, userTime.dwHighDateTime }};
        return li.QuadPart / 100000000000.;
Надо делить на 10000000., потому что измеряется в 100-наносекундных интервалах, а получить нужно секунды.

Так как код не мой, то точно ответить вам не могу. Судя по всему, вы правы и результат будет таким же, разве что делить надо на другое число и взять остаток.


        ULARGE_INTEGER li = {{userTime.dwLowDateTime, userTime.dwHighDateTime }};
        return (li.QuadPart % 864000000000) / 10000000.;

Сначала неправильно прикинул, показалось, что может влиять на точность. Прикинул еще раз, вроде в адектваных случаях не может. Уже закоммитил без остатка.

Чтобы не влиять на точность, во всём этом деле нужно использовать int64 вместо double.

17 десятичных знаков достаточно, ИМХО.

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

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


Почему утилита а не функция? Ведь автоматизировать замеры с функцией обычно гораздо легче, чем с утилитой.

Совершенно не легче. Во-первых, подобные утилиты обычно работают везде, где их можно скомпилировать, по идее их должны поддерживать их разработчики (runexe, в принципе, не требует поддержки сейчас — она работает). Что касается таких вот жутких функций, то встраивание их в мой код делает программу сложнее и не даёт гарантий, что она запустится у кого-то другого. Это против моих правил — давать код, который тяжело скомпилировать (одна из причин, по которой я плохо отношусь к опенсорсу — это трудности с компиляцией, возникающие по причине доступа к коду тех людей, которых это мало заботит). Во-вторых, указанная мною утилита может также правильно замерять использованную единовременно память, что тоже важно. В-третьих, включать таймер до цикла тестирования и выключать после — это ничем по сути не отличается от тестирования внешней утилитой. В-четвертых, я не знаю, какие побочные эффекты порождают вот такие отдельные функции и как они влияют на измерение. Короче, я считаю, что в любом эксперименте измерительный прибор должен быть как можно дальше от опытного образца, не только в программировании. Ну и в-пятых, дело привычки.

Поэтому когда я пишу код для других людей, то, к сожалению, приходится замеры делать через chono, в надежде, что когда-нибудь оно начнёт работать везде. Дома использую только runexe.
Что касается таких вот жутких функций, то встраивание их в мой код делает программу сложнее и не даёт гарантий, что она запустится у кого-то другого. Это против моих правил — давать код, который тяжело скомпилировать

Почему бы ей не скомпилироваться, если у нее никаких зависимостей, кроме стандартной билиотеки? Что тяжелого в компиляции, которая сводится к запуску компилятора?


runexe, в принципе, не требует поддержки сейчас

И, в принципе, не поддерживается, судя по сайту на мертвом Google Code и отсутсвию даже минимальной инструкции на этом самом сайте.


включать таймер до цикла тестирования и выключать после — это ничем по сути не отличается от тестирования внешней утилитой.

Отличается простотой автоматизации. Залез в ваш аккаунт и обнаружил, что как раз в вашей статье это всплыло.


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

Собственно вот он это код.

Вы ответили лишь на половину моих замечаний, при этом недооцениваете мой способ работы дома и то, что лично мне удобнее. Я лишь ответил на ваш тезис "Ведь автоматизировать замеры с функцией обычно гораздо легче, чем с утилитой", ответив, что лично мне не легче. Я с подозрением отношусь к внедрению стороннего кода в свой, в 99% случаев это приводит к пустой потере времени (в силу доминирующей криворукости создателей подобного опенсорса). Это лишь моё мнение. Вопрос практической полезности подобного кода решается ТОЛЬКО через практику.

Что касается моих проблем, которые я мог бы попытаться решить этим готовым кодом — а именно, подготовка для других людей готового к запуску проекта — это нужно пробовать решать в ходе исследования. На Вашем месте я бы так и сделал: состряпал бы программу с тестированием некоторых интересных функций, и попросил бы пользователей БЕЗ КАКИХ ЛИБО ЛИШНИХ УСИЛИЙ скомпилировать из запустиь её, затем показать вывод на консоль. Если это сработает, я буду рад таком подходу… однако это не изменит моих личных привычек и избавить от необходимости измерять иногда память.

Что касается автоматизации, то со сторонними утилитами она решается, но иным способом, например, через cmd-файл.

Если за мои эксперименты проголосует больше 80% участников, я могу попробовать данный подход в тестировании. Только тогда станет ясно, стоит игра свеч или нет. Я НЕ спорю, что это может работать, я лишь ответил, почему не считаю это решение более лёгким. Ответ мой можно опровергнуть только на практике. Тут как бы спорить не имеет смысла даже.
Вы ответили лишь на половину моих замечаний, при этом недооцениваете мой способ работы дома и то, что лично мне удобнее.

Я говорил конкретно об автоматизации бенчмарка — "запустил и пошел спать". Хотя вы и ответили, что автоматизировать со встроенной функцией не легче, но та самая половина замечаний отношения к автоматизации не имеет.


в силу доминирующей криворукости создателей подобного опенсорса

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


Что касается автоматизации, то со сторонними утилитами она решается, но иным способом, например, через cmd-файл

Если вы хотите сравнить две версии алгоритма, то в лоб еще скриптом не автоматизируешь. Или держать два проекта, или собирать вручную, или использовать аргументы при запуске.

Так а Вы думаете, что у меня подход чем-то отличается от «запустил и пошёл спать»?: )

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

С этим кодом я и не спорю (пока), я выразил мнение о том, чем закачивается 99% попыток внедрить в свой код что-то другое. По поводу runexe — у меня пока не было нареканий к нему, так что это дело не веры, а проверки на сотнях тысячах запусках. А предложенные Вами код я пока не проверял. Когда проверю, тогда будет видно.

Если вы хотите сравнить две версии алгоритма, то в лоб еще скриптом не автоматизируешь. Или держать два проекта, или собирать вручную, или использовать аргументы при запуске.

Эта проблема уже давно решена. Поэтому я и говорю, что лично мне не легче. Легче будет, возможно, сделать универсальный код для других пользователей, но это, повторюсь, нужно проверять на практике. Как я уже сказал, что если сработает, буду рад. Но почему-то я сомневаюсь пока.
Так а Вы думаете, что у меня подход чем-то отличается от «запустил и пошёл спать»? :)

Эта проблема уже давно решена.


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


С этим кодом я и не спорю (пока), я выразил мнение о том, чем закачивается 99% попыток внедрить в свой код что-то другое.

Ну чужой код надо читать, а не бездумно копировать.


По поводу runexe — у меня пока не было нареканий к нему, так что это дело не веры, а проверки на сотнях тысячах запусках.

А вы каким-то образом его проверяли? Или это "по ощущениям"? Если бы вы могли мерить процессорное время "по ощущениям", то и программа не нужна была наверное ;) Вдруг там лишних 5-10% намеряется в особых случаях.

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

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

Вопрос риторический, конечно. Что касается вопроса корректности тестирования с помощью runexe, то здесь всё просто — меня устраивает время, которое она выдаёт при тестировании. Есть ряд традиционных методов, изучаемых на курсах истории и методологии науки, по которым можно считать некое знание достоверным или недостоверным. Все эти методы мне известны и они работают. Абсолютной уверенности в том, что runexe работает лучше или хуже системных функций нет никаких. То же самое можно сказать о системных функциях — они тоже работают «как-то» и нам остаётся верить, что работают правильно. Это философский вопрос… если тянуть его дальше, то возникнет другой вопрос: правильно ли мы вообще живём и какова (и откуда) степень нашей уверенности в этом?

Я уже говорил, что предложенный здесь Вами подход нужно детально изучать на практике. А я по природе своей (и тому есть объяснение) всегда НЕ доверяю ЛЮБЫМ чужим программам, пока не проверю их на практике — отсюда и мой кажущийся скептицизм. Не знаю, что Вы ещё от меня хотите :) Я уже сказал, что попытаюсь всё это проверить массово и сделать выводы. Хотя это могли бы сделать и Вы сами.
Мне кажется, Вы напрасно уводите разговор в сторону. То, как я работаю дома, это вряд ли кому-то интересно

Ну так и то, что в вашем конкретном случае, после того, как вы проделали некоторую работу, вы смогли автоматизировать runexe никак не значит, что автоматизировать метод из статьи не легче.


И потом только мы получим гарантию, функция из Вашей статьи работает правильно. Так или нет?

Фактически — так. Практически, лично я доверяю системным вызовам и стандартным библиотекам, например.


Абсолютной уверенности в том, что runexe работает лучше или хуже системных функций нет никаких.

Runexe, очевидно, использует системные функции. В частности, версия на которую ссылаетесь вы, использует QueryInformationJobObject, хотя на данный момент, судя по всему, всё уже переписано на Go.


Не знаю, что Вы ещё от меня хотите :)

Собственно от вас ничего больше и не хочу. Весь спор начался из-за вашего необоснованного предположения, что если у вас все работает, значит ваш метод не сложнее.

Не-не-не, Евгений. Вы уж простите, если я как-то не так слова подобрал, но я имел в виду, что У МЕНЯ ЛИЧНО runexe уже хорошо работает, и поэтому мне не сложнее делать так, как уже делается. Кому-то другому, наверное, удобнее взять готовое. И потом я пока ещё не убедился, что предложенный Вами метод действительно будет работать — это нужно проверять. В данном случае практика — критерий истинности.

А в целом по статье всё нормально, я Вам очень благодарен за проделанную работу (перевод и популяризация). Одно замечание: название неверное. «Как измерять процессорное время» — это намёк на методологию самого процесса измерения, Вы же даёте готовое решение, написанное каким-то мужиком. То есть предлагаете инструмент, а не методологию. Но это имхо.
UFO just landed and posted this here
в windows лучше пользоваться

::QueryPerformanceCounter( &perfCntStart );
::QueryPerformanceFrequency( &proc_freq );

что-то делаем

::QueryPerformanceCounter( &perfCntStop );
float result = float( perfCntStop.QuadPart — perfCntStart.QuadPart );

::QueryPerformanceCounter( &perfCntStop );

Эта функция, если я не ошибаюсь, считает реальное время, а не процессорное.

С тех пор как в процессорах появилось больше одного потока (не важно ядра или HT) с помощью QueryPerformanceCounter считать нельзя, а с тех пор как процессоры стали в ходе работы изменять свою частоту вызов QueryPerformanceFrequency показывает текущую частоту и только одного ядра, а в итоговых вычислениях по такой формуле получается, скажем так, какая то дичь.
OpenMP и omp_get_wtime()/omp_get_tick(). В академических целях для вопросов параллелизма, правда, но почему бы и нет?
Забавно. Способы измерения процессорного времени на C++, а про RDTSC забыли.
Только им и измеряем.

clock_gettime() теоретически может использовать RDTSC.
На многоядерных/многопроцессорных системах RDTSC вроде как ненадежен.

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

В общем, статья скорее освещает тему “как написать переносимый враппер над функциями библиотеки Си для получения времени”, чем “как измерять время”.
Поэтому, если вы хотите измерить реальное физическое время

Мы хотим измерить процессорное время.

А что Вы понимаете под “процессорным временем”?

Формально, термин “процессорное время” означает реальное время, занятое выполнением задачи на процессоре, то есть сумму предоставленных ей (или в её интересах) квантов времени.

Если Вы говорите о “процессорном времени” в смысле привязки к единицам тактовой частоты процессора вместо реальных секунд, то даже для бенчмаркинга это требует определённых оговорок, как и вообще всякие махинации с единицами измерения. Обычно, пользователя всё-таки интересует, какова производительность системы, приведённой к реальным единицам времени, а не с использованием удлинённых или укороченных секунд наугад взятого процессора с поехавшим тактовым генератором.

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

Обычно пользователя интересует субъективные ощущения от работы (быстро/медленно, тормозит/не тормозит), а не процессорное время.


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


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

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

Если вы хотите просто прикинуть порядок величины на конкретной системе, тогда вообще неважно, что и как вы меряете, а заодно и вся рассмотренная переносимость вам не нужна.

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

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


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

Лучшее решение предложили коллеги в предыдущем комментарии – использовать ассемблерную вставку с RDTSC и не париться (включая приведённую по ссылке статью с методическими рекомендациями Intel, как вообще правильно организовывать работу с таймером). А прежде, чем замахиваться на кроссплатформенность, автору лучше было бы для начала разобраться поглубже хотя бы с одной платформой.

Ещё навскидку темы, которые хотелось бы видеть освещёнными в подобной статье:

– оценка случайной и систематической составляющей погрешности измерения;

– как момент вызова функции и момент возврата из функции соотносятся с моментом фиксации показаний таймера (в том числе, чему равен оверхед от её собственной работы, как разность между этими значениями);

– что происходит, когда ОС в процессе бенчмаркинга синхронизирует время по NTP и начинает подводить таймеры;

– что происходит при переполнении коротких таймеров;

– там автор в коде зачем-то работает с минутами и часами, что вызывает очевидный вопрос, что происходит в его функции с переходом через полночь, и менее очевидный вопрос, что происходит с удлинёнными минутами по 61 секунде (чем дальше, тем они появляются чаще в связи с удлинением астрономических суток).
использовать ассемблерную вставку с RDTSC и не париться
А если у меня не только х86 или вообще не х86?

как момент вызова функции и момент возврата из функции соотносятся с моментом фиксации показаний таймера (в том числе, чему равен оверхед от её собственной работы, как разность между этими значениями);


Могу лишь предположить, что общий оверхед будет равен ровно одному вызову функции (мы считаем от фиксации до фиксации, в начальном измерении после фиксации будет учтен "конец" функции, в конечном — будет учтено "начало" функции)


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

Ничего не происходит, читайте внимательнее код.

А если у меня не только х86 или вообще не х86?

Тогда к чему проблематика Windows?

Собственно, счётчик в процессоре есть во многих архитектурах.

Могу лишь предположить, что общий оверхед будет равен ровно одному вызову функции (мы считаем от фиксации до фиксации, в начальном измерении после фиксации будет учтен «конец» функции, в конечном — будет учтено «начало» функции)


Так вот и хочется знать, в частности, чему равен этот вызов функции в микросекундах (учитывая, что он включает неизвестные нам действия внутри libc и ядра).

Ничего не происходит, читайте внимательнее код.


return (double)userSystemTime.wHour * 3600.0 +
(double)userSystemTime.wMinute * 60.0 +
(double)userSystemTime.wSecond +
(double)userSystemTime.wMilliseconds / 1000.0;


Что здесь произойдёт, когда процесс работает более 24 часов?
Так вот и хочется знать, в частности, чему равен этот вызов функции в микросекундах (учитывая, что он включает неизвестные нам действия внутри libc и ядра).

Так как это зависит от кучи параметров, надо просто сделать замер на той системе, на которой это вас интересует.


Что здесь произойдёт, когда процесс работает более 24 часов?

В худшем случае — вы получите результат, на 86400 отличающийся от реального. Думаю, это не так уж и сложно заметить.

На 86400*n.

Вот я и говорю – проработка материала в статье на уровне сообразительного школьника. Конечно, есть определённое рациональное зерно в том, что все упомянутые функции действительно существуют и их при случае можно использовать. Но так вот бездумно приравнивать друг к другу в условной компиляции разные по своей сути методы получения времени – если и возможно, то, по крайней мере, это требует значительного количества методических комментариев.
На 86400*n.

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


Вот я и говорю – проработка материала в статье на уровне сообразительного школьника.

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

Вы спорите ради флейма. Пока я не могу понять даже того, какой вообще смысл имеет приравнивание друг к другу времени исполнения пользовательского процесса в Linux, OS X и Windows, если у них совершенно разное разделение нагрузки между user- и kernel-space. Так что про кроссплатформенность здесь вообще лучше не вспоминать.
Если нужно просто прикинуть время выполнения, то зачем вообще измерять процессорное время? Закрыть по максимуму все программы, запустить тест несколько раз, отбросить тесты с аномальными результатами (если есть) и вычислить среднее значение.
Есть несколько причин. Самая важная: при длительном тестировании у вас нет никаких гарантий, что в середине пути ОС вдруг не захочет что-нибудь сделать, что повлияет на результат (гарантировать на 100%, что этого не произойдёт, нельзя). При этом программа может работать весьма долго и перетестировать её (минимум трижды) довольно трудно. Далее, например, на олимпиаде по программированию один компьютер может запускать сразу несколько программ единовременно, нужно точно учитывать, сколько отработала каждая, с учётом разделения времени с конкурентами. Даже при отключённых лишних программах разница на несложных тестах может оказаться равной секунде или двум (в виндоусе). Так что как ни крути, процессорное время чище.
Я писал о «прикинуть время выполнения». Измерение времени выполнения олимпиадных программ — это совершенно другой сценарий.
Ну, смотря как «прикинуть». Если совсем не точно, то достаточно просто запустить и время от времени смотреть на часы. Если прикидка должна быть довольно точной, а программа работает долго, то можно параллельно работать на компьютере с другими вычислениями, которые могут занимать массу времени. В этом случае процессорное время необходимо, иначе получите, что программа работает час, а астрономическое время будет 2-3 часа. Так что при параллельной работе всё равно это важно.
Если программа выполняет много системных вызовов, то значительная часть времени её выполнения приходится на работу ядра. В этом случае пользовательское время даст вам заниженный результат даже по процессору. Тем более это справедливо в отношении ожидания ввода-вывода.

Реального способа выделить работу в интересах одного приложения из общей нагрузки на PC/Mac нет.
Одна из основных проблем — это не точность часов, не измерение процессорного времени вместо реального, а переменная производительность современных процессоров, связанная со сбросом частоты в целях снижения энергопотребления.

Для оценки времени выполнения коротких вычислительных задач (до 1 секунды) на процессорах Intel/AMD ни один из описанных в статье методов при применении «в лоб» не даст адекватных результатов, если не выключен, например, EIST для процессоров Intel, т.к. разброс будет двух-, а то и трёхкратным.

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

Так если RDTSC дает количество тактов, то, при условии что частота менялось по ходу выполнения процесса, переводить в секунды их тоже нельзя. Разве не так?

Получите приведённую к фиксированной частоте производительность, разумеется. То есть номинальные секунды.
Зависит от конкретной задачи. Если я оптимизирую по скорости составляющую часть вычислительного алгоритма, то для меня будет иметь значение именно количество тактов, а не время выполнения. Потому что алгоритм, требующий меньшего числа операций, будет выполняться быстрее.
Вынужден Вас поправить, это не всегда так. Иногда добавление лишних команд не только не приводит к замедлению, но даже может сделать программу быстрее. Есть минимум две причины, почему так может произойти: добавление лишней команды меняет состояние кэша, за счёт чего другие команды (дальше по коду), исполняются быстрее; «разбавление» кода командами может улучшить работу конвейера и сделать всё выполнение более быстрым. К сожалению, примеров я Вам не дам сходу, но лично наблюдал оба варианта. Не буду спорить, что второй случай специфический, но первый мне попадается часто. А что касается числа тактов, то это число не имеет никакого смысла на практике, так как есть конвейер (имхо). Число тактов не отражает скорость выполнения достаточно точно.

К тому же, по крайней мере на Linux clock_gettime( ) использует RDTSC или аналоги там, где это возможно.

Вы катастрофически ошибаетесь. На современных процессорах, RDTSC считает не такты, а с постоянной скоростью независимо от текущей тактовой частоты.


Цитата из интеловского мануала Intel® 64 and IA-32 Architectures Developer's Manual:


Processor families increment the time-stamp counter differently:
• For Pentium M processors (family [06H], models [09H, 0DH]); for Pentium 4 processors, Intel Xeon processors (family [0FH], models [00H, 01H, or 02H]); and for P6 family processors: the time-stamp counter increments with every internal processor clock cycle. The internal processor clock cycle is etermined by the current core-clock to bus-clock ratio. Intel® SpeedStep® technology transitions may also impact the processor clock.
• For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); for Intel Core 2 and Intel Xeon processors (family [06H], DisplayModel [17H]); for Intel Atom processors (family [06H], DisplayModel [1CH]): the time-stamp counter increments at a constant rate. That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by the maximum resolved frequency at
which the processor is booted. The maximum resolved frequency may differ from the processor base frequency, see Section 18.16.5 for more detail. On certain processors, the TSC frequency may not be the same as the frequency in the brand string.
The specific processor configuration determines the behavior. Constant TSC behavior ensures that the duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if the processor core changes frequency. This is the architectural behavior moving forward.
Видимо, пора мне делать апгрейд.
Как вы замеряете время в своих бенчмарках?

Профайлером, а что? Или надо по коду через каждую строку вот это getCPUTime писать?
Добавлю про RDTSC — эта инструкция может быть перехвачена гипервизором и возвращать что угодно. Более того, если снят бит TSD в регистре CR4, то для её использования нужны повышенные привелегии, и потому ваша программа, которая эту инструкцию использует, не будет работать правильно в QNX, которая ставит этот бит по умолчанию.
В качестве независимого от платформы и ОС источника времени (как точного, так и интервалов) могу посоветовать UEFI RT-сервис GetTime, но как вы до него из вашей конкретной ОС доберетесь — другой вопрос.
А какая у него реальная разрешающая способность?
Так я про конкретные реализации и спрашиваю. Судя по тому, что в материале это увязывается с RT-CMOS, там как бы не 1 секунда может оказаться на самом деле.
Разницу в миллисекунды на современных системах (Broadwell, Skylake, Merlin Falcon) я им измерял успешно, про наносекунды точно не скажу.
В теории много какие инструкции могут быть перехвачены, так что же, их вводили просто так?
Де-факто на всех современных OS rdtsc работает корректно и не является привилегированной инструкцией.
не недостоверна на Linux.

Опечатка?

Раньше я использовал Microseconds() на маке.
Дабы минимизировать временные затраты на саму функцию получения времени, вызываю два раза clock_gettime с CLOCK_PROCESS_CPUTIME_ID в начале и в конце, пересчет в секунды делаю уже потом. Если есть возможность зафиксировать частоту процессора, использую rdtsc инструкцию.
Sign up to leave a comment.

Articles