Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Nástroj DTrace pro Windows slouží ke zpracování existujících událostí Trasování událostí pro Windows (ETW) a přidávání nových ETW událostí.
Trasování událostí pro Windows (ETW) je zařízení pro trasování na úrovni jádra, které umožňuje protokolovat události definované jádrem nebo aplikacemi do souboru protokolu. Události můžete využívat v reálném čase nebo ze souboru protokolu a použít je k ladění aplikace nebo k určení, kde v aplikaci dochází k problémům s výkonem. Obecné informace o trasování událostí najdete v tématu Trasování událostí.
Poznámka:
DTrace se podporuje v buildech Insider systému Windows po verzi 18980 a buildu Windows Serveru 18975.
Obecné informace o práci s DTrace ve Windows naleznete v tématu DTrace.
Poskytovatel ETW Windows DTrace
Můžete použít DTrace k zachycení a generování sestav událostí ETW zaznamenaných trasováním a na základě manifestu. Pokud chcete testovat konkrétní klíčová slova, úrovně nebo ID událostí, budou sondy ETW fungovat mnohem spolehlivěji, pokud nepoužíváte zástupné znaky. Místo toho plně definujte sondu na základě těchto pravidel:
Název zkoušky = etw
Modname = Identifikátor GUID zprostředkovatele ve formátu xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx používající všechna malá písmena.
Funcname = Level_Keyword ve tvaru 0x00_0x0000000000000000. Aby vše odpovídalo, mělo by být nastaveno na 0xff_0xffffffffffffffff.
Probename = ID události typu Integer nebo "generic_event", aby odpovídalo všem ID událostí.
Filtrování založené na názvu sondy funguje pouze pro manifestované události. Pro trasované události použijte zástupný znak (*).
Datová část ETW je přístupná prostřednictvím arg0. Skládá se z nt'_EVENT_HEADER následované datem konkrétní události.
Určení dostupných ETW poskytovatelů
Pomocí příkazu logman zobrazte aktivní poskytovatele ETW (Trasování událostí pro Windows) a jejich identifikátory 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}
...
Zobrazení informací o stávajícím poskytovateli ETW
DTrace je schopna generovat události Trasování událostí pro Windows. To je užitečné pro scénáře, ve kterých existuje ETW pipeline pro reportování, shromažďování a analýzu.
Tento příkaz DTrace použijte k hlášení událostí poskytovatele 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
Přidání nových událostí ETW
Události ETW lze vytvořit voláním makra etw_trace. Události budou protokolovány pouze v případě, že pro zadaného zprostředkovatele trasování existuje aktivní posluchač, jinak budou přeskočeny.
Makro etw_trace podporuje základní datové typy, jako jsou int8, uint8, int16, uint16, int32, uint32, int64, uint64, hexint32, hexint64 a řetězec. Podrobnosti najdete v tabulce podporovaných datových typů ETW níže.
Příklad ETW_TRACE makra:
Tento skript vygeneruje vlastní událost etW, když rutina syscall vrátí 0xc0000001 – STATUS_UNSUCCESSFUL.
Změňte hodnotu this->status, aby používala jiné hodnoty NTSTATUS pro zaznamenávání různých návratových hodnot z "syscall".
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
Příklad kódu ETW NUMA MEM STATS
Tento ukázkový skript používá Microsoft-Windows-Kernel-Memory poskytovatele ETW k výpisu paměti uzlu NUMA. Velikost stránky lze převést na velikost v kB vynásobením 4. Obecné informace o NUMA naleznete v tématu Podpora NUMA.
Tento kód se nachází také na adrese 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++;
}
Uložte soubor jako etwnumamemstats.d.
Otevřete příkazový řádek jako správce a spusťte skript pomocí možnosti -s.
Na klientském počítači s Windows se zobrazí jeden uzel 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
Podporované datové typy Trasování událostí pro Windows
| Typ Trasování událostí pro Windows | Datový typ jazyka D | poznámky |
|---|---|---|
| etw_struct | Integer | Hodnota nákladu tohoto typu představuje počet členů, které bude mít nová struktura. |
| etw_string | řetězec | není k dispozici |
| etw_mbcsstring | řetězec | není k dispozici |
| etw_int8 | Integer | Velikost typu by se měla shodovat a přetypování na "int8_t" ve skriptu D se doporučuje. |
| etw_uint8 | Integer | Velikost typu by měla odpovídat a ve skriptu D se doporučuje přetypovat na "uint8_t". |
| etw_int16 | Integer | Velikost typu by se měla shodovat a přetypování na int16_t ve skriptu D se doporučuje. |
| etw_uint16 | Integer | Velikost typu by se měla shodovat a přetypování na "uint16_t" ve skriptu D se doporučuje. |
| etw_int32 | Integer | není k dispozici |
| etw_uint32 | Integer | není k dispozici |
| etw_int64 | Integer | Typ musí být explicitně "int64_t", protože výchozí hodnota D je int32_t. |
| etw_uint64 | Integer | Typ musí být explicitně "int64_t", protože výchozí hodnota D je int32_t. |
| etw_float | Skalární | Konstanty s plovoucí desetinou čárkou nejsou ve skriptu D povolené, ale umožňují ji na načtených symbolech. |
| etw_double | Skalární | Konstanty s plovoucí desetinou čárkou nejsou ve skriptu D povolené, ale umožňují ji na načtených symbolech. |
| etw_bool32 | Integer | není k dispozici |
| etw_hexint32 | Integer | není k dispozici |
| etw_hexint64 | Integer | Typ musí být explicitně "int64_t", protože výchozí hodnota D je int32_t. |
| etw_countedmbcsstring | Integer | není k dispozici |
| etw_intptr | Integer | Velikost datového typu se mění podle architektury (int32_t vs. int64_t). |
| etw_uintptr | Integer | Velikost datového typu se mění podle architektury (int32_t vs. int64_t). |
| etw_pointer | Integer | Velikost datového typu se mění podle architektury (int32_t vs. int64_t). |
| etw_char16 | Integer | Velikost typu by se měla shodovat a přetypování na "int16_t" ve skriptu D se doporučuje. |
| etw_char8 | Integer | Velikost typu by se měla shodovat a přetypování na „int8_t“ ve skriptu D je doporučeno. |
| etw_bool8 | Integer | Velikost typu by se měla shodovat a přetypování na "int8_t" ve skriptu D se doporučuje. |
| etw_hexint8 | Integer | Velikost typu by se měla shodovat a přetypování na "int8_t" ve skriptu D se doporučuje. |
| etw_hexint16 | Integer | Velikost typu by se měla shodovat a ve skriptu napsaném v jazyce D se doporučuje přetypování na "int16_t". |
| etw_pid | Integer | není k dispozici |
| etw_tid | Integer | není k dispozici |
| etw_mbcsxml | Integer | není k dispozici |
| etw_mbcsjson | Integer | není k dispozici |
| etw_countedmbcsxml | Integer | není k dispozici |
| etw_countedmbcsjson | Integer | není k dispozici |
| etw_win32error | Integer | není k dispozici |
| etw_ntstatus | Integer | není k dispozici |
| etw_hresult | Integer | není k dispozici |