Иллюстрированный самоучитель по задачам и примерам Assembler

Использование счетчика меток реального времени TSC

Счетчик меток реального времени TSC (Time Stamp Counter) – регистр, содержимое которого инкрементируется с каждым тактом процессорного ядра. Каждый раз при аппаратном сбросе (сигналом RESET) отсчет в этом счетчике начинается с нуля. Разрядность регистра обеспечивает счет без переполнения в течение сотен лет. Счетчик продолжает счет как при исполнении инструкции HLT, так и при остановке процессора по сигналу STPCLK# (для энергосбережения).

Чтение счетчика обеспечивает инструкция RDTSC, установкой бита CR4.TSD ее можно сделать привилегированной (доступной лишь при CPL = 0). Чтение и запись TSC возможны также по инструкциям обращения к MSR (при CPL ¦ 0), причем запись может выполняться только в младшие 32 бита, а старшие биты при операции записи обнуляются. Присутствие счетчика TSC определяется по инструкции CPUID (ЕАХ = 1), Если в результате ее вызова бит 4 регистра EDX равен 1, то процессор поддерживает счетчик меток реального времени TSC.

Команда RDTSC (ReaD from Time Stamp Counter – чтение 64-разрядного счетчика меток реального времени TSC (Time Stamp Counter)) не имеет операндов. Машинный код этой команды – Of 31. Команда проверяет состояние второго бита регистра CR4.TSD (Time Stamp Disable – отключить счетчик меток реального времени):

  • если CR4.TSD = 0, то выполнение команды RDTSC разрешается на любом уровне привилегий;
  • если CR4. TSD = 1, то выполнение команды RDTSC разрешается только на нулевом уровне привилегий.

Если после данной проверки выполнение команды разрешено на текущем уровне привилегий, то выполняется сохранение значения 64-битного MSR-счетчика TSC в паре 32-битных регистров EDX: ЕАХ. Если выполнение команды запрещено, то работа команды заканчивается.

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

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

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

Ниже приведены макрокоманды profiler_in и profiler_out с тестовым примером для проверки их работы. Данные макрокоманды производят корректировку результата своей работы, с тем чтобы исключить обсужденные выше внутренние причины "грязного" времени работы программы. Заметим, что не всякий транслятор ассемблера "знает" о новых командах микропроцессора, в том числе и о команде RDTSC. По этой причине мы ее моделируем, инициализируя в сегменте кода 2 байта значениями машинного кода этой команды db 0fh,31h.

:prg08_01.asm – программа демонстрации использования макрокоманд profiler_in
;и profiler out для оценки производительности фрагментов кода.
bin_dec_fpu macro string_bin_qword:REQ .string_pack:REQ .adr_string_pack
:REQ, len_ ~string_pack:REQ, ad^string^EQ .len_string:REQ
local cycl макрокоманда вывода на консоль десятичного числа:
;на входе:
;string_bin_qword – адрес 64-битной ячейки (описанной dt) с преобразуемым
:двоичным целым числом
:string_pack – адрес 80-битной ячейки (описанной dt), в которую сохраняется
упакованное 10-е значение
:adr_string_pack – ячейка с адресом string_pack (описанной dd)
:len_string_pack – длина string_pack
:adr_string – ячейка с адресом string (описанной dd). В string помещаются
;символы десятичных цифр для вывода.
:len_string – размер string (18 байт)
:………преобразуем bin › dec
finit
f 11d string_bin_qword:заносим в сопроцессор двоичное целое число
fbstp string_pack извлекаем упакованное десятичное
¦-------------распакуем……….
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.