Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Utilizzare DTrace per Windows per elaborare gli eventi ETW esistenti e per aggiungere nuovi eventi ETW.
Event Tracing for Windows (ETW) è una funzionalità di traccia a livello di kernel che consente di registrare eventi kernel o definiti dall'applicazione in un file di log. È possibile utilizzare gli eventi in tempo reale o da un file di log e usarli per eseguire il debug di un'applicazione o per determinare dove si verificano problemi di prestazioni nell'applicazione. Per informazioni generali su ETW, vedere Informazioni sulla traccia eventi.
Annotazioni
DTrace è supportato nelle build Insider di Windows dopo la versione 18980 e Windows Server Build 18975.
Per informazioni generali sull'uso di DTrace in Windows, vedere DTrace.
ETW Windows DTrace Provider
È possibile usare DTrace per acquisire e segnalare gli eventi ETW registrati come traccia e basati su manifesti. Per sondare parole chiave, livelli o EventID specifici, i probe ETW funzioneranno in modo molto più affidabile se non usate caratteri jolly. Specificare invece completamente la sonda in base a queste regole:
Probename = etw
Modname = GUID del provider nel formato xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, usando tutti i caratteri minuscoli.
Funcname = Level_Keyword del formato 0x00_0x0000000000000000. Per ottenere una corrispondenza con tutto, questo dovrà essere impostato su 0xff_0xffffffffffffffff.
Probename = ID evento intero o "generic_event" per corrispondere a tutti gli ID evento.
Il filtro basato su Probename funziona solo per gli eventi manifestati. Usare il carattere jolly (*) per gli eventi registrati nella traccia.
Il payload ETW è accessibile tramite arg0. Questo è costituito da nt'_EVENT_HEADER seguito da una data specifica dell'evento.
Determinazione dei provider ETW disponibili
Usare il comando logman per visualizzare i provider ETW attivi e i rispettivi GUID dei provider.
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}
...
Visualizzazione delle informazioni sul provider ETW esistenti
DTrace ha la possibilità di generare eventi ETW. Ciò è utile per gli scenari in cui è presente una pipeline ETW esistente da segnalare, raccogliere e analizzare.
Usare questo comando DTrace di esempio per segnalare gli eventi del provider 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
Aggiunta di nuovi eventi ETW
È possibile creare eventi di traccia Etw chiamando la macro etw_trace. Gli eventi verranno registrati solo se è presente un listener attivo per il provider di traccia specificato, altrimenti verranno ignorati.
La macro etw_trace supporta tipi di dati di base, ad esempio int8, uint8, int16, uint16, int32, uint32, int64, uint64, hexint32, hexint64 e string. Per altri dettagli, vedere la tabella Tipi di dati ETW supportati di seguito.
Esempio di macro ETW_TRACE:
Questo script genera un evento ETW personalizzato quando la routine syscall restituisce 0xc0000001 - STATUS_UNSUCCESSFUL.
È possibile modificare il valore this->status per usare i valori NTSTATUS diversi per registrare valori di ritorno syscall diversi.
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
Codice di esempio ETW NUMA MEM STATS
Questo script di esempio usa Microsoft-Windows-Kernel-Memory provider ETW per eseguire il dump della memoria del nodo NUMA. Le dimensioni della pagina possono essere convertite in dimensioni in KB moltiplicando per 4. Per informazioni generali su NUMA, vedere Supporto NUMA.
Questo codice si trova anche in 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++;
}
Salvare il file come etwnumamemstats.d
Aprire la finestra del prompt dei comandi come Amministratore ed eseguire lo script usando l'opzione -s.
In esecuzione in un PC Windows client viene visualizzato un singolo nodo 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
Tipi di dati ETW supportati
| Tipo ETW | Tipo di dati D Language | Notes |
|---|---|---|
| etw_struct | Integer | Il valore del payload di questo tipo rappresenta il numero di membri che avrà una nuova struttura. |
| etw_string | corda | Non disponibile |
| etw_mbcsstring | corda | Non disponibile |
| etw_int8 | Integer | È consigliabile che le dimensioni del tipo di dato corrispondano e il cast a `int8_t` nello script D |
| etw_uint8 | Integer | È consigliabile che la dimensione del tipo corrisponda e che nel D script si effettui il cast a 'uint8_t' |
| etw_int16 | Integer | Si consiglia di far corrispondere la dimensione del tipo ed effettuare il cast a `int16_t` nello script D. |
| etw_uint16 | Integer | È consigliabile che la dimensione del tipo sia coerente, e si consiglia di fare il cast a `uint16_t` nello script D. |
| etw_int32 | Integer | Non disponibile |
| etw_uint32 | Integer | Non disponibile |
| etw_int64 | Integer | Il tipo deve essere 'int64_t' in modo esplicito perché per impostazione predefinita D è 'int32_t' |
| etw_uint64 | Integer | Il tipo deve essere 'int64_t' in modo esplicito perché per impostazione predefinita D è 'int32_t' |
| etw_float | Scalare | Le costanti a virgola mobile non sono consentite nello script D, ma lo consentono sui simboli caricati |
| etw_double | Scalare | Le costanti a virgola mobile non sono consentite nello script D, ma lo consentono sui simboli caricati |
| etw_bool32 | Integer | Non disponibile |
| etw_hexint32 | Integer | Non disponibile |
| etw_hexint64 | Integer | Il tipo deve essere 'int64_t' in modo esplicito perché per impostazione predefinita D è 'int32_t' |
| etw_countedmbcsstring | Integer | Non disponibile |
| etw_intptr | Integer | Le dimensioni del tipo di dati cambiano in base all'architettura ('int32_t' rispetto a 'int64_t') |
| etw_uintptr | Integer | Le dimensioni del tipo di dati cambiano in base all'architettura ('int32_t' rispetto a 'int64_t') |
| etw_pointer | Integer | Le dimensioni del tipo di dati cambiano in base all'architettura ('int32_t' rispetto a 'int64_t') |
| etw_char16 | Integer | È consigliabile che la dimensione del tipo corrisponda ed effettuare un cast a 'int16_t' nello script D |
| etw_char8 | Integer | È consigliabile che la dimensione del tipo di dato corrisponda e il cast a 'int8_t' nello script D |
| etw_bool8 | Integer | È consigliabile che la dimensione del tipo coincida e si raccomanda il cast a `int8_t` nello script D. |
| etw_hexint8 | Integer | È consigliabile che le dimensioni del tipo coincidano e che si effettui il cast a 'int8_t' nello script D. |
| etw_hexint16 | Integer | È consigliabile che le dimensioni del tipo di dato corrispondano e il cast a `int16_t` nello script D |
| etw_pid | Integer | Non disponibile |
| etw_tid | Integer | Non disponibile |
| etw_mbcsxml | Integer | Non disponibile |
| etw_mbcsjson | Integer | Non disponibile |
| etw_countedmbcsxml | Integer | Non disponibile |
| etw_countedmbcsjson | Integer | Non disponibile |
| etw_win32error | Integer | Non disponibile |
| etw_ntstatus | Integer | Non disponibile |
| etw_hresult | Integer | Non disponibile |
Vedere anche
Programmazione DTrace di Windows