Googling and ack
-ing acabou! Eu tenho uma resposta.
Mas, primeiro, deixe-me esclarecer um pouco mais o objetivo da pergunta: quero distinguir claramente processos independentes no sistema e seus contadores de desempenho. Por exemplo, um núcleo de um processador, um dispositivo não essencial (aprendido sobre isso recentemente), um kernel ou aplicativo de usuário no processador, um barramento (= controlador de barramento), um disco rígido são todos processos independentes, não são sincronizados por um relógio . E hoje em dia provavelmente todos eles têm algum PMC (Process Monitoring Counter). Eu gostaria de entender de quais processos vêm os contadores. (Também é útil no Google: o "vendedor" de uma coisa zera melhor.)
Além disso, o equipamento utilizado para a pesquisa: Ubuntu 14.04
, linux 3.13.0-103-generic
, processador Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz
(a partir /proc/cpuinfo
, tem 2 núcleos físicos e 4 Virtual - a matéria física aqui).
Terminologia, coisas que a pergunta envolve
Da Intel:
processador é um core
dispositivo (é 1 dispositivo / processo) e um monte de uncore
dispositivos , core
é o que executa o programa (relógio, ALU, registros etc.), uncore
são dispositivos colocados no molde, próximos ao processador para velocidade e baixa latência (a verdadeira razão é "porque o fabricante pode fazer isso"); como eu entendi, é basicamente o Northbridge, como na placa-mãe do PC, além de caches; e a AMD realmente chama esses dispositivos de NorthBridge instead of
uncore`;
ubox
que aparece na minha sysfs
$ find /sys/devices/ -type d -name events
/sys/devices/cpu/events
/sys/devices/uncore_cbox_0/events
/sys/devices/uncore_cbox_1/events
- é um uncore
dispositivo que gerencia o cache de último nível (LLC, o último antes de atingir a RAM); Eu tenho 2 núcleos, portanto 2 LLC e 2 ubox
;
A Unidade de Monitoramento do Processador (PMU) é um dispositivo separado que monitora as operações de um processador e as registra no Contador de Monitoramento do Processador (PMC) (conta falhas de cache, ciclos do processador etc.); eles existem em core
e uncore
dispositivos; os core
ones são acessados com rdpmc
instrução (leia PMC); o uncore
, uma vez que esses dispositivos dependem do processador atual disponível, são acessados via MSR (Model Specific Registers) via rdmsr
(naturalmente);
aparentemente, o fluxo de trabalho com eles é feito por meio de pares de registradores - 1 registrador define quais eventos o contador conta; 2 registrador é o valor no contador; o contador pode ser configurado para incrementar após vários eventos, não apenas 1; + existem algumas interrupções / aviso de transbordamento nesses contadores;
mais pode-se encontrar no "Manual do desenvolvedor de software IA-32, Vol 3B", capítulo 18 "MONITORAMENTO DE DESEMPENHO";
além disso, o formato do MSR concretamente para esses uncore
PMCs para a versão "Architectural Performance Monitoring Version 1" (há versões 1-4 no manual, não sei qual é o meu processador) está descrito na "Figura 18-1. Layout dos MSRs IA32_PERFEVTSELx "(página 18-3 na mina) e na seção" 18.2.1.2 Eventos de desempenho arquitetônicos predefinidos "com" Tabela 18-1. eventos que aparecem como Hardware event
em perf list
.
Do kernel do linux:
O kernel possui um sistema (abstração / camada) para gerenciar contadores de desempenho de diferentes origens, tanto de software (do kernel) quanto de hardware, descrito em linux-source-3.13.0/tools/perf/design.txt
; um evento neste sistema é definido como struct perf_event_attr
(arquivo linux-source-3.13.0/include/uapi/linux/perf_event.h
), cuja parte principal é provavelmente o __u64 config
campo - ele pode conter uma definição de evento específica da CPU (a palavra de 64 bits no formato descrito nas figuras da Intel) ou um evento do kernel
O MSB da palavra de configuração significa se o restante contém [evento bruto da CPU ou do kernel]
o evento do kernel definido com 7 bits para o tipo e 56 para o identificador do evento, que são enum
-s no código e, no meu caso, são:
$ ak PERF_TYPE linux-source-3.13.0/include/
...
linux-source-3.13.0/include/uapi/linux/perf_event.h
29: PERF_TYPE_HARDWARE = 0,
30: PERF_TYPE_SOFTWARE = 1,
31: PERF_TYPE_TRACEPOINT = 2,
32: PERF_TYPE_HW_CACHE = 3,
33: PERF_TYPE_RAW = 4,
34: PERF_TYPE_BREAKPOINT = 5,
36: PERF_TYPE_MAX, /* non-ABI */
( ak
é meu apelido para ack-grep
, que é o nome ack
do Debian; e ack
é incrível);
no código fonte do kernel pode-se ver operações como "registrar todas as PMUs descobertas no sistema" e tipos de estrutura struct pmu
, que são passados para algo como int perf_pmu_register(struct pmu *pmu, const char *name, int type)
- assim, pode-se chamar esse sistema de "PMU do kernel", que seria uma agregação de todas as PMUs no sistema; mas esse nome poderia ser interpretado como sistema de monitoramento das operações do kernel, o que seria enganoso;
vamos chamar esse subsistema perf_events
para maior clareza;
como qualquer subsistema de kernel, esse subsistema pode ser exportado para sysfs
(que é feito para exportar subsistemas de kernel para uso das pessoas); e é isso que são esses events
diretórios no meu /sys/
- o perf_events
subsistema exportado (partes de?) ;
Além disso, o utilitário de espaço do usuário perf
(incorporado ao linux) ainda é um programa separado e possui suas próprias abstrações; ele representa um evento solicitado para monitoramento pelo usuário como perf_evsel
(arquivos linux-source-3.13.0/tools/perf/util/evsel.{h,c}
) - essa estrutura tem um campo struct perf_event_attr attr;
, mas também um campo como struct cpu_map *cpus;
o perf
utilitário atribui um evento a todas as CPUs ou a determinadas unidades.
Responda
De fato, Hardware cache event
são "atalhos" para os eventos dos dispositivos de cache ( ubox
dos dispositivos da Intel uncore
), que são específicos do processador e podem ser acessados através do protocolo Raw hardware event descriptor
. E Hardware event
são mais estáveis na arquitetura, que, pelo que entendi, nomeiam os eventos do core
dispositivo. Não há outros "atalhos" no meu kernel 3.13
para alguns outros uncore
eventos e contadores. Todo o resto - Software
e Tracepoints
- são eventos do kernel.
Pergunto-me se o core
's Hardware event
s são acessados através do mesmo Raw hardware event descriptor
protocolo. Eles podem não funcionar - já que o contador / PMU fica aceso core
, talvez ele seja acessado de maneira diferente. Por exemplo, com essa rdpmu
instrução, em vez de rdmsr
, que acessa uncore
. Mas isso não é importante.
Kernel PMU event
são apenas os eventos que são exportados para sysfs
. Não sei como isso é feito (automaticamente pelo kernel todos os PMCs descobertos no sistema, ou apenas algo codificado, e se eu adicionar um kprobe
- ele é exportado? Etc). Mas o ponto principal é que esses são os mesmos eventos Hardware event
do perf_event
sistema interno .
E eu não sei o que aqueles
$ ls /sys/devices/uncore_cbox_0/events
clockticks
estamos.
Detalhes sobre Kernel PMU event
A pesquisa no código leva a:
$ ak "Kernel PMU" linux-source-3.13.0/tools/perf/
linux-source-3.13.0/tools/perf/util/pmu.c
629: printf(" %-50s [Kernel PMU event]\n", aliases[j]);
- o que acontece na função
void print_pmu_events(const char *event_glob, bool name_only) {
...
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, &pmu->aliases, list) {...}
...
/* b.t.w. list_for_each_entry is an iterator
* apparently, it takes a block of {code} and runs over some lost
* Ruby built in kernel!
*/
// then there is a loop over these aliases and
loop{ ... printf(" %-50s [Kernel PMU event]\n", aliases[j]); ... }
}
e perf_pmu__scan
está no mesmo arquivo:
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) {
...
pmu_read_sysfs(); // that's what it calls
}
- que também está no mesmo arquivo:
/* Add all pmus in sysfs to pmu list: */
static void pmu_read_sysfs(void) {...}
É isso aí.
Detalhes sobre Hardware event
eHardware cache event
Aparentemente, o Hardware event
resultado é o que a Intel chama de "Eventos de desempenho arquitetônico predefinidos", 18.2.1.2 no Manual do desenvolvedor de software IA-32, Vol 3B. E "18.1 VISÃO GERAL DO MONITORAMENTO DE DESEMPENHO" do manual descreve-os como:
A segunda classe de recursos de monitoramento de desempenho é chamada de monitoramento de desempenho arquitetural. Esta classe suporta os mesmos usos de amostragem de eventos baseados em contagem e interrupção, com um conjunto menor de eventos disponíveis. O comportamento visível dos eventos de desempenho arquitetural é consistente nas implementações do processador. A disponibilidade dos recursos de monitoramento de desempenho arquitetural é enumerada usando o CPUID.0AH. Esses eventos são discutidos na Seção 18.2.
- o outro tipo é:
Começando pelos processadores Intel Core Solo e Intel Core Duo, existem duas classes de capacidade de monitoramento de desempenho. A primeira classe suporta eventos para monitorar o desempenho usando o uso de amostragem de eventos baseada em contagem ou interrupção. Esses eventos não são arquitetônicos e variam de um modelo de processador para outro ...
E esses eventos são de fato apenas links para eventos de hardware "brutos" subjacentes, que podem ser acessados via perf
utilitário como Raw hardware event descriptor
.
Para verificar isso, veja linux-source-3.13.0/arch/x86/kernel/cpu/perf_event_intel.c
:
/*
* Intel PerfMon, used on Core and later.
*/
static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
{
[PERF_COUNT_HW_CPU_CYCLES] = 0x003c,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x4f2e,
[PERF_COUNT_HW_CACHE_MISSES] = 0x412e,
...
}
- e exatamente 0x412e
é encontrado em "Tabela 18-1. Codificações de UMask e de seleção de eventos para eventos de desempenho arquitetônico predefinidos" para "LLC Misses":
Bit Position CPUID.AH.EBX | Event Name | UMask | Event Select
...
4 | LLC Misses | 41H | 2EH
- H
é para hexadecimal. Todos os 7 estão na estrutura, mais [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding *
. (A nomeação é um pouco diferente, os endereços são os mesmos.)
Então, os Hardware cache event
s estão em estruturas como (no mesmo arquivo):
static __initconst const u64 snb_hw_cache_extra_regs
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
{...}
- qual deve ser a ponte de areia?
Um deles - snb_hw_cache_extra_regs[LL][OP_WRITE][RESULT_ACCESS]
é preenchido com SNB_DMND_WRITE|SNB_L3_ACCESS
, de onde, nas def-s acima:
#define SNB_L3_ACCESS SNB_RESP_ANY
#define SNB_RESP_ANY (1ULL << 16)
#define SNB_DMND_WRITE (SNB_DMND_RFO|SNB_LLC_RFO)
#define SNB_DMND_RFO (1ULL << 1)
#define SNB_LLC_RFO (1ULL << 8)
que deve ser igual a 0x00010102
, mas não sei como verificar com alguma tabela.
E isso dá uma idéia de como é usado perf_events
:
$ ak hw_cache_extra_regs linux-source-3.13.0/arch/x86/kernel/cpu/
linux-source-3.13.0/arch/x86/kernel/cpu/perf_event.c
50:u64 __read_mostly hw_cache_extra_regs
292: attr->config1 = hw_cache_extra_regs[cache_type][cache_op][cache_result];
linux-source-3.13.0/arch/x86/kernel/cpu/perf_event.h
521:extern u64 __read_mostly hw_cache_extra_regs
linux-source-3.13.0/arch/x86/kernel/cpu/perf_event_intel.c
272:static __initconst const u64 snb_hw_cache_extra_regs
567:static __initconst const u64 nehalem_hw_cache_extra_regs
915:static __initconst const u64 slm_hw_cache_extra_regs
2364: memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
2365: sizeof(hw_cache_extra_regs));
2407: memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
2408: sizeof(hw_cache_extra_regs));
2424: memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
2425: sizeof(hw_cache_extra_regs));
2452: memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
2453: sizeof(hw_cache_extra_regs));
2483: memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
2484: sizeof(hw_cache_extra_regs));
2516: memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
$
Os memcpy
s são feitas em __init int intel_pmu_init(void) {... case:...}
.
Só attr->config1
é um pouco estranho. Mas está lá, no perf_event_attr
mesmo linux-source-3.13.0/include/uapi/linux/perf_event.h
arquivo:
...
union {
__u64 bp_addr;
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
__u64 config2; /* extension of config1 */
};
...
Eles são registrados no perf_events
sistema do kernel com chamadas para int perf_pmu_register(struct pmu *pmu, const char *name, int type)
(definidas em linux-source-3.13.0/kernel/events/core.c:
):
static int __init init_hw_perf_events(void)
(arquivo arch/x86/kernel/cpu/perf_event.c
) com chamadaperf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
(arquivo arch/x86/kernel/cpu/perf_event_intel_uncore.c
, também existem arch/x86/kernel/cpu/perf_event_amd_uncore.c
) com chamadaret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
Então, finalmente, todos os eventos vêm de hardware e está tudo bem. Mas aqui pode-se notar: por que temos LLC-loads
em perf list
e não ubox1 LLC-loads
, uma vez que estes são eventos de HW e eles actualy vêm de ubox
es?
Isso é coisa do perf
utilitário e de sua perf_evsel
estrutura: quando você solicita um evento HW, perf
define o evento de que processadores você deseja (o padrão é tudo) e configura perf_evsel
o evento e os processadores solicitados; em seguida, a agregação é soma os contadores de todos os processadores perf_evsel
(ou faz outras estatísticas com eles).
Pode-se ver em tools/perf/builtin-stat.c
:
/*
* Read out the results of a single counter:
* aggregate counts across CPUs in system-wide mode
*/
static int read_counter_aggr(struct perf_evsel *counter)
{
struct perf_stat *ps = counter->priv;
u64 *count = counter->counts->aggr.values;
int i;
if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
thread_map__nr(evsel_list->threads), scale) < 0)
return -1;
for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);
if (verbose) {
fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
perf_evsel__name(counter), count[0], count[1], count[2]);
}
/*
* Save the full runtime - to allow normalization during printout:
*/
update_shadow_stats(counter, count);
return 0;
}
(Portanto, para o utilitário, perf
um "contador único" não é nem um perf_event_attr
, que é uma forma geral, ajustando eventos SW e HW, é um evento da sua consulta - os mesmos eventos podem vir de dispositivos diferentes e são agregados .)
Também um aviso: struct perf_evsel
contém apenas 1 struct perf_evevent_attr
, mas também possui um campo struct perf_evsel *leader;
- está aninhado. Há um recurso de "grupos (hierárquicos) de eventos" em perf_events
, quando você pode despachar vários contadores juntos, para que eles possam ser comparados entre si e assim por diante. Não tenho certeza como ele trabalha com eventos independentes de kernel
, core
, ubox
. Mas esse aninhamento perf_evsel
é isso. E, provavelmente, é assim que perf
gerencia uma consulta de vários eventos juntos.