Bagikan melalui


DTrace ETW

Gunakan DTrace untuk Windows untuk memproses peristiwa ETW yang ada dan untuk menambahkan peristiwa ETW baru.

Pelacakan Peristiwa untuk Windows (ETW) adalah fasilitas pelacakan tingkat kernel yang memungkinkan Anda mencatat kernel atau peristiwa yang ditentukan aplikasi ke file log. Anda dapat mengolah peristiwa secara real-time atau dari file log dan menggunakannya untuk membedah aplikasi atau untuk mengetahui di mana masalah performa terjadi dalam aplikasi. Untuk informasi umum tentang ETW, lihat Tentang Pelacakan Peristiwa.

Nota

DTrace didukung di build Insider Windows setelah versi 18980 dan Windows Server Build 18975.

Untuk informasi umum tentang bekerja dengan DTrace di Windows, lihat DTrace.

Penyedia DTrace Windows ETW

Anda dapat menggunakan DTrace untuk menangkap dan melaporkan kejadian ETW yang berbasis pada pencatatan jejak dan manifes. Untuk menyelidiki kata kunci/level/eventID tertentu, probe ETW akan bekerja jauh lebih andal jika Anda tidak menggunakan karakter pengganti. Sebagai gantinya, tentukan sepenuhnya probe Anda berdasarkan aturan ini:

Probename = etw

Modname = Provider guid dalam bentuk xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, menggunakan karakter huruf kecil semua.

Funcname = Level_Keyword dalam bentuk 0x00_0x0000000000000000. Untuk mencocokkan semuanya, ini harus diatur ke 0xff_0xffffffffffffffff.

Probename = ID Peristiwa Bilangan Bulat (Integer) atau "generic_event" untuk mencocokkan semua ID peristiwa.

Pemfilteran berdasarkan Probename hanya berfungsi untuk peristiwa yang dimanifestasikan. Gunakan kartu liar (*) untuk peristiwa yang dilacak jejaknya.

Payload ETW diakses melalui arg0. Ini terdiri dari nt_EVENT_HEADER diikuti oleh data spesifik acara.

Menentukan penyedia ETW yang tersedia

Gunakan perintah logman untuk menampilkan penyedia ETW aktif dan GUID Penyedia mereka.

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

Menampilkan informasi penyedia ETW yang ada

DTrace memiliki kemampuan untuk menghasilkan peristiwa ETW. Ini berguna untuk skenario di mana ada alur ETW yang ada untuk melaporkan, mengumpulkan, dan menganalisis.

Gunakan contoh perintah DTrace ini untuk melaporkan kejadian dari penyediaKernel-Memory Microsoft-Windows.

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

Menambahkan peristiwa ETW baru

Peristiwa jejak Etw dapat dibuat dengan memanggil makro etw_trace. Peristiwa hanya akan dicatat jika ada pendengar aktif untuk penyedia pelacakan yang ditentukan, jika tidak, peristiwa tersebut akan dilewati.

Makro etw_trace mendukung jenis data dasar seperti int8, uint8, int16, uint16, int32, uint32, int64, uint64, hexint32, hexint64 dan string. Lihat tabel Tipe data ETW yang didukung di bawah ini untuk detail selengkapnya.

Contoh makro ETW_TRACE:

Skrip ini menghasilkan peristiwa ETW kustom saat rutinitas syscall mengembalikan 0xc0000001 - STATUS_UNSUCCESSFUL.

Anda dapat mengubah nilai this->status untuk menggunakan nilai NTSTATUS yang berbeda guna mencatat nilai pengembalian syscall yang berbeda.

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

Kode contoh ETW NUMA MEM STATS

Contoh skrip ini menggunakan penyedia Microsoft-Windows-Kernel-Memory ETW untuk mengeluarkan data memori simpul NUMA. Ukuran halaman dapat dikonversi ke ukuran dalam KB dengan mengalikan dengan 4. Untuk informasi umum tentang NUMA, lihat Dukungan NUMA.

Kode ini juga terletak di 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++;
}

Simpan file sebagai etwnumamemstats.d

Buka perintah sebagai Administrator dan jalankan skrip menggunakan opsi -s.

Berjalan pada PC Windows klien, satu simpul NUMA ditampilkan.

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

Jenis data ETW yang didukung

Jenis ETW Tipe data Bahasa D Notes
etw_struct Integer Nilai payload jenis ini mewakili jumlah anggota yang akan dimiliki struktur baru.
etw_string string Tidak tersedia
etw_mbcsstring string Tidak tersedia
etw_int8 Integer Ukuran tipe harus sesuai, dan pengubahan tipe ke `int8_t` dalam skrip D disarankan
etw_uint8 Integer Ukuran tipe harus sesuai, dan pengecoran tipe ke `uint8_t` dalam skrip D disarankan.
etw_int16 Integer Ukuran tipe harus sesuai, dan konversi menjadi `int16_t` dalam skrip D disarankan.
etw_uint16 Integer Ukuran jenis harus cocok, dan pencastingan menjadi `uint16_t` dalam skrip D disarankan.
etw_int32 Integer Tidak tersedia
etw_uint32 Integer Tidak tersedia
etw_int64 Integer Jenis harus ditetapkan secara eksplisit sebagai `int64_t` karena secara default D menggunakan `int32_t`
etw_uint64 Integer Jenis harus eksplisit sebagai "int64_t" karena D secara default ke "int32_t".
etw_float Skalar Konstanta floating-point tidak diperbolehkan dalam skrip D, tetapi diperbolehkan pada simbol yang dimuat.
etw_double Skalar Konstanta floating-point tidak diperbolehkan dalam skrip D, tetapi diperbolehkan pada simbol yang dimuat.
etw_bool32 Integer Tidak tersedia
etw_hexint32 Integer Tidak tersedia
etw_hexint64 Integer Jenis harus secara eksplisit berupa 'int64_t' karena D secara default menggunakan 'int32_t'
etw_countedmbcsstring Integer Tidak tersedia
etw_intptr Integer Ukuran jenis data berubah sesuai dengan arsitektur ('int32_t' vs 'int64_t')
etw_uintptr Integer Ukuran jenis data berubah sesuai dengan arsitektur ('int32_t' vs 'int64_t')
etw_pointer Integer Ukuran jenis data berubah sesuai dengan arsitektur ('int32_t' vs 'int64_t')
etw_char16 Integer Ukuran tipe harus sesuai, dan pencastingan ke `int16_t` dalam skrip D disarankan.
etw_char8 Integer Ukuran tipe harus sesuai, dan pengubahan tipe ke `int8_t` dalam skrip D disarankan.
etw_bool8 Integer Ukuran jenis harus cocok, dan transmisi ke 'int8_t' dalam skrip D disarankan
etw_hexint8 Integer Ukuran jenis harus cocok, dan pengubahan tipe ke `int8_t` dalam skrip D disarankan.
etw_hexint16 Integer Ukuran jenis harus cocok, dan pengalihan tipe ke 'int16_t' dalam skrip D disarankan
etw_pid Integer Tidak tersedia
etw_tid Integer Tidak tersedia
etw_mbcsxml Integer Tidak tersedia
etw_mbcsjson Integer Tidak tersedia
etw_countedmbcsxml Integer Tidak tersedia
etw_countedmbcsjson Integer Tidak tersedia
etw_win32error Integer Tidak tersedia
etw_ntstatus Integer Tidak tersedia
etw_hresult Integer Tidak tersedia

Lihat Juga

DTrace di Windows

Pemrograman DTrace Windows

Sampel Kode Windows DTrace

Dump Langsung DTrace