Сборник по задачам и примерам Assembler

         

Профайлер



Глава 8. Профайлер

 



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



Использование счетчика меток реального времени 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: ЕАХ. Если выполнение команды запрещено, то работа команды заканчивается.

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


На взгляд автора, применение этих макрокоманд должно подчиняться следующему алгоритму. Вызов первой макрокоманды, назовем ее profileMn, должен зафиксировать момент, относительно которого будет производиться отсчет тактов процессора, то есть в начале профилируемого участка программы. Вызов второй макрокоманды prof i I er_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 извлекаем упакованное десятичное

¦-------------распакуем..........

Ids si.adr_string_pack

add si.len_string_pack-2 :на конец string_pack (18 упак. дес. цифр)

les di.adr_string

movcx.9 ;9 пар упакованных десятичных цифр

xor ax,ax cycl: xor ax,ax

std ;string_pack обрабатываем с конца

lodsb ;в al очередные 2 упакованные десятичные цифры

распаковываем - аИ=младшая, а1=старшая

shi ax.4

rol al .4

or ах.ЗОЗОп :преобразуем в символьное представление

xchg ah .al :ап-младшая. al-старшая

eld :в string записываем с начала

stosw

loop cycl

;.........выводим на консоль...............................

' mov bx.l стандартный дескриптор - экран

mov cx.len_string

Ids dx.adr_string -.формируем указатель на строку string

mov ah.40h :номер функции DOS

int 21h :выводим

jc exit ;переход в случае ошибки

endm

profileMn macro val_l:REQ

;val_l - ячейка памяти 64 бита (2x32) для сохранения момента :начала профилирования ("грязного") pushad сохранение всех регистров общего назначения в стеке

db Ofh.31h;RDTSC mov val_l+4.edx

mov va!_l.eax popad восстановление всех регистров общего назначения из стека

endm

profiler_out macro val_l:REQ. val_2:REQ

:val_l - ячейка памяти 64 бита (2x32). 8 которой при входе в макрос сохранен :момент начала профилирования командой profilerjn. Далее в макросе эта ячейка :содержит результат профилирования - число тактов процессора :val_2 - ячейка памяти 64 бита (2x32). в которой сохраняется момент ("грязный") окончания профилирования



pushad сохранение всех регистров общего назначения в стеке db 0fh,31h :RDTSC - окончание профилирования

mov val_2+4.edx

mov val_2,eax

профилируем pushad и popad с учетом двух shrd pushad popad

db 0fh.31h;RDTSC

:теперь необходимо получить чистое время профилирования, для чего результат необходимо скорректировать (уменьшить) на количество тактов процессора, :потребное для выполнения пар команд PUSHAONPOPAD и M0V

subeax, val_2

jnc $+4 :учет заема из старшего разряда

dec edx

subedx. val_2+4 ;в edx:eax кол-ва тактов для выполнения 2-х команд ;PUSHAD\POPAD и 2-х SHRD

mov eax,val_l

sub val_2.eax

mov eax.val_l+4

jnc $+7 :учет заема из старшего разряда при выполнении предыдущего вычитания

dec val_2+4

sub val_2+4,eax

;в val_2:val_2+4 - чистое количество тактов процессора для выполнения профилируемого участка

popad восстановление всех регистров общего назначения из стека

:выводим

bin_dec_fpu val_2_q. string_pack, adr_string_pack, len_string_pack. adr_string. len_string

endm .data

val_2 label dword val_2_q dq 0 val_l label dword

dq 0

:b string_pack исходное значение из val_2_q в упакованном десятичном формате string_pack dt О

len_string_pack=$-string_pack adr_stringpack dd string_pack

string db 18 dup (0) максимальный результат состоит из 18 десятичных цифр

len_string=$-string adr_string dd string

.code

профилируем выполнение команд работы со стеком profiIer_i n val_l

push eax

pop eax

profiler_out val_l. val_2 exit: :выход из программы

Составьте тестовые примеры и «поиграйтесь» с данной программой. Обратите внимание, что при задании пустой последовательности команд между парой макросов profilerjn и profi1er_out все равно получается некоторая величина профилирования. Она постоянна, ее источник — сами команды RDTSC, которые требуют тактов процессора для своего исполнения. Эту величину можно скорректировать разными способами, но можно и не трогать, а учитывать при подведении окончательных результатов тестирования нужного вам фрагмента кода. На компьютере автора эта величина равна 52.

В этой программе для визуализации результатов профилирования разработана макрокоманда bi n_dec_fpu, производящая перевод значения из двоичной системы в десятичную.

 

Команда CPUID — получение информации о текущем процессоре



Команда CPUID — получение информации о текущем процессоре

