DTrace ETW

A Windows DTrace használatával feldolgozhatja a meglévő ETW-eseményeket, és új ETW-eseményeket vehet fel.

Az Event Tracing for Windows (ETW) egy kernelszintű nyomkövetési eszköz, amellyel naplózhatja a kernel- vagy alkalmazás által meghatározott eseményeket egy naplófájlba. Az eseményeket valós időben vagy naplófájlból is felhasználhatja, és segítségével hibakeresést végezhet egy alkalmazáson, vagy meghatározhatja, hogy hol fordulnak elő teljesítményproblémák az alkalmazásban. Az ETW-vel kapcsolatos általános információkért tekintse meg az eseménykövetést ismertető témakört.

Megjegyzés:

A DTrace az 18980-es és a Windows Server 18975-ös build után támogatott a Windows Insider-buildjeiben.

A DTrace windowsos használatával kapcsolatos általános információkért lásd: DTrace.

ETW Windows DTrace Provider

A DTrace használatával rögzítheti és jelentheti a naplózott és jegyzékalapú ETW-eseményeket. Adott kulcsszavak/szintek/eventID-k vizsgálatához az ETW vizsgálatok sokkal megbízhatóbbak lesznek, ha nem használ helyettesítő karaktereket. Ehelyett határozza meg pontosan a szondát az alábbi szabályok alapján:

Mintavétel neve = etw

Modname = Szolgáltató GUID a következő formában: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, minden karakter kisbetűvel van.

Funcname = a Level_Keyword formátuma: 0x00_0x0000000000000000. Annak érdekében, hogy minden illeszkedjen, ezt 0xff_0xffffffffffffffff értékre kell beállítani.

Probename = Egész szám eseményazonosító vagy "generic_event," hogy megfeleljen az összes eseményazonosítónak.

A Mintavételnév alapján történő szűrés csak a nyilvánult események esetében működik. A nyomkövetési eseményekhez használjon helyettesítő karaktert (*).

Az ETW hasznos terhelése az arg0-en keresztül érhető el. Ez az nt'_EVENT_HEADER és az eseményspecifikus dátumból áll.

Elérhető ETW-szolgáltatók meghatározása

A logman paranccsal megjelenítheti az aktív ETW-szolgáltatókat és azok szolgáltatói GRAFIKUS AZONOSÍTÓit.

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}
...

Meglévő ETW-szolgáltató adatainak megjelenítése

A DTrace képes az ETW-események kimenetére. Ez olyan helyzetekben hasznos, ahol már létezik ETW-folyamat jelentésére, gyűjtésére és elemzésére.

Ebben a példában a DTrace paranccsal jelentheti a Microsoft-WindowsKernel-Memory szolgáltatói eseményeket.

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

Új ETW-események hozzáadása

Az Etw nyomkövetési események a etw_trace makró meghívásával hozhatók létre. Az események csak akkor lesznek naplózva, ha a megadott nyomkövetési szolgáltató aktív figyelője van, ellenkező esetben a rendszer kihagyja őket.

Az etw_trace makró olyan alapvető adattípusokat támogat, mint az int8, az uint8, az int16, az uint16, az int32, az uint32, az int64, az uint64, az hexint32, az hexint64 és a string. További részletekért tekintse meg az alábbi támogatott ETW-adattípusok táblázatot.

Példa ETW_TRACE makróra:

Ez a szkript létrehoz egy egyéni ETW-eseményt, amikor a syscall rutin 0xc0000001 - STATUS_UNSUCCESSFUL ad vissza.

Az értéket módosíthatja this->status úgy, hogy egy másik NTSTATUS-értéket használjon a különböző syscall-visszatérési értékek naplózásához.

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 példakód

Ez a példaszkript a Microsoft-WindowsKernel-Memory ETW szolgáltatót használja a NUMA-csomópont memóriájának kiírásához. Az oldalméretet át lehet alakítani KB méretté, ha megszorozzuk 4-gyel. A NUMA-ról általános információkért lásd: NUMA-támogatás.

