Когда Intel впервые изобрела TSC, она измеряла циклы процессора. Из-за различных функций управления питанием «количество циклов в секунду» не является постоянным; поэтому TSC изначально был хорош для измерения производительности кода (и плохо для измерения прошедшего времени).
Для лучшего или худшего; в то время у процессоров не было слишком много управления питанием, часто процессоры все равно работали с фиксированным «циклом в секунду». Некоторые программисты ошиблись и неправильно использовали TSC для измерения времени, а не циклов. Позже (когда использование функций управления питанием стало более распространенным) эти люди, злоупотребляющие TSC для измерения времени, жаловались на все проблемы, вызванные их неправильным использованием. Производители процессоров (начиная с AMD) изменили TSC, чтобы он измерял время, а не циклы (что сделало его неработающим для измерения производительности кода, но правильным для измерения прошедшего времени). Это вызвало путаницу (программному обеспечению было трудно определить, что на самом деле измерял TSC), поэтому немного позже AMD добавила флаг «TSC Invariant» в CPUID, чтобы, если этот флаг установлен, программисты знали, что TSC не работает (для измерения циклы) или фиксированные (для измерения времени).
Intel последовала за AMD и изменила поведение своего TSC, чтобы также измерять время, а также приняла флаг AMD «TSC Invariant».
Это дает 4 разных случая:
TSC измеряет как время, так и производительность (количество циклов в секунду является постоянным)
TSC измеряет производительность, а не время
TSC измеряет время, а не производительность, но не использует для этого флаг «TSC Invariant».
TSC измеряет время, а не производительность, и для этого использует флаг «TSC Invariant» (большинство современных процессоров).
В случаях, когда TSC измеряет время, для правильного измерения производительности/циклов необходимо использовать счетчики мониторинга производительности. К сожалению, счетчики мониторинга производительности различаются для разных процессоров (в зависимости от модели) и требуют доступа к MSR (привилегированный код). Это делает непрактичным для приложений измерение «циклов».
Также обратите внимание, что если TSC действительно измеряет время, вы не можете знать, какой масштаб времени он возвращает (сколько наносекунд в «воображаемом цикле»), не используя какой-либо другой источник времени для определения коэффициента масштабирования.
Вторая проблема заключается в том, что для многопроцессорных систем большинство операционных систем отстой. Правильный способ для ОС обрабатывать TSC — запретить приложениям использовать его напрямую (путем установки флага TSD
в CR4, чтобы инструкция RDTSC вызывала исключение). Это предотвращает различные уязвимости безопасности (временные побочные каналы). Это также позволяет ОС эмулировать TSC и гарантировать, что он возвращает правильный результат. Например, когда приложение использует инструкцию RDTSC и вызывает исключение, обработчик исключений ОС может вычислить правильную «глобальную метку времени» для возврата.
Конечно, у разных процессоров есть свои TSC. Это означает, что если приложение использует TSC напрямую, оно получает разные значения на разных процессорах. Чтобы помочь людям обойти неспособность ОС решить проблему (эмулируя RDTSC, как они должны); AMD добавила инструкцию RDTSCP
, которая возвращает TSC и «идентификатор процессора» (Intel также приняла инструкцию RDTSCP
). Приложение, работающее в сломанной ОС, может использовать «идентификатор процессора», чтобы определить, когда они работают на другом процессоре по сравнению с прошлым разом; и таким образом (используя инструкцию RDTSCP
) они могут узнать, когда "прошедшее = TSC - предыдущее_TSC" дает неверный результат. Тем не мение; «Идентификатор процессора», возвращаемый этой инструкцией, является просто значением в MSR, и ОС должна установить это значение на каждом ЦП в какое-либо другое значение, иначе RDTSCP
скажет, что «идентификатор процессора» равен нулю на всех ЦП.
В основном; если ЦП поддерживает инструкцию RDTSCP
и если ОС правильно установила «идентификатор процессора» (используя MSR); тогда инструкция RDTSCP
может помочь приложениям узнать, когда они получили плохой результат «прошедшего времени» (но она никоим образом не обеспечивает исправление или предотвращение плохого результата).
Так; Короче говоря, если вам нужно точное измерение производительности, вы в основном облажались. Лучшее, на что вы можете надеяться, это точное измерение времени; но только в некоторых случаях (например, при работе на машине с одним процессором или "прикреплении" к определенному процессору; или при использовании RDTSCP
в ОС, которые настраивают его правильно, пока вы обнаруживаете и отбрасываете недопустимые значения).
Конечно, даже тогда вы получите сомнительные измерения из-за таких вещей, как IRQ. По этой причине; лучше запускать свой код много раз в цикле и отбрасывать любые результаты, которые намного выше, чем другие результаты.
Наконец, если вы действительно хотите сделать это правильно, вы должны измерить накладные расходы на измерение. Чтобы сделать это, вы должны измерить, сколько времени требуется, чтобы ничего не делать (только одна инструкция RDTSC/RDTSCP, отбрасывая сомнительные измерения); затем вычтите накладные расходы на измерение из результатов «измерения чего-либо». Это дает вам лучшую оценку времени, которое на самом деле занимает «что-то».
Примечание. Если вы сможете откопать копию Руководства по системному программированию Intel, выпущенного с момента первого выпуска Pentium (середина 1990-х годов — не уверен, что он доступен в Интернете — у меня есть архивные копии с 1980-х годов), вы обнаружите, что Intel задокументировала счетчик отметок времени как нечто, что «может использоваться для отслеживания и определения относительного времени возникновения событий процессора». Они гарантировали, что (исключая 64-битный цикл) он будет монотонно увеличиваться (но не что он будет увеличиваться с фиксированной скоростью) и что потребуется минимум 10 лет, прежде чем он завершится. В последней редакции руководства более подробно описан счетчик меток времени, в котором указано, что для более старых процессоров (P6, Pentium M, более старый Pentium 4) счетчик меток времени «увеличивается с каждым внутренним тактовым циклом процессора» и что «Intel(r) Переходы на технологию SpeedStep(r) могут повлиять на тактовую частоту процессора"; и что более новые процессоры (более новые Pentium 4, Core Solo, Core Duo, Core 2, Atom) TSC увеличиваются с постоянной скоростью (и что это «архитектурное поведение в будущем»). По сути, с самого начала это был (переменный) «внутренний счетчик циклов», который использовался для отметки времени (а не счетчик времени, который использовался для отслеживания времени «настенных часов»), и это поведение изменилось вскоре после 2000 год (на основании даты выпуска Pentium 4).
person
Brendan
schedule
13.11.2013