Для получения информации о процессоре необходимо в регистр ЕАХ поместить параметр — одно из значений 0, 1 или 2.

Если ЕАХ = 0, то в регистрах ЕАХ, ЕВХ, EDX, ЕСХ формируется следующая информация:

ЕАХ = n, где n — максимально допустимое значение параметра, которое может быть помещено в регистр ЕАХ для задания режима сбора информации;

(EBX)+(EDX)+(ECX) — в этих регистрах содержится строка-идентификатор процессора Geninnelntel .

Если ЕАХ = 1, то в регистрах процессора сформируется следующая информация:

ЕАХ = n — информация о микропроцессоре (см. табл. 8.1 и 8.2);

EDX = n — информация о возможностях процессора (см. табл. 8.3).

Если ЕАХ = 2, то в регистрах ЕАХ, ЕВХ, ЕСХ и EDX формируется информация о кэшпамяти первого уровня и TLB-буферах. Первый байт регистра ЕАХ содержит число, означающее, сколько раз необходимо последовательно выполнить команду CPUID для получения полной информации о кэш-памяти первого уровня и TLB-буферах. Другие байты регистра ЕАХ и все байты регистров ЕВХ, ЕСХ и EDX содержат однобайтовые дескрипторы, характеризующие кэш-память и TLB-буферы (см. табл. 8.4). Старший бит каждого регистра характеризует достоверность информации в регистре. Если он равен нулю, то информация достоверна, иначе — регистр не используется.

Таблица 8.1. Поля регистра ЕАХ после выполнения команды CPUID (при ЕАХ = 1)

Биты ЕАХ Назначение

0...3 Версия изменений модели

4...7 Модель в семействе (см. табл. 8.2)

8...11 Семейство микропроцессоров (см. табл. 8.2)
12...13 Тип процессора (00 — обычный процессор; 01 — Overdrive-процессор;
10 — процессор для использования в двухпроцессорных системах)

Таблица 8.2., Значения бит 4...7 и 8...11 регистра ЕАХ

Биты ЕАХ (8...11) Биты ЕАХ (4...7) Тип процессора
0100 0000 или 0001 I486DX
0100 0010 I486SX
0101 0010 Pentium 75-200
0101 0100 Pentium MMX 166-200
0110 0001 Pentium Pro
0110 0011 Pentium II, модель 3
0110

0101 Pentium II, модель 5,
Pentium II Xeon
0110 0110 Celeron, модель 6
0110

0111

Pentium III и Pentium HI
Xeon
0110 0011 Pentium II OverDrive

Таблица 8.3. Поля регистра EDX после выполнения команды CPUID (при ЕАХ=n)

Биты EDX Назначение (если биты установлены)
0 Присутствует сопроцессор с набором команд i387
1 Поддержка расширенных возможностей обработки прерываний в режиме

виртуального процессора i8086
2 Процессор поддерживает точки прерывания ввода-вывода (точки останова

по обращению к портам) для предоставления расширенных возможностей

отладки и доступ к регистрам DR4 и DR5. Флаг CR4.DE=1
3 Процессор поддерживает 4-мегабайтные страницы
4 Поддержка счетчика меток реального времени TSC
5 Поддержка команд RDMSR и WRMSR для работы с модельно-зависимыми

регистрами
6 Процессор поддерживает физические адреса, большие, чем 32 бита,

расширенный формат элемента таблицы страниц, дополнительный

уровень трансляции страничного адреса и 2-мегабайтные страницы
7 Поддержка исключения 18 — машинного контроля
8 Поддержка инструкции CMPXCHG8B
9 Микропроцессор содержит программно-доступный контроллер

прерываний APIC
10 Резерв
11 Поддержка инструкций SYSENTER и SYSEXIT быстрых системных вызовов
12 Поддержка регистра управления кэшированием MTRR_CAP

(относится к MSR-регистрам)
13 Поддержка работы с битом G, определяющим глобальность страницы

в PTDE и РТЕ. Бит CR4.PGE = 1
14 Поддержка архитектуры машинного контроля (MSR-регистр MCG_CAP)
15 Поддержка инструкций CMOV, FCMOVCC, FCOMI условной пересылки
16 Поддержка инструкций CMOVCC, FMOVCC и FCOMI (если установлен бит 0)
17 Процессор поддерживает 36-разрядную физическую адресацию

с 4-мегабайтными страницами
18 Процессор поддерживает собственную идентификацию по уникальному

96-битному номеру и эта поддержка активна
19-22 Резерв
23 Поддержка целочисленного MMX-расширения
24 Процессор поддерживает команды FXSAVE и FXRSTOR
25 Поддержка MMX-расширения с плавающей точкой
24-31 Резерв
Таблица 8.4. Значения дескрипторов, описывающих кэш-память, и дескрипторов TLB



