exchg
> Подкину еще дегтя в твой метод
Я когда первый раз gettickcount использовал, он мне выдавал время обновляемое ровно 1/60 секунды. И так получилось что с Vsync давал выполняться этому методу тоже через 1/60 секунды. В результате эти микро сдвиги добавляли +-1/60. То есть интервал был либо 0 либо 2/60. И это давало заметные прыжки при анимации. Но вот чтобы таким заморачиваться с RTDC или QPC это надо быть Флешем. Ну это же +-1/1000000 и меньше.
foxes
> Но вот чтобы таким заморачиваться с RTDC или QPC это надо быть Флешем. Ну это
> же +-1/1000000 и меньше.
А откуда ты знаешь сколько там погрешность получится в итоге? Может там погрешность превысит точность? Проблема в том, что в том же gettickcount ты знал ширину ступеньки и у тебя была известна погрешность, а тут такова нету, сколько там получится в дельте от разных счетчиков - неизвестно. Где то от нуля до максимального значения счетчика.
А самое забавное тут то, что оно будет работать правильно в +90% случаев и выстрелит в самый неожиданный момент. Например жизнерадостный Delfigamer считает, что проскочит с пачкой семплов, а погрешность поймает статистикой, он так всегда делал. Но сегодня его процесс слегка отогнули на обочину и частота смены ядра критически выросла. В итоге он намерил херни и ломает голову что пошло не так свято веря в реальность цифирей.
exchg
> Например жизнерадостный Delfigamer считает, что проскочит с пачкой семплов, а
> погрешность поймает статистикой, он так всегда делал. Но сегодня его процесс
> слегка отогнули на обочину и частота смены ядра критически выросла. В итоге он
> намерил херни и ломает голову что пошло не так свято веря в реальность цифирей.
Ну открою диспетчер задач и поставлю максимальный приоритет. Вместо замера Trace буду замерять каждый IntersectRayWithPlane по отдельности.
В этом, кстати, и заключается преимущество tsc - он достаточно детализированный, чтобы измерять интервалы в тысячи и сотни тактов процессора; в то время как QPC, по вашим же статьям, может гранулироваться по тысячам (и разницу между 4900 и 5500 не увидит); а GetTickCount, вон, у Фоксеса вообще тикает раз в 10^8.
exchg
> Если мы допустим что оно так, то т.к.:
> ты не можешь знать размер сэмпла наперед, ты его как раз измеряешь.
> размер слайса тоже не константа (даже близко). Даже больше эта величина вне
> твоей системы вообще. На нее закладываться вообще нельзя.
> То возникает законный вопрос (если откинем послезнание) на основании чего
> сделан вывод, что семпл будет меньше слайса? )))
А зачем ты откидываешь послезнание? Не надо его откидывать.
На основании того и делаем, что засекаем по таймеру и видим результат.
И у тебя какое-то неправильное представление о том, зачем мне нужен tsc. Прежде всего - это инструмент отладки, а никак не таймер для основной логики приложения. Подобно тому, как никто в здравом уме не выкладывает дебаг-билды в релиз - точно так же и tsc предназначен именно для разработчика, а не для пользователя.
Соответственно, если какие-то требования не выполняются - например, видеоплеер кванты отжирает, или измеряемый интервал в 10 раз длиннее слайса - то совершенно естественно будет не оборачивать таймер свистелками на все случаи жизни, а закрыть плеер, переместить timer.start/timer.stop внутрь цикла и запустить рендерер на сцене попроще.
И вообще, изначально, главная мысль звучала именно так:
> Если только нас не интересует, сколько времени тратит ОС на переключение
> контекстов.
То есть - если посреди сэмпла переключение всё-таки произошло, то мы считаем его неправильным. Без разницы, как мы это определяем - по увеличению времени в 100 раз, по запросу на номер текущего ядра или как-нибудь ещё, если было переключение - сэмпл отбрасывается. Это условие задачи.
Тогда совершенно без разницы, пользуемся ли мы стабильным QPC или переключаемся между десятью разными tsc - по самой формулировке задачи, после фильтрации, среди правильных сэмплов останутся только те, у которых t1 и t2 посчитаны на одних часах.
И именно в такой задаче, стабильность QPC оказывается бесполезной, в то время как большее разрешение tsc вместе с меньшими затратами на измерение - остаются преимуществами.
Если же тебя вдруг интересует, что это за задача, вот тебе пример - мы можем хранить матрицы в row-major или в column-major, у нас есть использующий их Trace и мы хотим выбрать вариант, с которым Trace будет работать быстрее.
на самом деле трюки с RDTSC не сильно много дают профита имхо. ими можно очень быстро сравнивать выполнение двух вариантов кода, там достаточно и попугаев для оценки.
я часто, если оптимизирую функцию то сравниваю на сколько есть выигрыш с старым вариантом и стоит ли игра свеч. тот же ассемблер нужно минимизировать по возможности. и тут даже не столько мультиплатформенность беспокоит, сколько вероятность возникновения трудноуловимых ошибок. в том числе если компиллятор переиграет свое поведение с переменными.
с другой стороны, если я провожу такой тест, то функции катаю по миллиону циклов. там даже GTK начинает показывать чето приближенное к реальности. а стоимость QPC на миллион вызовов уже не считается и там результаты уже идентичные от теста к тесту.
тут тоже кстати есть одна тонкость. почему то всегда у функции которая прогоняется по циклу первой всегда выигрышь на определенный процент меньше, а если поменять местами то она может наоборот "победить") интересно чем вызвана эта погрешность. я понимаю что когда обсчитваешь массив то он должен еще в кеш свалиться а тут вроде переменные небольшие, на стеке.
Delfigamer
> А зачем ты откидываешь послезнание?
Потому, что оно на то и послезнание его нету на момент измерения. На момент измерения у тебя есть предположение, что оно так должно быть.
> Ну открою диспетчер задач и поставлю максимальный приоритет
...
> Соответственно, если какие-то требования не выполняются - например
Да и вот ты все это проделал, но случился реордеринг. И твои вызовы немного не в том порядке выполнились и вся точность ушла в никуда.
> И вообще, изначально, главная мысль звучала именно так:
> Без разницы, как мы это определяем - по увеличению времени в 100 раз, по
> запросу на номер текущего ядра или как-нибудь ещё, если было переключение -
> сэмпл отбрасывается.
Меня заинтересовал вопрос о сборе статистики. А об отбрасывании вообще я говорил в самом начале - берешь rdscp и отбрасываешь все измерения где сменилось ядро (возвращается значение в регистре). Но и у него проблема с реордерингом тоже остается.
> И именно в такой задаче, стабильность QPC оказывается бесполезной, в то время
> как большее разрешение tsc вместе с меньшими затратами на измерение - остаются
> преимуществами.
А кстати, какая разница между QPC и rdtsc у тебя получается на практике?
Mira
> на самом деле трюки с RDTSC не сильно много дают профита имхо.
Просто для каждой задачи свой инструмент.
Для анализа производительности ~10 инструкций железные методы не подходят, нужен эмулятор вроде Intel IACA.
Для работы с сотнями-тысячами инструкций — rdtsc без вариантов, как и говорит Delfigamer.
Для миллисекундных интервалов и больше уже нужны системные средства.
Кстати, советую не использовать непереносимые вещи вроде QPC/GTC/timeGetTime, вполне достаточно стандартных кроссплатформенных инструментов (я обычно использую clock()).
Я в 2017 году это исследовал
Тест таймеров, сорец
Тест таймеров, виндовый екзешник
QPC - огрубляет до 410 наносекунд на вызов, длительность вызова такая же, как у RDTSC (~65 миллионов в секунду или около 15нс)
RDTSC - шумная, даёт в среднем 15 нс - что равно длительности вызова ея.
Вывод? Я был не прав, надо использовать QPC везде, кроме Windows 98/Me. Там использовать RDTSC либо вообще отключать профайлинг.
Microsoft Windows [Version 6.1.7601] (c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены. d:\tmp>test_timers qpc Testing the mighty RDTSC instruction, directly from the CPU! // гы, ашипка Measuring frequency... 2435898 0ms: 57812425 1ms: 2 2ms: 2 Total changes: 57812429, cycles: 57812430 The milisecond grid is too coarse! Measuring microseconds... 0us: 57468526 1us: 1712 7us: 2469 Total changes: 57473977, cycles: 57473978 The microsecond grid is too coarse! Measuring nanoseconds... 411ns: 2273422 821ns: 1051 1000ns: 5002 Total changes: 2279475, cycles: 65566345 press Enter to close d:\tmp>test_timers rdtsc Testing the mighty RDTSC instruction, directly from the CPU! Measuring frequency... 2.4950999010000000E+009 0ms: 63399634 1ms: 4 2ms: 1 3ms: 1 Total changes: 63399640, cycles: 63399641 The milisecond grid is too coarse! Measuring microseconds... 0us: 64350913 1us: 1811 7us: 3029 Total changes: 64357388, cycles: 64357389 The microsecond grid is too coarse! Measuring nanoseconds... 7ns: 1007 8ns: 269317 10ns: 5241901 11ns: 7740186 12ns: 8309189 13ns: 5512086 14ns: 7727709 15ns: 2781930 16ns: 8816960 17ns: 6951703 18ns: 3940313 19ns: 38220 20ns: 3433102 21ns: 2438963 22ns: 1504266 23ns: 192456 24ns: 46580 25ns: 1192 26ns: 26474 27ns: 14334 28ns: 8357 29ns: 5296 30ns: 3267 32ns: 2463 33ns: 2102 34ns: 1618 35ns: 3148 36ns: 1615 38ns: 13493 39ns: 4429 40ns: 12101 41ns: 4653 42ns: 1749 Total changes: 65065766, cycles: 65069655 press Enter to close
З.Ы. Вон те взбрыки в несколько микросекунд или даже милисекунд - это как раз случаи, где система упихивала тред в долгий ящик. 5 тысяч на 65 миллионов, или 0.007% всех измерений.
Вот мои результаты по rdtsc.
Кратко - это простейший прямой пат-трейсер, камера пускает обратный фотон, он гуляет по сцене и собирает свет с поверхностей-источников, пока не поглотится по альбедо.
Один IteratePixel содержит в себе произвольное дискретное число Trace, время дочерних функций из родительских не вычитается.
Результаты:
Обратите внимание - графики логарифмические.
Delfigamer
> Результаты:
Ты бы хоть оси подписал. Мне лично с этих картинок пока мало что понятно.
MrShoor
Это график частот.
В xxxperf.csv сохраняется весь std::map как есть.
sp импортируется как массив точек {показание_таймера, количество_сэмплов}.
Соответственно, Total[Last /@ sp] - что в более развёрнутом виде выглядит как Total[Map[Function[{p}, Last[p]], sp]] - посчитает суммарное количество сэмплов.
Для sp число сэмплов должно насчитать целое количество проходов по фреймбуферу 800*600 - поэтому у Total[Last /@ sp] четыре нуля справа, он пропорционален 480000.
ListPlot[sp] выводит sp как массив точек на плоскости - по x оказывается показание дельты таймера, по y - количество сэмплов с совпадающим показанием. ListLogLogPlot делает то же, и затем преобразует картинку под логарифмические оси.
Я бы назвал его "график распределения", но настоящая плотность распределения при переходе к логарифмическому икс должна масштабироваться на \(\frac{d x}{d \log x}\), а тут такого не происходит.
}:+()___ [Smile]
> Для анализа производительности ~10 инструкций железные методы не подходят, нужен эмулятор вроде Intel IACA.
Зависит как и что считать. Agner Fog же меряет.
Ну и сейчас осмысленнее MCA ( https://llvm.org/docs/CommandGuide/llvm-mca.html ).
> Для работы с сотнями-тысячами инструкций — rdtsc без вариантов, как и говорит Delfigamer.
Ну оговорки про стабильность частоты в силе. Бывает нужно реальное количество тактов.
> Кстати, советую не использовать непереносимые вещи вроде QPC/GTC/timeGetTime, вполне достаточно стандартных кроссплатформенных инструментов (я обычно использую clock()).
Если бы clock() под windows имел разрешение выше пары миллисекунд (MinGW), я бы может и согласился. А так - грубо. Сама по себе CPU time - хорошая вещь.
FordPerfect
> Зависит как и что считать. Agner Fog же меряет.
Он меряет 100500 одинаковых инструкций в цикле, это немного не то.
Я, кстати, тоже так делал: прямо в ассемблерном коде крутил цикл на 10^9 итераций и снаружи замерял время.
Обнаружил, что хранение констант в памяти, а не регистрах (это был xmm), не влияет на производительность при определенных условиях.
> Ну и сейчас осмысленнее MCA
О! Я помнил, что был опенсорсный аналог, но когда писал пост его не нашел.
> Если бы clock() под windows имел разрешение выше пары миллисекунд (MinGW), я бы может и согласился.
Я циклы бенчмарков гоняю в районе секунд каждый, мне точности хватает, особенно на моем линуксе :)
Но, думаю, и под винды есть какой-нибудь стандартный способ с нормальным разрешением.
Тема в архиве.