Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Используйте DTrace для Windows для обработки существующих событий ETW и добавления новых событий ETW.
Трассировка событий для Windows (ETW) — это средство трассировки на уровне ядра, которое позволяет регистрировать события ядра или события, определенные приложением, в файл журнала. События можно использовать в режиме реального времени или из файла журнала и использовать их для отладки приложения или определения проблем с производительностью приложения. Общие сведения о трассировке событий см. в разделе "О трассировке событий".
Замечание
DTrace поддерживается в инсайдерских сборках Windows после версии 18980 и Windows Server сборке 18975.
Общие сведения о работе с DTrace в Windows см. в разделе DTrace.
Поставщик DTrace для Windows ETW
DTrace можно использовать для записи и отчета о событиях, зафиксированных в трассировке, и событиях ETW на основе манифестов. Для проверки определенных ключевых слов, уровней или идентификаторов событий пробы ETW будут работать гораздо надежнее, если вы не используете подстановочные карточки. Вместо этого полностью укажите датчик на основе следующих правил:
Probename = etw
Modname = GUID поставщика в форме xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, используя все строчные символы.
Funcname = Level_Keyword формы 0x00_0x0000000000000000. Чтобы сопоставить все это, необходимо задать значение 0xff_0xffffffffffffffff.
Probename = целочисленный идентификатор события или "generic_event" для сопоставления всех идентификаторов событий.
Фильтрация на основе имени пробы работает только для манифестированных событий. Используйте подстановочный знак (*) для трассируемых событий.
Нагрузка ETW доступ осуществляется через arg0. Это состоит из nt'_EVENT_HEADER, за которым следует конкретная дата события.
Определение доступных поставщиков ETW
Используйте команду logman для отображения активных провайдеров ETW и их идентификаторов GUID.
C:\>logman query providers
...
Microsoft-Windows-Kernel-Memory {D1D93EF7-E1F2-4F45-9943-03D245FE6C00}
Microsoft-Windows-Kernel-Network {7DD42A49-5329-4832-8DFD-43D979153A88}
Microsoft-Windows-Kernel-PnP {9C205A39-1250-487D-ABD7-E831C6290539}
Microsoft-Windows-Kernel-Power {331C3B3A-2005-44C2-AC5E-77220C37D6B4}
Microsoft-Windows-Kernel-Prefetch {5322D61A-9EFA-4BC3-A3F9-14BE95C144F8}
Microsoft-Windows-Kernel-Process {22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}
...
Отображение сведений о существующем поставщике ETW
DTrace имеет возможность выводить события ETW. Это полезно для сценариев, когда существует конвейер ETW для создания отчетов, сбора и анализа.
Используйте эту команду DTrace, чтобы регистрировать события провайдера Microsoft-Windows-Kernel-Memory.
C:\>dtrace -n "etw:d1d93ef7-e1f2-4f45-9943-03d245fe6c00:0xff_0xffffffffffffffff:12"
dtrace: description 'etw:d1d93ef7-e1f2-4f45-9943-03d245fe6c00:0xff_0xffffffffffffffff:12' matched 1 probe
CPU ID FUNCTION:NAME
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
0 3271 0xff_0xffffffffffffffff:12
Добавление новых событий ETW
События трассировки etw можно создать, вызвав макрос etw_trace. События будут регистрироваться только если существует активный прослушиватель для указанного поставщика трассировки, в противном случае события будут пропущены.
Макрос etw_trace поддерживает базовые типы данных, такие как int8, uint8, int16, uint16, int32, uint32, int64, uint64, hexint32, hexint64 и string. Дополнительные сведения см. в таблице поддерживаемых типов данных ETW ниже.
Пример макроса ETW_TRACE:
Этот скрипт создает настраиваемое событие ETW, когда подпрограмма syscall возвращает 0xc0000001 - STATUS_UNSUCCESSFUL.
Можно изменить this->status значения, чтобы использовать другие значения NTSTATUS для регистрации различных возвращаемых значений системных вызовов.
syscall:::return
{
this->status = (uint32_t) arg0;
if (this->status == 0xc0000001UL)
{
etw_trace
(
"Tools.DTrace.Platform", /* Provider Name */
"AAD330CC-4BB9-588A-B252-08276853AF02", /* Provider GUID */
"My custom event from DTrace", /* Event Name */
1, /* Event Level (0 - 5) */
0x0000000000000020, /* Flag */
"etw_int32", /* Field_1 Name */
"PID",/* Field_1 Type */
(int32_t)pid, /* Field_1 Value */
"etw_string", /* Field_2 Name */
"Execname", /* Field_2 type */
execname, /* Field_2 Value */
"etw_string", /* Field_3 Name */
"Probefunc", /* Field_3 type */
probefunc /* Field_3 Value */
);
}
}
C:\> dtrace -s addnewetwevent.d
dtrace: script 'addnewetwevent.d' matched 1881 probes
CPU ID FUNCTION:NAME
0 93 NtAlpcSendWaitReceivePort:return
0 93 NtAlpcSendWaitReceivePort:return
0 93 NtAlpcSendWaitReceivePort:return
Пример кода ETW NUMA MEM STATS
В этом примере скрипт использует поставщика Microsoft-Windows-Kernel-Memory ETW для дампа памяти узла NUMA. Размер страницы может быть преобразован в размер в КБ путем умножения на 4. Общие сведения о NUMA см. в разделе "Поддержка NUMA".
Этот код также находится в https://github.com/microsoft/DTrace-on-Windows/blob/windows/samples/windows/etw/numamemstats.d
typedef struct KernelMemInfoEvent
{
struct nt`_EVENT_HEADER _EH;
uint32_t PartitionId;
uint32_t Count;
uint32_t NodeNumber;
}kmi;
typedef struct MemoryNodeInfo
{
uint64_t TotalPageCount;
uint64_t SmallFreePageCount;
uint64_t SmallZeroPageCount;
uint64_t MediumFreePageCount;
uint64_t MediumZeroPageCount;
uint64_t LargeFreePageCount;
uint64_t LargeZeroPageCount;
uint64_t HugeFreePageCount;
uint64_t HugeZeroPageCount;
}m_nodeinfo;
int printcounter;
BEGIN
{
printcounter = 0;
}
/* MemNodeInfo */
etw:d1d93ef7-e1f2-4f45-9943-03d245fe6c00:0xff_0xffffffffffffffff:12
{
if (printcounter%10 == 0)
{
printf ("\n \n");
printf("Partition ID: %d \n",((kmi *)arg0)->PartitionId);
printf("Count: %d \n", ((kmi *)arg0)->Count);
printf("Node number: %d\n", ((kmi *)arg0)->NodeNumber);
counters = (m_nodeinfo*)(arg0 + sizeof(struct nt`_EVENT_HEADER) + 12);
print(*counters);
/* Dump rest of the NUMA node info */
if (((kmi *)arg0)->Count > 1)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(1)) + (sizeof(uint32_t)*(1)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(1)) + (sizeof(uint32_t)*(1)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 2)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(2)) + (sizeof(uint32_t)*(2)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(2)) + (sizeof(uint32_t)*(2)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 3)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(3)) + (sizeof(uint32_t)*(3)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(3)) + (sizeof(uint32_t)*(3)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 4)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(4)) + (sizeof(uint32_t)*(4)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(4)) + (sizeof(uint32_t)*(4)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 5)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(5)) + (sizeof(uint32_t)*(5)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(5)) + (sizeof(uint32_t)*(5)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 6)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(6)) + (sizeof(uint32_t)*(6)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(6)) + (sizeof(uint32_t)*(6)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 7)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(7)) + (sizeof(uint32_t)*(7)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(7)) + (sizeof(uint32_t)*(7)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 8)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(8)) + (sizeof(uint32_t)*(8)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(8)) + (sizeof(uint32_t)*(8)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 9)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(9)) + (sizeof(uint32_t)*(9)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(9)) + (sizeof(uint32_t)*(9)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 10)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(10)) + (sizeof(uint32_t)*(10)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(10)) + (sizeof(uint32_t)*(10)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 11)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(11)) + (sizeof(uint32_t)*(11)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(11)) + (sizeof(uint32_t)*(11)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 12)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(12)) + (sizeof(uint32_t)*(12)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(12)) + (sizeof(uint32_t)*(12)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 13)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(13)) + (sizeof(uint32_t)*(13)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(13)) + (sizeof(uint32_t)*(13)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 14)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(14)) + (sizeof(uint32_t)*(14)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(14)) + (sizeof(uint32_t)*(14)) + sizeof(uint32_t));
print(*counters);
}
if (((kmi *)arg0)->Count > 15)
{
nodenumber = (uint32_t *) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(15)) + (sizeof(uint32_t)*(15)) );
printf ("Node Number: %d \n", *nodenumber);
counters = (m_nodeinfo*) (arg0 + sizeof(struct nt`_EVENT_HEADER) + 8 + (sizeof(m_nodeinfo)*(15)) + (sizeof(uint32_t)*(15)) + sizeof(uint32_t));
print(*counters);
}
}
exit(1);
printcounter++;
}
Сохраните файл как etwnumamemstats.d
Откройте командную строку от имени администратора и запустите скрипт с помощью параметра -s.
На клиентском Windows-компьютере отображается один узел NUMA.
C:\> dtrace -s etwnumamemstats.d
trace: script 'etwnumamemstats.d' matched 36 probes
CPU ID FUNCTION:NAME
0 42735 0xff_0xffffffffffffffff:12
Partition ID: 0
Count: 1
Node number: 1
m_nodeinfo {
uint64_t TotalPageCount = 0xab98d
uint64_t SmallFreePageCount = 0
uint64_t SmallZeroPageCount = 0x1bec
uint64_t MediumFreePageCount = 0
uint64_t MediumZeroPageCount = 0x5a
uint64_t LargeFreePageCount = 0
uint64_t LargeZeroPageCount = 0
uint64_t HugeFreePageCount = 0
uint64_t HugeZeroPageCount = 0
}
0 42735 0xff_0xffffffffffffffff:12
Поддерживаемые типы данных ETW
| Тип ETW | Тип данных языка D | Примечания |
|---|---|---|
| etw_struct | Целое число | Значение полезной нагрузки этого типа представляет количество членов новой структуры. |
| etw_string | струна | Не применимо |
| etw_mbcsstring | струна | Не применимо |
| etw_int8 | Целое число | Размер типа должен совпадать, и рекомендуется приведение к int8_t в скрипте D. |
| etw_uint8 | Целое число | Размер типа должен совпадать, и приведение к типу `uint8_t` в скрипте D рекомендуется |
| etw_int16 | Целое число | Размер типа должен совпадать, и приведение к `int16_t` в скрипте D рекомендуется. |
| etw_uint16 | Целое число | Размер типа должен соответствовать, а приведение типа к `uint16_t` в скрипте D рекомендуется. |
| etw_int32 | Целое число | Не применимо |
| etw_uint32 | Целое число | Не применимо |
| etw_int64 | Целое число | Тип должен быть явным образом "int64_t", так как по умолчанию D используется значение "int32_t" |
| etw_uint64 | Целое число | Тип должен быть явным образом "int64_t", так как по умолчанию D используется значение "int32_t" |
| etw_float | Скаляр | Константы с плавающей запятой не допускаются в скрипте D, но разрешены для загруженных символов. |
| etw_double | Скаляр | Константы с плавающей запятой не допускаются в скрипте D, но разрешены для загруженных символов. |
| etw_bool32 | Целое число | Не применимо |
| etw_hexint32 | Целое число | Не применимо |
| etw_hexint64 | Целое число | Тип должен быть явным образом "int64_t", так как по умолчанию D используется значение "int32_t" |
| etw_countedmbcsstring | Целое число | Не применимо |
| etw_intptr | Целое число | Размер типа данных изменяется в соответствии с архитектурой ("int32_t" и "int64_t" |
| etw_uintptr | Целое число | Размер типа данных изменяется в соответствии с архитектурой ("int32_t" и "int64_t" |
| etw_pointer | Целое число | Размер типа данных изменяется в соответствии с архитектурой ("int32_t" и "int64_t" |
| etw_char16 | Целое число | Размер типа должен соответствовать, и приведение к `int16_t` в D-скрипте рекомендуется. |
| etw_char8 | Целое число | Размер типа должен соответствовать, и приведение к типу "int8_t" в скрипте D рекомендуется |
| etw_bool8 | Целое число | Размер типа должен соответствовать и приведение к "int8_t" в скрипте D рекомендуется |
| etw_hexint8 | Целое число | Размер типа должен совпадать, и рекомендуется приведение к int8_t в скрипте D. |
| etw_hexint16 | Целое число | Размер типа должен соответствовать, а приведение к `int16_t` в скрипте D рекомендуется |
| etw_pid | Целое число | Не применимо |
| etw_tid | Целое число | Не применимо |
| etw_mbcsxml | Целое число | Не применимо |
| etw_mbcsjson | Целое число | Не применимо |
| etw_countedmbcsxml | Целое число | Не применимо |
| etw_countedmbcsjson | Целое число | Не применимо |
| etw_win32error | Целое число | Не применимо |
| etw_ntstatus | Целое число | Не применимо |
| etw_hresult | Целое число | Не применимо |
См. также
Программирование DTrace Windows