Sdílet prostřednictvím


DTrace ETW

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

Viz také

DTrace ve Windows

Programování s DTrace pro Windows

Ukázky kódu DTrace Windows

DTrace – živý výpis