Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Use o DTrace para Windows para processar eventos ETW existentes e adicionar novos eventos ETW.
O ETW (Rastreamento de Eventos para Windows) é um recurso de rastreamento no nível do kernel que permite registrar eventos definidos por kernel ou aplicativo em um arquivo de log. Você pode consumir os eventos em tempo real ou em um arquivo de log e usá-los para depurar um aplicativo ou determinar onde os problemas de desempenho estão ocorrendo no aplicativo. Para obter informações gerais sobre o ETW, consulte Sobre o Rastreamento de Eventos.
Observação
O DTrace tem suporte nos builds do Insider do Windows após a versão 18980 e o Windows Server Build 18975.
Para obter informações gerais sobre como trabalhar com o DTrace no Windows, consulte DTrace.
Provedor de DTrace do Windows ETW
Você pode usar o DTrace para capturar e relatar eventos ETW registrados e baseados em manifesto. Para sondar palavras-chave/níveis/eventIDs específicos, as sondagens ETW funcionarão de forma muito mais confiável se você não usar curingas. Em vez disso, especifique totalmente sua investigação com base nessas regras:
Probename = etw
Modname = GUID do provedor no formato xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, usando todos os caracteres minúsculos.
Funcname = Level_Keyword no formato 0x00_0x0000000000000000. Para corresponder a tudo, este valor deve ser ajustado para 0xff_0xffffffffffffffff.
Probename = ID de evento inteiro ou "generic_event" para corresponder a todas as IDs de evento.
A filtragem com base em Probename só funciona para eventos manifestos. Utilize coringa (*) para eventos rastreados.
O payload do ETW é acessado por meio do arg0. Isso é composto por nt'_EVENT_HEADER seguido pela data específica do evento.
Determinando provedores ETW disponíveis
Use o comando logman para exibir provedores ETW ativos e seus GUIDs de provedor.
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}
...
Exibindo informações existentes do provedor ETW
O DTrace tem a capacidade de gerar eventos ETW. Isso é útil para cenários em que existe um pipeline ETW para relatar, coletar e analisar.
Use este exemplo de comando DTrace para reportar eventos do provedor 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
Adicionando novos eventos ETW
Eventos de rastreamento etw podem ser criados chamando a macro etw_trace. Os eventos só serão registrados se houver um ouvinte ativo para o provedor de rastreamento especificado, caso contrário, eles serão ignorados.
A macro etw_trace dá suporte a tipos de dados básicos como int8, uint8, int16, uint16, int32, uint32, int64, uint64, hexint32, hexint64 e string. Consulte a tabela de tipos de dados ETW com suporte abaixo para obter mais detalhes.
Exemplo ETW_TRACE macro:
Este script gera um evento ETW personalizado quando a rotina de chamada de sistema retorna 0xc0000001 – STATUS_UNSUCCESSFUL.
Você pode alterar o this->status valor para usar valores NTSTATUS diferentes para registrar valores de retorno de syscall diferentes.
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
Código de exemplo ETW NUMA MEM STATS
Este script de exemplo usa o provedor ETWKernel-Memory Microsoft-Windows para despejar memória de nó NUMA. O tamanho da página pode ser convertido em tamanho em KB multiplicando por 4. Para obter informações gerais sobre NUMA, consulte o suporte a NUMA.
Esse código também está localizado em 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++;
}
Salvar o arquivo como etwnumamemstats.d
Abra um prompt de comando como Administrador e execute o script usando a opção -s.
Quando executado em um PC com Windows no modo cliente, um único nó NUMA é exibido.
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
Tipos de dados ETW com suporte
| Tipo de ETW | Tipo de dado da linguagem D | Observações |
|---|---|---|
| etw_struct | Número Inteiro | O valor da carga útil desse tipo representa a contagem de membros que uma nova estrutura terá. |
| etw_string | cadeia | Não aplicável |
| etw_mbcsstring | cadeia | Não aplicável |
| etw_int8 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int8_t' no script D é aconselhada |
| etw_uint8 | Número Inteiro | O tamanho do tipo deve ser compatível, e a conversão para 'uint8_t' no script D é aconselhável. |
| etw_int16 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int16_t' no script D é aconselhada |
| etw_uint16 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'uint16_t' no script D é aconselhável |
| etw_int32 | Número Inteiro | Não aplicável |
| etw_uint32 | Número Inteiro | Não aplicável |
| etw_int64 | Número Inteiro | O tipo deve ser explicitamente 'int64_t', pois D usa como padrão 'int32_t' |
| etw_uint64 | Número Inteiro | O tipo deve ser explicitamente 'int64_t', pois D usa como padrão 'int32_t' |
| etw_float | Escalar | Constantes de ponto flutuante não são permitidas no script D, mas permitem isso em símbolos carregados |
| etw_double | Escalar | Constantes de ponto flutuante não são permitidas no script D, mas permitem isso em símbolos carregados |
| etw_bool32 | Número Inteiro | Não aplicável |
| etw_hexint32 | Número Inteiro | Não aplicável |
| etw_hexint64 | Número Inteiro | O tipo deve ser explicitamente 'int64_t', pois D usa como padrão 'int32_t' |
| etw_countedmbcsstring | Número Inteiro | Não aplicável |
| etw_intptr | Número Inteiro | O tamanho do tipo de dados é alterado de acordo com a arquitetura ('int32_t' versus 'int64_t') |
| etw_uintptr | Número Inteiro | O tamanho do tipo de dados é alterado de acordo com a arquitetura ('int32_t' versus 'int64_t') |
| etw_pointer | Número Inteiro | O tamanho do tipo de dados é alterado de acordo com a arquitetura ('int32_t' versus 'int64_t') |
| etw_char16 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int16_t' no script D é aconselhada |
| etw_char8 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int8_t' no script D é aconselhada |
| etw_bool8 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int8_t' no script D é aconselhada |
| etw_hexint8 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int8_t' no script D é aconselhada |
| etw_hexint16 | Número Inteiro | O tamanho do tipo deve corresponder e a conversão para 'int16_t' no script D é aconselhada |
| etw_pid | Número Inteiro | Não aplicável |
| etw_tid | Número Inteiro | Não aplicável |
| etw_mbcsxml | Número Inteiro | Não aplicável |
| etw_mbcsjson | Número Inteiro | Não aplicável |
| etw_countedmbcsxml | Número Inteiro | Não aplicável |
| etw_countedmbcsjson | Número Inteiro | Não aplicável |
| etw_win32error | Número Inteiro | Não aplicável |
| etw_ntstatus | Número Inteiro | Não aplicável |
| etw_hresult | Número Inteiro | Não aplicável |