Googler et ack
-ing est terminé! J'ai une réponse.
Mais permettez-moi tout d'abord de clarifier un peu plus le but de la question: je veux distinguer clairement les processus indépendants du système et leurs compteurs de performance. Par exemple, un noyau d'un processeur, un périphérique non-core (appris récemment), un noyau ou une application utilisateur sur le processeur, un bus (= contrôleur de bus), un disque dur sont tous des processus indépendants, ils ne sont pas synchronisés par une horloge . Et de nos jours, tous ont probablement un compteur de surveillance de processus (PMC). J'aimerais comprendre de quels processus proviennent les compteurs. (Il est également utile pour la recherche sur Google: le "vendeur" d'une chose la met à zéro.)
En outre, le matériel utilisé pour la recherche: Ubuntu 14.04
, linux 3.13.0-103-generic
, processeur Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz
( à partir /proc/cpuinfo
, il dispose de 2 noyaux physiques et 4 virtuelles - la matière physique ici).
Terminologie, ce que la question implique
D'Intel:
le processeur est un core
appareil (c'est 1 appareil / processus) et un tas d' uncore
appareils , core
c'est ce qui exécute le programme (horloge, ALU, registres, etc.), uncore
sont des appareils mis sous tension, proches du processeur pour la vitesse et une faible latence (la vraie raison est "parce que le fabricant peut le faire"); si j'ai bien compris, c'est essentiellement le Northbridge, comme sur la carte mère du PC, plus les caches; et AMD appelle en fait ces appareils NorthBridge instead of
uncore`;
ubox
qui apparaît dans mon sysfs
$ find /sys/devices/ -type d -name events
/sys/devices/cpu/events
/sys/devices/uncore_cbox_0/events
/sys/devices/uncore_cbox_1/events
- est un uncore
appareil qui gère Last Level Cache (LLC, le dernier avant de toucher la RAM); J'ai 2 cœurs, donc 2 LLC et 2 ubox
;
L'unité de surveillance du processeur (PMU) est un appareil séparé qui surveille les opérations d'un processeur et les enregistre dans le compteur de surveillance du processeur (PMC) (compte les échecs de cache, les cycles du processeur, etc.); ils existent sur core
et les uncore
appareils; les core
celles sont accessibles avec rdpmc
(lecture PMC) instruction; les uncore
, puisque ces dispositifs dépendent du processeur réel à portée de main, sont accessibles via des registres spécifiques au modèle (MSR) via rdmsr
(naturellement);
apparemment, le flux de travail avec eux se fait via des paires de registres - 1 jeux de registres qui événements le compteur compte, 2 registre est la valeur dans le compteur; le compteur peut être configuré pour incrémenter après un tas d'événements, pas seulement 1; + il y a des interruptions / technologies remarquant des débordements dans ces compteurs;
on en trouvera plus dans le chapitre 18 du manuel "IA-32 Software Developer's Manual Vol 3B" "SURVEILLANCE DES PERFORMANCES";
aussi, le format du MSR concrètement pour ces uncore
PMC pour la version "Architectural Performance Monitoring Version 1" (il y a les versions 1-4 dans le manuel, je ne sais pas laquelle est mon processeur) est décrit dans "Figure 18-1. Disposition de IA32_PERFEVTSELx MSR "(page 18-3 dans la mienne), et la section" 18.2.1.2 Événements de performances architecturales prédéfinies "avec" Tableau 18-1. Codages UMask et Event Select pour les événements de performances architecturales prédéfinis ", qui montre la les événements qui apparaissent comme Hardware event
dans perf list
.
Depuis le noyau Linux:
le noyau a un système (abstraction / couche) pour gérer les compteurs de performance d'origine différente, à la fois logiciel (noyau) et matériel, il est décrit dans linux-source-3.13.0/tools/perf/design.txt
; un événement dans ce système est défini comme struct perf_event_attr
(fichier linux-source-3.13.0/include/uapi/linux/perf_event.h
), dont la partie principale est probablement un __u64 config
champ - il peut contenir à la fois une définition d'événement spécifique au processeur (le mot 64 bits au format décrit sur les figures d'Intel) ou un événement du noyau
Le MSB du mot de configuration signifie si le reste contient [l'événement CPU ou noyau brut]
l'événement du noyau défini avec 7 bits pour le type et 56 pour l'identifiant de l'événement, qui sont enum
-s dans le code, qui dans mon cas sont:
$ 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
est mon alias ack-grep
, qui est le nom de ack
sur Debian; et ack
est génial);
dans le code source du noyau, on peut voir des opérations comme "enregistrer tous les PMU découverts sur le système" et les types de structure struct pmu
, qui sont passés à quelque chose comme int perf_pmu_register(struct pmu *pmu, const char *name, int type)
- ainsi, on pourrait simplement appeler ce système "PMU du noyau", qui serait une agrégation de toutes les UGP du système; mais ce nom pourrait être interprété comme un système de surveillance des opérations du noyau, ce qui serait trompeur;
appelons ce sous-système perf_events
pour plus de clarté;
comme tout sous-système de noyau, ce sous-système peut être exporté vers sysfs
(qui est conçu pour exporter des sous-systèmes de noyau pour que les gens les utilisent); et c'est ce que sont ces events
répertoires dans mon /sys/
- le sous-système exporté (parties de?) perf_events
;
en outre, l'utilitaire d'espace utilisateur perf
(intégré à Linux) est toujours un programme distinct et possède ses propres abstractions; il représente un événement demandé pour la surveillance par l'utilisateur en tant que perf_evsel
(fichiers linux-source-3.13.0/tools/perf/util/evsel.{h,c}
) - cette structure a un champ struct perf_event_attr attr;
, mais aussi un champ comme struct cpu_map *cpus;
c'est ainsi que l' perf
utilitaire attribue un événement à tous les CPU ou à certains CPU.
Réponse
En effet, Hardware cache event
sont des "raccourcis" vers les événements des périphériques de cache ( ubox
des périphériques d'Intel uncore
), qui sont spécifiques au processeur, et sont accessibles via le protocole Raw hardware event descriptor
. Et Hardware event
sont plus stables au sein de l'architecture, qui, si je comprends bien, nomme les événements de l' core
appareil. Il n'y a pas d'autres "raccourcis" dans mon noyau 3.13
vers d'autres uncore
événements et compteurs. Tous les autres - Software
et Tracepoints
- sont des événements du noyau.
Je me demande si le core
de » Hardware event
de s sont accessibles via le même Raw hardware event descriptor
protocole. Ils pourraient ne pas - puisque le compteur / PMU est assis core
, il est peut-être accessible différemment. Par exemple, avec cette rdpmu
instruction, au lieu de rdmsr
, qui accède uncore
. Mais ce n'est pas si important.
Kernel PMU event
ne sont que les événements, qui sont exportés dans sysfs
. Je ne sais pas comment cela se fait (automatiquement par le noyau tous les PMC découverts sur le système, ou simplement quelque chose de codé en dur, et si j'ajoute un kprobe
- est-il exporté? Etc.). Mais l'essentiel est qu'il s'agit des mêmes événements que Hardware event
tout autre événement du perf_event
système interne .
Et je ne sais pas ce que ces
$ ls /sys/devices/uncore_cbox_0/events
clockticks
sont.
Détails sur Kernel PMU event
La recherche dans le code conduit à:
$ 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]);
- ce qui se passe dans la fonction
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]); ... }
}
et se perf_pmu__scan
trouve dans le même fichier:
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) {
...
pmu_read_sysfs(); // that's what it calls
}
- qui se trouve également dans le même fichier:
/* Add all pmus in sysfs to pmu list: */
static void pmu_read_sysfs(void) {...}
C'est ça.
Détails sur Hardware event
etHardware cache event
Apparemment, cela Hardware event
vient de ce qu'Intel appelle "Evénements de performances architecturales prédéfinies", 18.2.1.2 dans le Manuel du développeur du logiciel IA-32 Vol 3B. Et "18.1 APERÇU DE LA SURVEILLANCE DES PERFORMANCES" du manuel les décrit comme:
La deuxième classe de capacités de surveillance des performances est appelée surveillance des performances architecturales. Cette classe prend en charge les mêmes utilisations d'échantillonnage d'événements de comptage et d'interruption, avec un plus petit ensemble d'événements disponibles. Le comportement visible des événements de performances architecturales est cohérent dans toutes les implémentations de processeur. La disponibilité des capacités de surveillance des performances architecturales est énumérée à l'aide du CPUID.0AH. Ces événements sont traités dans la section 18.2.
- l'autre type est:
À partir des processeurs Intel Core Solo et Intel Core Duo, il existe deux classes de capacités de surveillance des performances. La première classe prend en charge les événements pour surveiller les performances en utilisant le comptage ou l'utilisation d'échantillonnage d'événements basé sur les interruptions. Ces événements sont non architecturaux et varient d'un modèle de processeur à l'autre ...
Et ces événements ne sont en effet que des liens vers des événements matériels "bruts" sous-jacents, accessibles via l' perf
utilitaire as Raw hardware event descriptor
.
Pour vérifier celui-ci regarde 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,
...
}
- et 0x412e
se trouve exactement dans le "Tableau 18-1. Codages UMask et Event Select pour les événements de performances architecturales prédéfinis" pour "LLC Misses":
Bit Position CPUID.AH.EBX | Event Name | UMask | Event Select
...
4 | LLC Misses | 41H | 2EH
- H
est pour hex. Tous les 7 sont dans la structure, plus [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding *
. (Le nom est un peu différent, les adresses sont les mêmes.)
Ensuite, les Hardware cache event
s sont dans des structures comme (dans le même fichier):
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] =
{...}
- lequel devrait être pour le pont de sable?
L'un d'eux - snb_hw_cache_extra_regs[LL][OP_WRITE][RESULT_ACCESS]
est rempli SNB_DMND_WRITE|SNB_L3_ACCESS
, d'où les def-s ci-dessus:
#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)
qui devrait être égal à 0x00010102
, mais je ne sais pas comment le vérifier avec une table.
Et cela donne une idée de la façon dont il est utilisé dans 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));
$
Les memcpy
s sont terminés __init int intel_pmu_init(void) {... case:...}
.
C'est attr->config1
un peu bizarre. Mais il est là, dans perf_event_attr
(même linux-source-3.13.0/include/uapi/linux/perf_event.h
fichier):
...
union {
__u64 bp_addr;
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
__u64 config2; /* extension of config1 */
};
...
Ils sont enregistrés dans le perf_events
système du noyau avec des appels à int perf_pmu_register(struct pmu *pmu, const char *name, int type)
(définis dans linux-source-3.13.0/kernel/events/core.c:
):
static int __init init_hw_perf_events(void)
(fichier arch/x86/kernel/cpu/perf_event.c
) avec appelperf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
(fichier arch/x86/kernel/cpu/perf_event_intel_uncore.c
, il y en a aussi arch/x86/kernel/cpu/perf_event_amd_uncore.c
) avec appelret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
Donc, finalement, tous les événements proviennent du matériel et tout va bien. Mais ici, on pourrait remarquer: pourquoi avons-nous LLC-loads
en perf list
et non ubox1 LLC-loads
, car ce sont des événements HW et ils viennent réellement d' ubox
es?
C'est une chose de l' perf
utilité et de sa perf_evsel
structure: lorsque vous demandez un événement HW à perf
vous, définissez l'événement à partir de quels processeurs vous le souhaitez (par défaut c'est tout), et il configure perf_evsel
avec l'événement et les processeurs demandés, puis lors de l'agrégation est additionne les compteurs de tous les processeurs perf_evsel
(ou fait d'autres statistiques avec eux).
On peut le voir dans 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;
}
(Donc, pour l'utilitaire, perf
un "compteur unique" n'est même pas un perf_event_attr
, qui est une forme générale, s'adaptant aux événements SW et HW, c'est un événement de votre requête - les mêmes événements peuvent provenir de différents appareils et ils sont agrégés .)
Également un avis: struct perf_evsel
contient seulement 1 struct perf_evevent_attr
, mais il a également un champ struct perf_evsel *leader;
- il est imbriqué. Il existe une fonctionnalité de "groupes d'événements (hiérarchiques)" dans perf_events
, lorsque vous pouvez répartir un groupe de compteurs ensemble, afin qu'ils puissent être comparés entre eux et ainsi de suite. Je ne sais pas comment cela fonctionne avec des événements indépendants de kernel
, core
, ubox
. Mais cette imbrication l' perf_evsel
est. Et, très probablement, c'est ainsi que perf
gère une requête de plusieurs événements ensemble.