Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Use o DTrace para Windows para processar eventos ETW existentes e adicionar novos eventos ETW.
O Rastreamento de Eventos para Windows (ETW) é um recurso de rastreamento no nível do kernel que permite registrar eventos definidos pelo kernel ou pelo aplicativo em um arquivo de log. Você pode consumir os eventos em tempo real ou a partir de um arquivo de log e usá-los para depurar um aplicativo ou para 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 é suportado nas builds do programa Insider do Windows após a versão 18980 e na build do Windows Server 18975.
Para obter informações gerais sobre como trabalhar com o DTrace no Windows, consulte DTrace.
Provedor DTrace do Windows ETW
Você pode usar o DTrace para capturar e relatar eventos ETW registrados por rastreamento e baseados em manifesto. Para investigar palavras-chave/níveis/eventIDs específicos, as sondas ETW funcionarão de forma muito mais confiável se você não usar curingas. Em vez disso, especifique completamente sua sonda com base nestas regras:
Nome da sonda = etw
Modname = guid do fornecedor no formato xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, usando todos os caracteres minúsculos.
Funcname = Level_Keyword da forma 0x00_0x0000000000000000. Para corresponder a tudo, isso deve ser definido como 0xff_0xffffffffffffffff.
Probename = ID de evento inteiro ou "generic_event" para corresponder a todas as IDs de evento.
A filtragem baseada em Probename só funciona para eventos manifestados. Utilize o curinga (*) para eventos registados.
A carga útil ETW é acessada via arg0. Este é composto por nt'_EVENT_HEADER seguido da data específica do evento.
Determinando provedores de ETW disponíveis
Use o comando logman para mostrar 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 produzir eventos ETW. Isso é útil para cenários em que há pipeline ETW existente para relatar, coletar e analisar.
Use este exemplo de comando DTrace para relatar eventos do provedor Microsoft-WindowsKernel-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
Os 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 suporta tipos de dados básicos como int8, uint8, int16, uint16, int32, uint32, int64, uint64, hexint32, hexint64 e string. Consulte a tabela Tipos de dados ETW suportados abaixo para obter mais detalhes.
Exemplo ETW_TRACE macro:
Esse script gera um evento ETW personalizado quando a rotina syscall retorna 0xc0000001 - STATUS_UNSUCCESSFUL.
Você pode alterar o this->status valor para usar valores NTSTATUS diferentes para registrar valores de retorno 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 ETW Microsoft-Windows-Kernel-Memory para despejar a memória do 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 Suporte NUMA.
Este 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++;
}
Salve o arquivo como etwnumamemstats.d
Abra um prompt de comando como administrador e execute o script usando a opção -s.
Executado num PC cliente Windows, é exibido um único nó 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
Tipos de dados ETW suportados
| Tipo ETW | D Tipo de dados de idioma | Observações |
|---|---|---|
| etw_struct | Número inteiro | O valor da carga útil deste tipo representa a contagem de membros que uma nova estrutura terá. |
| etw_string | cadeia (de caracteres) | N/A |
| etw_mbcsstring | cadeia (de caracteres) | N/A |
| etw_int8 | Número inteiro | O tamanho do tipo deve corresponder, e recomenda-se converter para `int8_t` no script D. |
| etw_uint8 | Número inteiro | O tamanho do tipo deve ser correspondente e é aconselhável converter para `uint8_t` no script D. |
| etw_int16 | Número inteiro | O tamanho do tipo deve corresponder e é aconselhável transmitir para 'int16_t' no script D |
| etw_uint16 | Número inteiro | O tamanho do tipo deve corresponder, e é aconselhável converter para `uint16_t` no script D. |
| etw_int32 | Número inteiro | N/A |
| etw_uint32 | Número inteiro | N/A |
| etw_int64 | Número inteiro | O tipo deve ser explicitamente 'int64_t', uma vez que D assume como padrão 'int32_t' |
| etw_uint64 | Número inteiro | O tipo deve ser explicitamente 'int64_t', uma vez que D assume 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/A |
| etw_hexint32 | Número inteiro | N/A |
| etw_hexint64 | Número inteiro | O tipo deve ser explicitamente 'int64_t', uma vez que D assume como padrão 'int32_t' |
| etw_countedmbcsstring | Número inteiro | N/A |
| etw_intptr | Número inteiro | O tamanho do tipo de dados muda de acordo com a arquitetura ('int32_t' vs 'int64_t') |
| etw_uintptr | Número inteiro | O tamanho do tipo de dados muda de acordo com a arquitetura ('int32_t' vs 'int64_t') |
| etw_pointer | Número inteiro | O tamanho do tipo de dados muda de acordo com a arquitetura ('int32_t' vs 'int64_t') |
| etw_char16 | Número inteiro | O tamanho do tipo deve corresponder, e é aconselhável converter para 'int16_t' no script em D |
| etw_char8 | Número inteiro | O tamanho do tipo deve corresponder e é aconselhável transmitir para 'int8_t' no script D |
| etw_bool8 | Número inteiro | O tamanho do tipo deve corresponder e é aconselhável converter para «int8_t» no script D. |
| etw_hexint8 | Número inteiro | O tamanho do tipo deve corresponder, e recomenda-se converter para `int8_t` no script D. |
| etw_hexint16 | Número inteiro | O tamanho do tipo deve corresponder, e é aconselhável converter para 'int16_t' no script D |
| etw_pid | Número inteiro | N/A |
| etw_tid | Número inteiro | N/A |
| etw_mbcsxml | Número inteiro | N/A |
| etw_mbcsjson | Número inteiro | N/A |
| etw_countedmbcsxml | Número inteiro | N/A |
| etw_countedmbcsjson | Número inteiro | N/A |
| etw_win32error | Número inteiro | N/A |
| etw_ntstatus | Número inteiro | N/A |
| etw_hresult | Número inteiro | N/A |
Ver também
Programação do DTrace para Windows