Ez a kód itt található: 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++;
}

Mentse a fájlt etwnumamemstats.d néven

Nyisson meg egy parancssort rendszergazdaként, és futtassa a szkriptet a -s beállítással.

Egy ügyfélszámítógépen futtatva egyetlen NUMA-csomópont jelenik meg.

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

Támogatott ETW-adattípusok

ETW típus D Nyelv adattípusa Jegyzetek
etw_struct Egész szám Az ilyen típusú hasznos teher érték azt a tagszámot adja meg, amely az új struktúrának lesz.
etw_string karakterlánc Nincs adat.
etw_mbcsstring karakterlánc Nincs adat.
etw_int8 Egész szám A típus méretének meg kell egyeznie, és az 'int8_t'-re való kasztolás javasolt a D szkriptben.
etw_uint8 Egész szám A típus méretének meg kell egyeznie, és a D szkriptben a "uint8_t" értéket kell megadni
etw_int16 Egész szám A típus méretének meg kell felelnie, és a D szkriptben az `int16_t` típusra történő konvertálás javasolt
etw_uint16 Egész szám A típusméretnek meg kell egyeznie, és a D szkriptben az `uint16_t` típusra való átalakítást javasolt elvégezni.
etw_int32 Egész szám Nincs adat.
etw_uint32 Egész szám Nincs adat.
etw_int64 Egész szám A típusnak explicit módon "int64_t" kell lennie, mivel a D alapértelmezett értéke "int32_t"
etw_uint64 Egész szám A típusnak explicit módon "int64_t" kell lennie, mivel a D alapértelmezett értéke "int32_t"
etw_float Skaláris A lebegőpontos állandók nem engedélyezettek a D szkriptben, de a betöltött szimbólumokon engedélyezik
etw_double Skaláris A lebegőpontos állandók nem engedélyezettek a D szkriptben, de a betöltött szimbólumokon engedélyezik
etw_bool32 Egész szám Nincs adat.
etw_hexint32 Egész szám Nincs adat.
etw_hexint64 Egész szám A típusnak explicit módon "int64_t" kell lennie, mivel a D alapértelmezett értéke "int32_t"
etw_countedmbcsstring Egész szám Nincs adat.
etw_intptr Egész szám Az adattípus mérete az architektúra szerint változik ("int32_t" és "int64_t")
etw_uintptr Egész szám Az adattípus mérete az architektúra szerint változik ("int32_t" és "int64_t")
etw_pointer Egész szám Az adattípus mérete az architektúra szerint változik ("int32_t" és "int64_t")
etw_char16 Egész szám A típus méreteinek egyezniük kell egymással, és a D szkriptben ajánlott az `int16_t` típusra való kényszerítés.
etw_char8 Egész szám A típus méretének meg kell egyeznie, és a D szkriptben az `int8_t` típusra történő konvertálás javasolt.
etw_bool8 Egész szám A típus méretének meg kell egyeznie, és a D szkriptben javasolt az `int8_t` típusra történő konvertálás.
etw_hexint8 Egész szám A típus méretének meg kell egyeznie, és a D szkriptben az `int8_t` típusra történő átalakítás javasolt.
etw_hexint16 Egész szám A típus méretének meg kell egyeznie, és a D szkriptben a `int16_t` típusra történő kényszerítés javasolt.
etw_pid Egész szám Nincs adat.
etw_tid Egész szám Nincs adat.
etw_mbcsxml Egész szám Nincs adat.
etw_mbcsjson Egész szám Nincs adat.
etw_countedmbcsxml Egész szám Nincs adat.
etw_countedmbcsjson Egész szám Nincs adat.
etw_win32error Egész szám Nincs adat.
etw_ntstatus Egész szám Nincs adat.
etw_hresult Egész szám Nincs adat.

Lásd még:

DTrace Windows rendszeren

DTrace Windows–programozás

DTrace Windows-kódminták

DTrace Élő memóriakép