Жажда скорости Крис Касперски Хакер, номер #095, стр. 095-130-4 Чтение/запись MSR регистров осуществляется командами RDMSR/WRMSR. Они доступны только из нулевого кольца и действуют следующим образом: в регистр ECX помещается номер выбранного MSR-регистра, а в регистровой паре EDX:EAX – возвращаемое/записываемое значение. Номера MSR-регистров также можно узнать из руководства по системному программированию. Так, например, номер регистр PerfEvtSel0 имеет номер 186h, а структура его управляющих полей приведена на рисунке. Собственно говоря, все, что нам нужно, это занести код события в регистр PerfEvtSel0/PerfEvtSel1 (биты 0-7), занести маску события, в данном случае равную нулю (биты 8-15), и взвести флажок Enable Counter (бит 22), чтобы начать подсчет событий. Описание остальных битов можно найти в документации. Нам они совершенно неинтересны, за исключением, пожалуй, поля USR (бит 16), открывающего доступ к счетчику с пользовательского уровня, что позволяет реализовать основной код в программе прикладного режима, которую намного проще отладить, чем драйвер. Но все-таки совсем без драйвера обойтись не получится, поскольку инструкция RDMSR на прикладном уровне возбуждает неизменное исключение. Как же быть?! Intel предоставила крошечную лазейку в виде команды RDPMC, читающей текущий счетчик производительности в регистровую пару EDX:EAX. Текущий — это тот, который до этого был установлен командой WRMSR, запустившей MSR-регистр PerfEvtSel0 или PerfEvtSel1. Однако по умолчанию RDMSR с прикладного уровня недоступна, и, прежде чем ей удастся воспользоваться, необходимо взвести PCE флажок в регистре CR4 (бит 8), модифицировать который можно только из нулевого кольца. Зато потом наступает благодать!!! Подробнее обо всем, что связано со счетчиками производительности, можно прочитать в разделе «Performance-Monitoring Events and Counters» руководства «Intel Architecture Optimization Reference Manua» или в уже упомянутой «библии» системного программиста «Intel Architecture Software Developer's Manual Volume 3: System Programming Guide». Таким образом, мыщъх'иная программа состоит из двух частей: крохотного псевдодрайвера и прикладной части. Драйвер обеспечивает загрузку необходимого кода события в соответствующий MSR-регистр (PerfEvtSel0 или PerfEvtSel1) и запускает счетчик, предварительно «разблокировав» команду RDPMC. Поскольку RDPMC способна читать только один счетчик (а нам необходимо отслеживать по меньшей мере два события — промахи кэш-памяти кода и данных), драйвер должен обеспечивать IOCTL-интерфейс с прикладным приложением, позволяя ему переключаться с одного счетчика на другой. Чтобы не переводить понапрасну бумагу, ниже будут приведены только ключевые фрагменты кода, а все остальное читатель без труда допишет и сам. В частности, процедура инициализации драйвера среди прочего должна содержать: DriverInitialize: ; // процедура инициализации драйвера … MOV EAX, CR4 OR EAX, 100h ; // разрешаем доступ к RDPMC с прикладного уровня |