Googling e ack
-ing sono finiti! Ho una risposta.
In primo luogo, vorrei chiarire un po 'di più l'obiettivo della domanda: voglio distinguere chiaramente i processi indipendenti nel sistema e i relativi contatori delle prestazioni. Ad esempio, un core di un processore, un dispositivo uncore (appreso di recente), kernel o applicazione utente sul processore, un bus (= controller di bus), un disco rigido sono tutti processi indipendenti, non sono sincronizzati da un clock . E oggi probabilmente tutti hanno alcuni Process Monitoring Counter (PMC). Mi piacerebbe capire da quali processi provengono i contatori. (È anche utile per cercare su Google: il "fornitore" di una cosa lo zeri meglio.)
Inoltre, l'ingranaggio utilizzato per la ricerca: Ubuntu 14.04
, linux 3.13.0-103-generic
, processore Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz
(da /proc/cpuinfo
, ha 2 core fisici e 4 virtuale - la materia fisica qui).
Terminologia, cose che la domanda comporta
Da Intel:
il processore è un core
dispositivo (è 1 dispositivo / processo) e un sacco di uncore
dispositivi , core
è ciò che esegue il programma (orologio, ALU, registri ecc.), uncore
sono dispositivi messi su die, vicino al processore per velocità e bassa latenza (il vero motivo è "perché il produttore può farlo"); come ho capito è fondamentalmente il Northbridge, come sulla scheda madre del PC, oltre alle cache; e AMD in realtà chiama questi dispositivi NorthBridge instead of
uncore`;
ubox
che si presenta nel mio sysfs
$ find /sys/devices/ -type d -name events
/sys/devices/cpu/events
/sys/devices/uncore_cbox_0/events
/sys/devices/uncore_cbox_1/events
- è un uncore
dispositivo che gestisce Last Level Cache (LLC, l'ultimo prima di colpire la RAM); Ho 2 core, quindi 2 LLC e 2 ubox
;
Processor Monitoring Unit (PMU) è un dispositivo separato che monitora le operazioni di un processore e le registra in Processor Monitoring Counter (PMC) (conta i cache cache, i cicli del processore ecc.); esistono su core
e uncore
dispositivi; i core
quelli si accede con rdpmc
istruzioni (leggi PMC); la uncore
, dal momento che questi dispositivi dipendono effettiva del processore a portata di mano, sono accessibili tramite modello registri specifici (MSR) tramite rdmsr
(naturalmente);
apparentemente, il flusso di lavoro con essi viene eseguito tramite coppie di registri: 1 set di registri quali eventi contano il contatore, 2 registri è il valore nel contatore; il contatore può essere configurato per incrementare dopo un mucchio di eventi, non solo 1; + ci sono alcune interruzioni / tecnologia che notano overflow in questi contatori;
ne è possibile trovare di più nel capitolo 18 "MONITORAGGIO DELLE PRESTAZIONI" del "Manuale di sviluppo software IA-32 di Intel", capitolo 18;
inoltre, il formato del MSR concretamente per questi uncore
PMC per la versione "Architectural Performance Monitoring Version 1" (ci sono versioni 1-4 nel manuale, non so quale sia il mio processore) è descritto nella "Figura 18-1. di MSR IA32_PERFEVTSELx "(pagina 18-3 nella mia) e la sezione" 18.2.1.2 Eventi prestazionali architetturali predefiniti "con" Tabella 18-1. UMask ed Event Select Encodings for Pre-Defined Architectural Performance Events ", che mostra il eventi che si presentano come Hardware event
in perf list
.
Dal kernel di Linux:
il kernel ha un sistema (astrazione / layer) per la gestione di contatori delle prestazioni di diversa origine, sia software (kernel) che hardware, come descritto in linux-source-3.13.0/tools/perf/design.txt
; un evento in questo sistema è definito come struct perf_event_attr
(file linux-source-3.13.0/include/uapi/linux/perf_event.h
), la cui parte principale è probabilmente un __u64 config
campo - può contenere sia una definizione di evento specifica della CPU (la parola a 64 bit nel formato descritto su quelle figure di Intel) sia un evento del kernel
L'MSB della parola di configurazione indica se il resto contiene [evento della CPU o del kernel non elaborato]
l'evento del kernel definito con 7 bit per type e 56 per l'identificatore dell'evento, che sono enum
-s nel codice, che nel mio caso sono:
$ 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
è il mio alias di ack-grep
, che è il nome di ack
Debian; ed ack
è fantastico);
nel codice sorgente del kernel si possono vedere operazioni come "registra tutte le PMU rilevate sul sistema" e tipi di struttura struct pmu
, che vengono passati a qualcosa del genere int perf_pmu_register(struct pmu *pmu, const char *name, int type)
- quindi, si potrebbe semplicemente chiamare questo sistema "PMU del kernel", che sarebbe un'aggregazione di tutte le PMU sul sistema; ma questo nome potrebbe essere interpretato come sistema di monitoraggio delle operazioni del kernel, il che sarebbe fuorviante;
chiamiamo questo sottosistema perf_events
per chiarezza;
come qualsiasi sottosistema kernel, questo sottosistema può essere esportato in sysfs
(che è fatto per esportare sottosistemi kernel che le persone possono usare); ed è quello che sono quelle events
directory nel mio sottosistema /sys/
esportato (parti di?) perf_events
;
inoltre, l'utilità spazio utente perf
(integrata in Linux) è ancora un programma separato e ha le sue "astrazioni; rappresenta un evento richiesto per il monitoraggio da parte dell'utente come perf_evsel
(file linux-source-3.13.0/tools/perf/util/evsel.{h,c}
): questa struttura ha un campo struct perf_event_attr attr;
, ma anche un campo come struct cpu_map *cpus;
quello in cui l' perf
utilità assegna un evento a tutte o CPU particolari.
Risposta
In effetti, Hardware cache event
sono "scorciatoie" per gli eventi dei dispositivi cache ( ubox
dei dispositivi Intel uncore
), che sono specifici del processore e sono accessibili tramite il protocollo Raw hardware event descriptor
. E Hardware event
sono più stabili all'interno dell'architettura, che, a quanto ho capito, nomina gli eventi dal core
dispositivo. Non ci sono altre "scorciatoie" nel mio kernel 3.13
per altri uncore
eventi e contatori. Tutto il resto - Software
e Tracepoints
- sono eventi del kernel.
Mi chiedo se il core
's Hardware event
s sono accessibili tramite lo stesso Raw hardware event descriptor
protocollo. Potrebbero non farlo - dal momento che il contatore / PMU si trova su core
, forse si accede in modo diverso. Ad esempio, con rdpmu
quell'istruzione, invece di rdmsr
, a cui accede uncore
. Ma non è così importante.
Kernel PMU event
sono solo gli eventi in cui vengono esportati sysfs
. Non so come sia fatto (automaticamente dal kernel tutti i PMC rilevati sul sistema, o solo qualcosa di hard-coded, e se aggiungo un kprobe
- viene esportato? Ecc.). Ma il punto principale è che questi sono gli stessi eventi di Hardware event
qualsiasi altro perf_event
sistema interno .
E non so cosa siano quelli
$ ls /sys/devices/uncore_cbox_0/events
clockticks
siamo.
Dettagli su Kernel PMU event
La ricerca attraverso il codice porta 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]);
- che succede nella funzione
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]); ... }
}
ed perf_pmu__scan
è nello stesso file:
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) {
...
pmu_read_sysfs(); // that's what it calls
}
- che è anche nello stesso file:
/* Add all pmus in sysfs to pmu list: */
static void pmu_read_sysfs(void) {...}
Questo è tutto.
Dettagli su Hardware event
eHardware cache event
Apparentemente, Hardware event
deriva da ciò che Intel chiama "Eventi prestazionali architetturali predefiniti", 18.2.1.2 nel Manuale per gli sviluppatori di software IA-32 Vol 3B. E "18.1 PANORAMICA SUL MONITORAGGIO DELLE PRESTAZIONI" del manuale li descrive come:
La seconda classe di funzionalità di monitoraggio delle prestazioni viene definita monitoraggio delle prestazioni dell'architettura. Questa classe supporta gli stessi utilizzi di conteggio e campionamento di eventi basati su interrupt, con una serie ridotta di eventi disponibili. Il comportamento visibile degli eventi di prestazione architettonica è coerente tra le implementazioni del processore. La disponibilità delle capacità di monitoraggio delle prestazioni architettoniche viene enumerata utilizzando CPUID.0AH. Questi eventi sono discussi nella Sezione 18.2.
- l'altro tipo è:
A partire dai processori Intel Core Solo e Intel Core Duo, esistono due classi di capacità di monitoraggio delle prestazioni. La prima classe supporta eventi per il monitoraggio delle prestazioni utilizzando il conteggio o l'utilizzo del campionamento di eventi basato su interrupt. Questi eventi non sono architetturali e variano da un modello di processore a un altro ...
E questi eventi sono in effetti solo collegamenti ad eventi hardware "grezzi" sottostanti, a cui è possibile accedere tramite l' perf
utilità Raw hardware event descriptor
.
Per controllare questo guarda 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 0x412e
si trova esattamente nella "Tabella 18-1. Codifiche UMask ed Event Select per eventi prestazionali architetturali predefiniti" per "Misses LLC":
Bit Position CPUID.AH.EBX | Event Name | UMask | Event Select
...
4 | LLC Misses | 41H | 2EH
- H
è per esadecimale. Tutti e 7 sono nella struttura, oltre [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding *
. (La denominazione è un po 'diversa, gli indirizzi sono gli stessi.)
Quindi le Hardware cache event
s sono in strutture come (nello stesso file):
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] =
{...}
- quale dovrebbe essere per il ponte sabbioso?
Uno di questi - snb_hw_cache_extra_regs[LL][OP_WRITE][RESULT_ACCESS]
è pieno SNB_DMND_WRITE|SNB_L3_ACCESS
, dove dai def-s sopra:
#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)
che dovrebbe essere uguale a 0x00010102
, ma non so come controllarlo con qualche tabella.
E questo dà un'idea di come viene utilizzato in 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));
$
Gli memcpy
s sono finiti __init int intel_pmu_init(void) {... case:...}
.
Solo attr->config1
è un po 'strano. Ma è lì, in perf_event_attr
(stesso linux-source-3.13.0/include/uapi/linux/perf_event.h
file):
...
union {
__u64 bp_addr;
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
__u64 config2; /* extension of config1 */
};
...
Sono registrati nel perf_events
sistema del kernel con chiamate a int perf_pmu_register(struct pmu *pmu, const char *name, int type)
(definito in linux-source-3.13.0/kernel/events/core.c:
):
static int __init init_hw_perf_events(void)
(file arch/x86/kernel/cpu/perf_event.c
) con chiamataperf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
(file arch/x86/kernel/cpu/perf_event_intel_uncore.c
, ci sono anche arch/x86/kernel/cpu/perf_event_amd_uncore.c
) con chiamataret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
Quindi, alla fine, tutti gli eventi provengono dall'hardware e tutto è ok. Ma qui si può notare: perché abbiamo LLC-loads
in perf list
e non ubox1 LLC-loads
, dal momento che si tratta di eventi HW e actualy proveniamo ubox
es?
Questo è un aspetto perf
dell'utilità e della sua ' perf_evsel
struttura: quando richiedi un evento HW da perf
te definisci l'evento da cui processori lo desideri (il default è tutto), e imposta perf_evsel
l'evento con i processori e l'evento richiesti, quindi all'aggregazione è somma i contatori di tutti i processori perf_evsel
(o fa alcune altre statistiche con loro).
Lo si può vedere in 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;
}
(Quindi, per l'utilità perf
un "contatore singolo" non è nemmeno un perf_event_attr
, che è una forma generale, adatta sia agli eventi SW che HW, è un evento della tua query - gli stessi eventi possono provenire da dispositivi diversi e sono aggregati .)
Anche un avviso: struct perf_evsel
contiene solo 1 struct perf_evevent_attr
, ma ha anche un campo struct perf_evsel *leader;
- è nidificato. Esiste una funzione di "gruppi di eventi (gerarchici)" perf_events
, quando è possibile inviare un gruppo di contatori insieme, in modo che possano essere confrontati tra loro e così via. Non so come funziona con eventi indipendenti da kernel
, core
, ubox
. Ma questa nidificazione perf_evsel
è. E, molto probabilmente, è così che perf
gestisce insieme una query di più eventi.