дескриптора Значение
00h

Olh
Нулевой дескриптор

Буфер TLB-команд: размер страницы — 4 Кбайт,

ассоциативный 4-канальный, 32 входа
02h Буфер TLB-команд: размер страницы — 4 Кбайт, ассоциативный,

2 входа
03h Буфер TLB-данных: размер страницы — 4 Кбайт,

ассоциативный 4-канальный, 64 входа
04h Буфер TLB-данных: размер страницы — 4 Кбайт,

ассоциативный 4-направленный, 8 входов
06h Кэш команд: размер 8 Кбайт, наборно-ассоциативный 4-канальный,

длина строки 32 байта
08h Кэш команд: размер 16 Кбайт, наборно-ассоциативный 2-канальный,

длина строки 32 байта
Oah Кэш данных: размер 8 Кбайт, ассоциативный 2-направленный,

длина строки 32 байта
Och Кэш данных: размер 16 Кбайт,

ассоциативный 2-или 4-направленный, длина строки 32 байта
40h Кэш-память второго уровня (L2) отсутствует
41h Объединенный кэш: размер 128 Кбайт,

наборно-ассоциативный 4-канальный, длина строки 32 байта
42h Объединенный кэш: размер 256 Кбайт,

наборно-ассоциативный 4-направленный, длина строки 32 байта
43h Объединенный кэш: размер 512 Кбайт,

наборно-ассоциативный 4-направленный, длина строки 32 байта
44h Объединенный кэш: размер 1 Мбайт,

наборно-ассоциативный 4-направленный, длина строки 32 байта
45h Объединенный кэш: размер 2 Мбайт,

наборно-ассоциативный 4-нанравлеиный, длина строки 32 байта
Рассмотрим подробнее средства для мониторинга производительности, которые включают счетчик меток реального времени TSC (Time Stamp Counter) и счетчики событий CTRO, CTRL

 

Команды RDMSR и WRMSR



Команды RDMSR и WRMSR

Команда RDMSR (ReaD from Model Specific Register) выполняет чтение из MSR-регистра. Действие команды заключается в проверке двух условий: во-первых, проверяется наличие нулевого уровня привилегированности кода, во-вторых, проверяется наличие в регистре ЕСХ значения, адресующего один из MSR-регистров. Если хотя бы одно из этих условий не выполняется, то выполнение команды RDMSR заканчивается. Если выполняются оба условия, то значение MSR-регистра, адресуемого содержимым регистра ЕСХ, помещается в пару 32-битных регистров EDX:EAX.

Команда WRMSR (WRite to Model Specific Register) производит запись значения в один из 64-разрядных MSR-регистров. Действие команды заключается в проверке тех же двух условий: во-первых, проверяется наличие нулевого уровня привилегированности кода, во-вторых, проверяется наличие в регистре ЕСХ значения, адресующего один из MSR-регистров. Если хотя бы одно из этих условий не выполняется, то работа команды заканчивается. Если выполняются оба условия, то значение пары 32-битных регистров EDX: ЕАХ пересылается в 64-битный MSR-регистр, номер которого задан в регистре ЕСХ.

 



Профайлер



Профайлер

Если вы можете измерить и выразить числами то, о чем

говорите, — кое-что вы об этом знаете, если же вы не можете

этого измерить и выразить числами — тание ваше ограничено

и неудовлетворительно: возможно, что это начало знания,

но едва ли вы в мыслях продвинулись до уровня научной теории.

Лорд Кельвин (конец XIX века)

...наука начинается с тех пор, как начинают измерять.

Д. И. Менделеев

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

 



Расширение традиционной архитектуры Intel



Расширение традиционной архитектуры Intel

С появлением микропроцессоров пятого поколения (Pentium, Pentium MMX...) программисту следует различать два слоя микропроцессоров архитектуры Intel: базовый и модельно-зависимый.

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

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

Физически модельно-зависимые средства представляют собой набор модель-но-зависимых регистров — MSR (Model Specific Registers). Наличие и назначение этих регистров по определению зависит от конкретной модели процессора, что, в свою очередь, не гарантирует их поддержку будущими процессорами архитектуры Intel. MSR-регистры обеспечивают управление различными аппаратно-и программно-зависимыми средствами, включая следующие:

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

расширения отладки;

И поддержка исключения машинной ошибки и архитектуры машинного контроля (МСА);

регистры MTRR для поддержки расширенных средств кэширования.

Чтение и запись в MSR-регистры осуществляются командами RDMSR и WRMSR. Большинство MSR-регистров инициализируются при программной инициализации процессора, многие из них можно впоследствии установить в соответствии с конкретными потребностями программы. Приведем «краткое описание команд RDMSR, WRMSR И CPUID.