À partir d'une liste de paramètres,
perf_event_open() renvoie un descripteur de fichier, pour une
utilisation dans les appels système suivants (read(2),
mmap(2), prctl(2), fcntl(2), etc.).
Un appel de perf_event_open() crée un descripteur de
fichier qui permet de mesurer les renseignements de performance. Tous les
descripteurs de fichier correspondent chacun à un
événement mesuré ; ils peuvent être
regroupés pour mesurer plusieurs événements
simultanément.
Les événements peuvent être activés et
désactivés de deux façons : à l'aide de
ioctl(2) ou de prctl(2). Quand un événement est
désactivé, il ne décompte ni ne génère de
dépassement, mais continue vraiment d'exister et maintient sa valeur
de décompte.
Les événements sont de deux types : comptage
et échantillonnage. Un événement de comptage
sert à comptabiliser le nombre total d'événements qui
se produisent. En général, les résultats d'un
événement de comptage sont recueillis avec un appel
read(2). Un événement d'échantillonnage
écrit périodiquement les mesures dans un tampon qui peut
ensuite être accédé à l'aide de
mmap(2).
Les arguments pid et cpu permettent
d’indiquer le processus et le processeur à
surveiller :
- pid == 0 et cpu ==
-1
- Cela mesure le processus ou thread appelant sur tous les processeurs.
- pid == 0 et cpu
>= 0
- Cela ne mesure le processus ou thread appelant que s’il est en
cours d’exécution sur le processeur indiqué.
- pid > 0 et cpu
== -1
- Cela mesure le processus ou thread indiqué sur tous les
processeurs.
- pid > 0 et cpu
>= 0
- Cela ne mesure le processus ou thread indiqué que s’il est
en cours d’exécution sur le processeur indiqué.
- pid == -1 et cpu
>= 0
- Cela mesure tous les processus et threads du processeur indiqué.
Cela nécessite la capacité CAP_PERFMON (depuis
Linux 5.8) ou CAP_SYS_ADMIN ou une valeur
/proc/sys/kernel/perf_event_paranoid strictement inférieure
à 1.
- pid == -1 et cpu
== -1
- Ce réglage est incorrect et renverra une erreur.
Quand pid est supérieur à zéro, le
droit d'effectuer cet appel système est géré par
CAP_PERFMON (depuis Linux 5.9) et une vérification
PTRACE_MODE_READ_REALCREDS du mode d'accès ptrace sur les
anciennes versions du noyau ; voir ptrace(2).
L'argument group_fd permet aux groupes
d'événements d'être créés. Un groupe
d'événements a un événement qui est le leader de
groupe. Le leader est d'abord créé avec
group_fd = -1. Les autres membres du groupe sont
créés par les appels perf_event_open() suivants, avec
group_fd défini au descripteur de fichier du leader de groupe
(un événement unique créé avec
group_fd = -1 est considéré comme
formant un groupe d'un seul membre). Un événement de groupe
est programmé dans le processeur comme un bloc : il ne sera
mis dans le processeur que si tous les événements du groupe
peuvent être mis dans le processeur. Cela veut dire que les valeurs
des événements de tous les membres peuvent être
comparées — ajoutées, divisées (pour
obtenir des rapports), etc. — ensemble de
manière significative, puisqu'elles ont compté les
événements pendant les mêmes instructions
exécutées.
L'argument flags est constitué d’un OU
binaire entre une ou plusieurs des valeurs suivantes.
- PERF_FLAG_FD_CLOEXEC
(depuis Linux 3.14)
- Cet attribut active l’attribut
« close-on-exec » pour le descripteur de
fichier de l’événement créé, de telle
sorte que le descripteur de fichier est automatiquement fermé par
execve(2). L’attribution de
« close-on-exec » au moment de la
création, plutôt qu’ensuite avec fcntl(2),
évite de potentielles situations de compétition où le
thread appelant invoque perf_event_open() et fcntl() en
même temps qu’un autre thread appelle fork(2) puis
execve(2).
- PERF_FLAG_FD_NO_GROUP
- Cet attribut dit à l'événement d'ignorer le
paramètre group_fd, sauf pour initialiser la redirection de
la sortie en utilisant l'attribut PERF_FLAG_FD_OUTPUT.
- PERF_FLAG_FD_OUTPUT
(cassé depuis Linux 2.6.35)
- Cet attribut redirige la sortie échantillonnée de
l'événement vers le tampon mmap de l'événement
indiqué par group_fd.
- PERF_FLAG_PID_CGROUP
(depuis Linux 2.6.39)
- Cet attribut active la surveillance par conteneur sur tout le
système. Un conteneur est une abstraction qui isole un ensemble de
ressources à contrôler plus finement (processeurs,
mémoire, etc.). Dans ce mode, l'événement
n'est mesuré que si le thread exécuté sur le
processeur surveillé appartient au conteneur désigné
(cgroup). Le cgroup est identifié en passant un fichier au
descripteur de fichier ouvert sur son répertoire dans le
système de fichiers cgroupfs. Par exemple, si le cgroup à
surveiller est appelé test, alors un descripteur de fichier
ouvert sur /dev/cgroup/test (en supposant que cgroupfs est
monté sur /dev/cgroup) doit être passé au
paramètre pid. La surveillance de cgroup n'est disponible
que pour les événements sur tout le système et
pourrait donc nécessiter des droits supplémentaires.
La structure perf_event_attr fournit des renseignements de
configuration détaillés pour les événements en
cours de création.
struct perf_event_attr {
__u32 type; /* Type d'événement */
__u32 size; /* Taille de la structure d'attributs */
__u64 config; /* Configuration spécifique au type */
union {
__u64 sample_period; /* Période d'échantillonnage */
__u64 sample_freq; /* Fréquence d'échantillonnage */
};
__u64 sample_type; /* Indique les valeurs incluses dans
l’échantillon */
__u64 read_format; /* Indique les valeurs renvoyées en
lecture */
__u64 disabled : 1, /* désactivé par défaut */
inherit : 1, /* les enfants en héritent */
pinned : 1, /* doit toujours être en PMU */
exclusive : 1, /* ne regrouper qu'en PMU */
exclude_user : 1, /* ne pas compter l'utilisateur */
exclude_kernel : 1, /* ne pas compter le noyau */
exclude_hv : 1, /* ne pas compter l'hyperviseur */
exclude_idle : 1, /* ne pas compter quand inactif */
mmap : 1, /* inclure les données mmap */
comm : 1, /* inclure les données comm */
freq : 1, /* utiliser la fréquence, pas la
période */
inherit_stat : 1, /* décomptes par tâche */
enable_on_exec : 1, /* prochain exec activé */
task : 1, /* tracer la création d’enfant
et la fin */
watermark : 1, /* wakeup_watermark */
precise_ip : 2, /* contrainte de dérapage */
mmap_data : 1, /* données mmap non exécutées */
sample_id_all : 1, /* tous les événements sample_type */
exclude_host : 1, /* ne pas compter dans l'hôte */
exclude_guest : 1, /* ne pas compter dans l'invité */
exclude_callchain_kernel : 1,
/* exclure les appels en chaîne
du noyau */
exclude_callchain_user : 1,
/* exclure les appels en chaîne
d’utilisateur */
mmap2 : 1, /* inclure mmap avec les données d'inœud */
comm_exec : 1, /* événements flag comm devant être
exécutés */
use_clockid : 1, /* utiliser clockid pour les champs de temps */
context_switch : 1, /* données de changement de contexte */
write_backward : 1, /* Écrire le tampon circulaire de la fin
vers le début */
namespaces : 1, /* inclure les données des espaces de noms */
ksymbol : 1, /* inclure les événements ksymbol */
bpf_event : 1, /* inclure les événements BPF */
aux_output : 1, /* générer les enregistrements AUX au lieu des
événements */
cgroup : 1, /* inclure les événements cgroup */
text_poke : 1, /* inclure les événements de poke de texte */
build_id : 1, /* utiliser build id dans les événements mmap2 */
inherit_thread : 1, /* seuls les enfants en héritent */
/* si cloné avec CLONE_THREAD */
remove_on_exec : 1, /* l'événement est supprimé des tâches
à l'exécution */
sigtrap : 1, /* envoyer un SIGTRAP synchrone
lors d'un événement */
__reserved_1 : 26;
union {
__u32 wakeup_events; /* réveil tous les n événements */
__u32 wakeup_watermark; /* octets avant le réveil */
};
__u32 bp_type; /* type de point d'arrêt */
union {
__u64 bp_addr; /* adresse de point d'arrêt */
__u64 kprobe_func; /* pour perf_kprobe */
__u64 uprobe_path; /* pour perf_uprobe */
__u64 config1; /* extension de config */
};
union {
__u64 bp_len; /* taille de point d'arrêt */
__u64 kprobe_addr; /* avec kprobe_func == NULL */
__u64 probe_offset; /* pour perf_[k,u]probe */
__u64 config2; /* extension de config1 */
};
__u64 branch_sample_type; /* enum perf_branch_sample_type */
__u64 sample_regs_user; /* registres utilisateur à renvoyer
dans les échantillons */
__u32 sample_stack_user; /* taille de pile à renvoyer dans
les échantillons */
__s32 clockid; /* horloge à utiliser pour les champs
de temps */
__u64 sample_regs_intr; /* registres à renvoyer dans les
échantillons */
__u32 aux_watermark; /* octets supp. avant le réveil */
__u16 sample_max_stack; /* nombre maximal de trames dans la
chaîne d'appel */
__u32 __reserved_2; /* aligner sur u64 */
__u32 aux_sample_size; /* taille maximale d'échantillon aux */
__u32 __reserved_3; /* aligner sur u64 */
__u64 sig_data; /* données utilisateur pour sigtrap */
};
Les champs de la structure perf_event_attr sont
décrits en détail ci-dessous.
- type
- Ce champ indique le type d'événement dans son ensemble. Il a
une des valeurs suivantes :
- PERF_TYPE_HARDWARE
- Cela indique un des événements matériels
« généralisés » fournis
par le noyau. Consultez la définition du champ config pour
plus de précisions.
- PERF_TYPE_SOFTWARE
- Cela indique un des événements logiciels fournis par le
noyau (même si aucune prise en charge matérielle n'est
disponible).
- PERF_TYPE_TRACEPOINT
- Cela indique un point de trace fourni par l'infrastructure de point de
trace du noyau.
- PERF_TYPE_HW_CACHE
- Cela indique un événement de cache matériel. Cela a
un encodage particulier décrit dans la définition du champ
config.
- PERF_TYPE_RAW
- Cela indique un événement
« brut » spécifique à
l'implémentation dans le champ config.
- PERF_TYPE_BREAKPOINT
(depuis Linux 2.6.33)
- Cela indique un point d'arrêt matériel tel que fourni par le
processeur. Les points d'arrêt peuvent être des accès
en lecture ou écriture sur une adresse ainsi que l'exécution
d'une adresse d'instruction.
- PMU dynamique
- Depuis Linux 2.6.38, perf_event_open() permet de
gérer plusieurs PMU. Pour activer cela, une valeur exportée
par le noyau peut être utilisée dans le champ type
pour indiquer la PMU à utiliser. La valeur à utiliser est
trouvable dans le système de fichiers sysfs : un
sous-répertoire existe par instance PMU sous
/sys/bus/event_source/devices. Le fichier type dans chaque
sous-répertoire contient un entier qui peut être
utilisé dans le champ type. Par exemple,
/sys/bus/event_source/devices/cpu/type contient la valeur de PMU du
processeur principal, c'est-à-dire 4 en général.
- kprobe et
uprobe (depuis Linux 4.17)
- Ces deux PMU dynamiques créent un kprobe/uprobe et le rattachent
à un descripteur de fichier généré par
perf_event_open. kprobe/uprobe sera détruit lors de la destruction
du descripteur de fichier. Voir les champs kprobe_func,
uprobe_path, kprobe_addr et probe_offset pour plus de
détails.
- size
- La taille de la structure perf_event_attr pour
compatibilités ascendante et descendante. Définissez-la en
utilisant sizeof(struct perf_event_attr) pour permettre au noyau de
voir la taille de struct au moment de la compilation.
- Le PERF_ATTR_SIZE_VER0 relatif est défini à
64 ; c'était la taille de la première struct
publiée. PERF_ATTR_SIZE_VER1 est 72, correspondant à
l'addition des points d'arrêts dans Linux 2.6.33.
PERF_ATTR_SIZE_VER2 est 80, correspondant à l'addition
d'échantillonnage de branchement dans Linux 3.4.
PERF_ATR_SIZE_VER3 est 96, correspondant à l'addition de
sample_regs_user et sample_stack_user dans Linux 3.7.
PERF_ATTR_SIZE_VER4 vaut 104, correspondant à l'ajout de
sample_regs_intr dans Linux 3.19. PERF_ATTR_SIZE_VER5
vaut 112, correspondant à l'ajout de aux_watermark dans
Linux 4.1.
- config
- Cela indique l'événement voulu, en conjonction avec le champ
type. Les champs config1 et config2 sont aussi pris
en compte dans les cas où 64 bits ne suffisent pas pour
spécifier complètement l'événement. L'encodage
de ces champs dépend de l'événement.
- Le champ config peut être défini de
différentes façons, en fonction de la valeur du champ
type précédemment décrit. Suivent les divers
réglages possibles pour config, distingués par
type.
- Si type est PERF_TYPE_HARDWARE, un des
événements processeur matériel
généralisé est mesuré. Ils ne sont pas tous
disponibles sur toutes les plateformes. Définissez config
à une des valeurs suivantes :
- Si type est PERF_TYPE_SOFTWARE, les événements
logiciels fournis par le noyau sont mesurés. Définissez
config à une des valeurs suivantes :
- PERF_COUNT_SW_CPU_CLOCK
- Cela rend compte de l'horloge du processeur, un temporisateur par
processeur à haute résolution.
- PERF_COUNT_SW_TASK_CLOCK
- Cela rend compte de l'horloge spécifique à la tâche
en cours d'exécution.
- PERF_COUNT_SW_PAGE_FAULTS
- Cela rend compte du nombre d'erreurs de pagination.
- PERF_COUNT_SW_CONTEXT_SWITCHES
- Cela compte les changements de contexte. Jusqu'à
Linux 2.6.34, ils étaient tous signalés comme des
événements en espace utilisateur, ils sont maintenant
signalés comme ayant lieu dans le noyau.
- PERF_COUNT_SW_CPU_MIGRATIONS
- Cela rend compte du nombre de fois où le processus a migré
vers un nouveau processeur.
- PERF_COUNT_SW_PAGE_FAULTS_MIN
- Cela compte le nombre d'erreurs mineures de pagination. Elles n'ont pas
nécessité d'entrées ou sorties du disque pour les
traiter.
- PERF_COUNT_SW_PAGE_FAULTS_MAJ
- Cela compte le nombre d'erreurs majeures de pagination. Elles ont
nécessité des entrées ou sorties de disque pour les
traiter.
- PERF_COUNT_SW_ALIGNMENT_FAULTS
(depuis Linux 2.6.33)
- Cela compte le nombre de défauts d'alignement. Ils ont lieu lors
d'accès non alignés en mémoire ; le noyau peut
les traiter mais cela réduit les performances. Cela n'arrive que
sur certaines architectures (jamais sur x86).
- PERF_COUNT_SW_EMULATION_FAULTS
(depuis Linux 2.6.33)
- Cela compte le nombre de défauts d'émulation. Le noyau
intercepte parfois des instructions non implémentées et les
émule pour l'espace utilisateur. Cela peut avoir des
conséquences négatives sur les performances.
- PERF_COUNT_SW_DUMMY
(depuis Linux 3.12)
- C’est un événement fictif qui ne compte rien. Les
types d’enregistrement d’échantillonnage informatif
comme mmap ou comm doivent être associés à un
événement actif. Cet événement factice permet
de récupérer ce genre d’enregistrements sans
nécessiter d’événement de comptage.
- PERF_COUNT_SW_BPF_OUTPUT
(depuis Linux 4.4)
- Cela est utilisé pour générer des données
d'échantillonnage brutes à partir de BPF. Les programmes BPF
peuvent écrire sur cet événement en utilisant
l'assistant bpf_perf_event_output.
- PERF_COUNT_SW_CGROUP_SWITCHES
(since Linux 5.13)
- Cela compte les changements de contexte d'une tâche dans un cgroup
différent. En d'autres termes, si la tâche suivante est dans
le même cgroup, il ne comptera le changement.
Si type est PERF_TYPE_TRACEPOINT, alors les
points de trace du noyau sont mesurés. La valeur à utiliser dans
config peut être obtenue depuis tracing/events/*/*/id de
debugfs si ftrace est activé dans le noyau.
Si
type est
PERF_TYPE_HW_CACHE, alors un
événement de cache du processeur matériel est
mesuré. Utilisez l'équation suivante pour calculer la valeur
config appropriée.
config = (perf_hw_cache_id) |
(perf_hw_cache_op_id << 8) |
(perf_hw_cache_op_result_id << 16);
où perf_hw_cache_id peut être :
et perf_hw_cache_op_id est parmi :
et perf_hw_cache_op_result_id peut être :
Si type est PERF_TYPE_RAW, alors une valeur
config « brute » personnalisée est
nécessaire. La plupart des processeurs gèrent les
événements qui ne sont pas couverts par les
événements
« généralisés ». Ceux-ci
sont définis par l'implémentation ; consultez le manuel
du processeur (par exemple la documentation Intel Volume 3B ou le
guide du développeur de BIOS et noyau AMD). La bibliothèque
libpfm4 peut être utilisée pour traduire le nom, dans les
manuels architecturaux, en valeur hexadécimale brute que
perf_event_open() attend dans ce champ.
Si type est PERF_TYPE_BREAKPOINT, alors laissez
config défini à zéro. Ses paramètres sont
définis ailleurs.
Si type est kprobe ou uprobe, définir
retprobe (bit 0 de config, voir
/sys/bus/event_source/devices/[k,u]probe/format/retprobe) pour
kretprobe/uretprobe. Voir les champs kprobe_func, uprobe_path,
kprobe_addr et probe_offset pour plus de détails.
- kprobe_func,
uprobe_path, kprobe_addr et probe_offset
- Ces champs décrivent les kprobe/uprobe pour les PMU dynamiques
kprobe et uprobe. Pour kprobe utilisez
kprobe_func et probe_offset ou alors utilisez
kprobe_addr et laissez le champ kprobe_func à NULL.
Pour uprobe, utilisez uprobe_path et
probe_offset.
- sample_period,
sample_freq
- Un compteur d'« échantillonnage »
génère une notification de dépassement tous les
N événements, où N est donné par
sample_period. Un compteur d'échantillonnage a
sample_period > 0. Quand un dépassement
arrive, les données demandées sont enregistrées dans
le tampon mmap. Le champ sample_type contrôle les
données qui sont enregistrées à chaque
dépassement.
- sample_freq permet d'utiliser la fréquence au lieu de la
période. Dans ce cas, l'attribut freq doit être
défini. Le noyau ajustera la période
d'échantillonnage pour essayer d'atteindre le taux voulu. Le taux
d'ajustement est un tic d'horloge.
- sample_type
- Les divers bits de ce champ indiquent les valeurs à inclure dans
l'échantillon. Elles seront enregistrées dans un tampon
circulaire, disponible en espace utilisateur avec mmap(2). L'ordre
de sauvegarde des valeurs dans l'échantillon est documenté
dans la sous-section Disposition MMAP ci-dessous ; ce n'est
pas l'ordre enum perf_event_sample_format.
- PERF_SAMPLE_IP
- Enregistrement de pointeur d'instruction.
- PERF_SAMPLE_TID
- Enregistrement des identifiants de processus et de thread.
- PERF_SAMPLE_TIME
- Enregistrement d'un horodatage.
- PERF_SAMPLE_ADDR
- Enregistrement d'une adresse, si applicable.
- PERF_SAMPLE_READ
- Enregistrement des valeurs de décompte de tous les
événements d'un groupe, pas seulement du leader de
groupe.
- PERF_SAMPLE_CALLCHAIN
- Enregistrement de l'appel en chaîne (backtrace de pile).
- PERF_SAMPLE_ID
- Enregistrement d'un identifiant unique pour le leader de groupe
d'événements ouvert.
- PERF_SAMPLE_CPU
- Enregistrement de numéro de processeur.
- PERF_SAMPLE_PERIOD
- Enregistrement de la période d'échantillonnage
actuelle.
- PERF_SAMPLE_STREAM_ID
- Enregistrement d'un identifiant unique pour l'événement
ouvert. Contrairement à PERF_SAMPLE_ID, le véritable
identifiant est renvoyé, pas celui du leader de groupe. Cet
identifiant est le même que celui renvoyé par
PERF_FORMAT_ID.
- PERF_SAMPLE_RAW
- Enregistrement de données supplémentaires, si applicable.
Normalement renvoyées par les événements de point de
trace.
- PERF_SAMPLE_BRANCH_STACK
(depuis Linux 3.4)
- Cela fournit un enregistrement des derniers branchements tels que fournis
par le matériel d’échantillonnage de branchement
processeur (comme le LBR – Last Branch
Record – d’Intel). Les matériels ne prennent
pas tous en charge cette fonctionnalité.
- Consultez le champ branch_sample_type pour la façon de
filtrer les branchements signalés.
- PERF_SAMPLE_REGS_USER
(depuis Linux 3.7)
- Enregistrement de l’état actuel du registre processeur au
niveau utilisateur (les valeurs dans le processus avant d’appeler
le noyau).
- PERF_SAMPLE_STACK_USER
(depuis Linux 3.7)
- Enregistrement de la pile au niveau utilisateur, permettant le
défilement de la pile.
- PERF_SAMPLE_WEIGHT
(depuis Linux 3.10)
- Enregistrement d’une valeur de poids fournie par le matériel
qui exprime le coût de l’événement
d’échantillonnage. Cela permet au matériel de mettre
en valeur les événements coûteux dans un profil.
- PERF_SAMPLE_DATA_SRC
(depuis Linux 3.10)
- Enregistrement des sources de données : d’où
viennent, dans la hiérarchie de mémoire, les données
associées à l’instruction
d’échantillonnage. Ce n’est disponible que si le
matériel sous-jacent prend en charge cette
fonctionnalité.
- PERF_SAMPLE_IDENTIFIER
(depuis Linux 3.12)
- Placement de la valeur SAMPLE_ID à un endroit fixe de
l’enregistrement, soit au début (pour les
événements d’échantillonnage), soit à
la fin (si ce n’est pas un événement
d’échantillonnage).
- C’était nécessaire parce qu’un flux
d’échantillonnage pourrait avoir des enregistrements
provenant de différentes sources d’événements
avec des réglages de sample_type différents.
L’analyse correcte du flux d’événements
n’était pas possible parce que le format de
l’enregistrement était nécessaire pour trouver
SAMPLE_ID, mais le format ne pouvait pas être trouvé
sans savoir à quel événement
l’échantillonnage appartenait (provoquant une
dépendance circulaire).
- Ce nouveau réglage PERF_SAMPLE_IDENTIFIER rend le flux
d’événements toujours analysable en plaçant
SAMPLE_ID à une position fixe, même si cela a pour
conséquence de dupliquer les valeurs SAMPLE_ID dans les
enregistrements.
- PERF_SAMPLE_TRANSACTION
(depuis Linux 3.13)
- Enregistrement des raisons pour les événements
d’abandon de mémoire transactionnelle (venant par exemple de
la prise en charge de mémoire transactionnelle TSX Intel).
- Le réglage precise_ip doit être positif et un
événement d’abandon de mémoire
transactionnelle doit être mesuré sinon aucune valeur ne
sera enregistrée. Remarquez également que certaines mesures
perf_event, comme le comptage de cycles d’échantillonnage,
peuvent provoquer des abandons supplémentaires (en provoquant une
interruption lors d’une transaction).
- PERF_SAMPLE_REGS_INTR
(depuis Linux 3.19)
- Enregistrement d'un sous-ensemble de l'état actuel du registre du
processeur comme indiqué par sample_regs_intr. Contrairement
à PERF_SAMPLE_REGS_USER, les valeurs du registre renverront
l'état du registre du noyau si le dépassement s'est produit
alors que le code du noyau est en cours d'exécution. Si le
processeur gère l'échantillonnage matériel de
l'état du registre (à savoir PEBS sur Intel x86) et si
precise_ip est supérieur à zéro, les valeurs
du registre renvoyées sont celles récupérées
par le matériel au moment du retrait de l'instruction
échantillonnée.
- PERF_SAMPLE_PHYS_ADDR
(depuis Linux 4.13)
- Enregistrement de l'adresse physique des données comme avec
PERF_SAMPLE_ADDR.
- PERF_SAMPLE_CGROUP
(depuis Linux 5.7)
- Enregistrement de l'identifiant cgroup (perf_event) du processus. Cela
correspond au champ id de l'événement
PERF_RECORD_CGROUP.
- PERF_SAMPLE_DATA_PAGE_SIZE
(depuis Linux 5.11)
- Enregistrement de la taille de la page de données comme avec
PERF_SAMPLE_ADDR.
- PERF_SAMPLE_CODE_PAGE_SIZE
(depuis Linux 5.11)
- Enregistrement de la taille de la page de l'ip comme avec
PERF_SAMPLE_ADDR.
- PERF_SAMPLE_WEIGHT_STRUCT
(depuis Linux 5.12)
- Enregistrement d’une valeur de poids fournie par le matériel
comme PERF_SAMPLE_WEIGHT, mais il peut représenter plusieurs
valeur dans un struct. Il partage le même espace que
PERF_SAMPLE_WEIGHT, aussi les utilisateurs peuvent appliquer l'un
ou l'autre, mais pas les deux à la fois. Il a le format suivant et
la signification de chaque champ dépend de l'implémentation
matérielle.
union perf_sample_weight {
u64 full; /* PERF_SAMPLE_WEIGHT */
struct { /* PERF_SAMPLE_WEIGHT_STRUCT */
u32 var1_dw;
u16 var2_w;
u16 var3_w;
};
};
- read_format
- Ce champ indique le format des données renvoyées par
read(2) sur un descripteur de fichier
perf_event_open().
- PERF_FORMAT_TOTAL_TIME_ENABLED
- Ajout du champ time_enabled de 64 bits. Cela peut servir
à calculer les totaux estimés si la PMU est
surutilisée et qu'il y a multiplexage.
- PERF_FORMAT_TOTAL_TIME_RUNNING
- Ajout du champ time_running de 64 bits. Cela peut servir
pour calculer les totaux estimés si la PMU est surutilisée
et qu'il y a multiplexage.
- PERF_FORMAT_ID
- Ajout d'une valeur unique de 64 bits qui correspond au groupe
d’événements.
- PERF_FORMAT_GROUP
- Permettre à toutes les valeurs de décompte d'un groupe
d'événements d'être lues en une seule lecture.
- PERF_FORMAT_LOST
(depuis Linux 6.0)
- Ajout d'une valeur 64 bits qui est le nombre d'échantillons
perdus pour cet événement. Ce ne devrait significatif
uniquement quand sample_period ou sample_freq est
défini.
- disabled
- Le bit disabled indique si le compteur commence
désactivé ou activé. Si désactivé,
l'événement peut être activé plus tard par
ioctl(2), prctl(2) ou enable_on_exec.
- Lors de la création d’un groupe
d’événements, le leader de groupe est
généralement initialisé avec disabled
défini à 1 et tous les événements
enfants sont initialisés avec disabled défini
à 0. Bien que disabled soit 0, les
événements enfants ne démarrent pas avant que le
leader de groupe ne soit activé.
- inherit
- Le bit inherit indique que le compteur devrait compter les
événements des tâches enfant comme les tâches
indiquées. Cela ne s'applique qu'aux nouveaux enfants, pas à
ceux existants au moment où le compteur est créé (ni
aux nouveaux enfants des enfants existants).
- L'héritage ne fonctionne pas pour certaines combinaisons de
read_format, comme PERF_FORMAT_GROUP.
- pinned
- Le bit pinned indique que le compteur devrait toujours être
sur le processeur si c'est possible. Cela ne s'applique qu'aux compteurs
matériels et seulement aux leaders de groupe. Si un compteur
épinglé ne peut pas être mis dans le processeur (par
exemple s'il n'y a pas assez de compteurs matériels ou en cas de
confit avec n'importe quel autre événement), alors le
compteur arrive en état d'« erreur »,
où les lectures renvoient une fin de fichier (c'est-à-dire
que read(2) renvoie 0) jusqu'à ce que le compteur
soit ensuite activé ou désactivé.
- exclusive
- Le bit exclusive indique que si ce groupe du compteur est sur le
processeur, il devrait être le seul groupe utilisant les compteurs
du processeur. Cela pourrait permettre à l'avenir de surveiller des
programmes pour gérer les fonctionnalités PMU qui doivent
fonctionner seules, sans perturber d'autres compteurs
matériels.
- Remarquez que de nombreuses situations non attendues pourraient
empêcher de démarrer les événements avec le
bit exclusive défini. Cela concerne tous les utilisateurs
exécutant des mesures au niveau du système ainsi que toutes
les utilisations par le noyau des compteurs de performance (y compris
l’interface NMI Watchdog Timer habituellemen activée).
- exclude_user
- Si ce bit est défini, le décompte exclut les
événements qui arrivent dans l'espace utilisateur.
- exclude_kernel
- Si ce bit est défini, le décompte exclut les
événements qui arrivent dans l'espace du noyau.
- exclude_hv
- Si ce bit est défini, le décompte exclut les
événements qui arrivent dans l'hyperviseur. C'est surtout
pour les PMU avec prise en charge intégrée de leur
traitement (comme POWER). Une prise en charge supplémentaire est
nécessaire pour traiter les mesures d'hyperviseur sur la plupart
des machines.
- exclude_idle
- S'il est défini, ne pas décompter quand le processeur
exécute la tâche inactive. Si vous pouvez actuellement
activer cela pour n'importe quel type d'événement, il est
ignoré pour tous, sauf ceux de type logiciel.
- mmap
- Le bit mmap active la génération des
échantillons PERF_RECORD_MMAP pour tous les appels
mmap(2) qui ont PROT_EXEC défini. Cela permet aux
outils de remarquer le nouveau code exécutable en train
d’être associé dans un programme (les
bibliothèques partagées dynamiques par exemple) de telle
sorte que les adresses peuvent être réassociées au
code d’origine.
- comm
- Le bit comm active le suivi du nom de commande de processus tel que
modifié par les appels système execve(2) et
prctl(PR_SET_NAME) ainsi que l'écriture dans
/proc/self/comm. Si l'attribut comm_exec est
positionné avec succès (ce qui est possible depuis
Linux 3.16), l'attribut général
PERF_RECORD_MISC_COMM_EXEC peut être utilisé pour
différencier le cas execve(2) des autres.
- freq
- Si ce bit est activé, alors sample_frequency est
utilisé au lieu de sample_period lors du réglage de
l'intervalle d'échantillonnage.
- inherit_stat
- Ce bit active la sauvegarde des décomptes
d'événements lors du changement de contexte pour les
tâches héritées. Cela n'a de sens que si le champ
inherit est défini.
- enable_on_exec
- Si ce bit est défini, un compteur est automatiquement activé
après un appel d'execve(2).
- task
- Si ce bit est défini, alors les notifications de création
d’enfant et de fin sont inclues au tampon circulaire.
- watermark
- Si défini, une notification de débordement arrive lors du
passage de la frontière wakeup_watermark. Sinon, les
notifications arrivent après les échantillons
wakeup_events.
- precise_ip
(depuis Linux 2.6.35)
- Cela contrôle la quantité de dérapage. Le
dérapage est le nombre d'instructions qui s'exécutent entre
l'arrivée d'un événement d'intérêt et
la possibilité du noyau de s'arrêter pour enregistrer
l'événement. Les plus petits dérapages sont meilleurs
et permettent d'associer plus précisément les
événements correspondant aux instructions, mais le
matériel est souvent limité par leur taille.
- Les valeurs possibles du champ sont les suivantes :
- 0
- SAMPLE_IP peut avoir un dérapage arbitraire ;
- 1
- SAMPLE_IP doit avoir un dérapage constant ;
- 2
- SAMPLE_IP a demandé un dérapage nul ;
- 3
- SAMPLE_IP doit avoir un dérapage nul. Consultez aussi la
description de PERF_RECORD_MISC_EXACT_IP.
- mmap_data
(depuis Linux 2.6.36)
- L’opposé du champ mmap. Cela active la
génération des échantillons PERF_RECORD_MMAP
pour les appels mmap(2) qui n’ont pas PROT_EXEC
défini (par exemple les données et la mémoire
partagée SysV).
- sample_id_all
(depuis Linux 2.6.38)
- Si défini, alors TID, TIME, ID, STREAM_ID et CPU peuvent de plus
être inclus dans les non PERF_RECORD_SAMPLE si le
sample_type correspondant est sélectionné.
- Si PERF_SAMPLE_IDENTIFIER est indiqué, alors une valeur
d’identifiant supplémentaire est incluse en dernière
valeur pour faciliter l’analyse du flux d’enregistrement.
Cela peut avoir pour conséquence de voir apparaître la
valeur id deux fois.
- La disposition est décrite par cette pseudostructure :
-
struct sample_id {
{ u32 pid, tid; } /* si PERF_SAMPLE_TID est défini */
{ u64 time; } /* si PERF_SAMPLE_TIME est défini */
{ u64 id; } /* si PERF_SAMPLE_ID est défini */
{ u64 stream_id;} /* si PERF_SAMPLE_STREAM_ID est défini */
{ u32 cpu, res; } /* si PERF_SAMPLE_CPU est défini */
{ u64 id; } /* si PERF_SAMPLE_IDENTIFIER est défini */
};
- exclude_host
(depuis Linux 3.2)
- Quand on prend des mesures comprenant les processus exécutant des
instances de VM (à savoir si on exécute ioctl(2)
KVM_RUN), ne mesurer que les événements dans
l'instance de l'invité. Cela n'a de sens qu'à
l'extérieur de l'invité ; ce paramètre ne
modifie pas les compteurs à l'intérieur d'un invité.
Actuellement, cette fonctionnalité n'existe que sur x86.
- exclude_guest
(depuis Linux 3.2)
- Quand on prend des mesures comprenant les processus exécutant des
instances de VM (à savoir si on exécute ioctl(2)
KVM_RUN), ne pas mesurer les événements dans
l'instance de l'invité. Cela n'a de sens qu'à
l'extérieur de l'invité ; ce paramètre ne
modifie pas les compteurs à l'intérieur d'un invité.
Actuellement, cette fonctionnalité n'existe que sur x86.
- exclude_callchain_kernel
(depuis Linux 3.7)
- Ne pas inclure les appels en chaîne du noyau.
- exclude_callchain_user
(depuis Linux 3.7)
- Ne pas inclure les appels en chaîne d'utilisateur.
- mmap2 (depuis Linux
3.16)
- Générer un enregistrement mmap exécutable
étendu contenant assez d'informations supplémentaires pour
n'identifier que les projections partagées. L'attribut mmap
doit aussi être défini pour que cela fonctionne.
- comm_exec
(depuis Linux 3.16)
- Il s'agit d'un attribut de pure détection de fonctionnalité,
il ne modifie pas le comportement du noyau. Si cet attribut peut
être positionné avec succès, quand comm est
activé, l'attribut PERF_RECORD_MISC_COMM_EXEC sera
positionné dans le champ misc de l'entête de
l'enregistrement comm si l'événement de renommage
signalé a été causé par un appel à
execve(2). Cela permet aux outils de distinguer les types de
renommage du processus.
- use_clockid
(depuis Linux 4.1)
- Cela permet de sélectionner l'horloge interne du noyau Linux
à utiliser lors de la génération des horodatages
à l'aide du champ clockid. Cela peut faciliter la
corrélation des durées d'échantillonnage des perf
avec les horodatages générés par d'autres
outils.
- context_switch
(depuis Linux 4.3)
- Cela active la génération d'enregistrements
PERF_RECORD_SWITCH lors d'un changement de contexte. Cela active
aussi la génération d'enregistrements
PERF_RECORD_SWITCH_CPU_WIDE lors d'un échantillonnage en
mode processeur complet. Cette fonctionnalité s'ajoute aux points
de trace existants et aux événements logiciels de mesure des
changements de contexte. L'avantage de cette méthode est qu'elle
fournira toutes les informations même avec des réglages
perf_event_paranoid stricts.
- write_backward
(depuis Linux 4.6)
- Cela fait écrire le tampon circulaire de la fin vers le
début. Cela permet de gérer la lecture à partir
d’un tampon circulaire réinscriptible.
- namespaces
(depuis Linux 4.11)
- Cela active la génération d'enregistrements
PERF_RECORD_NAMESPACES lorsqu'une tâche entre dans un nouvel
espace de noms. Chaque espace de noms a une combinaison de numéros
de périphérique et d'inœud.
- ksymbol (depuis
Linux 5.0)
- Cela active la génération d'enregistrements
PERF_RECORD_KSYMBOL quand de nouveaux symboles du noyau sont
enregistrés ou désenregistrés. Cela concerne les
fonctions dynamiques d’analyse du noyau comme eBPF.
- bpf_event
(depuis Linux 5.0)
- Cela active la génération d'enregistrements
PERF_RECORD_BPF_EVENT lorsqu'un programme eBPF est chargé ou
déchargé.
- aux_output
(depuis Linux 5.4)
- Cela permet aux événements normaux (non-AUX) de
générer des données pour des événements
AUX si le matériel le prend en charge.
- cgroup (depuis
Linux 5.7)
- Cela active la génération d'enregistrements
PERF_RECORD_CGROUP quand un nouveau cgroup est créé
(et activé).
- text_poke
(depuis Linux 5.8)
- Cela active la génération d'enregistrements
PERF_RECORD_TEXT_POKE quand un changement se produit dans le texte
du noyau (c'est-à-dire quand du code se modifie
lui-même).
- build_id
(depuis Linux 5.12)
- Cela modifie le contenu dePERF_RECORD_MMAP2 pour avoir un build-id
à la place des numéros de périphérique et
d'inœud.
- inherit_thread
(depuis Linux 5.13)
- Cela désactive l'héritage de l'événement vers
un processus enfant. Seuls les nouveaux threads dans le même
processus (qui est cloné avec CLONE_THREAD)
hériteront de l'événement.
- remove_on_exec
(depuis Linux 5.13)
- Cela clôt l'événement quand il démarre une
nouvelle image de processus avec execve(2).
- sigtrap (depuis
Linux 5.13)
- Cela permet l'envoi d'un signal synchrone de SIGTRAP quand un
événement déborde.
- wakeup_events,
wakeup_watermark
- Cette union indique le nombre d'échantillons (wakeup_events)
ou d'octets (wakeup_watermark) qui arrivent avant un signal de
dépassement. Celui utilisé est sélectionné par
l'attribut watermark.
- wakeup_events ne compte que les types d’enregistrement
PERF_RECORD_SAMPLE. Pour recevoir un signal pour tous les types
PERF_RECORD arrivant, choisissez watermark et définissez
wakeup_watermark à 1.
- Avant Linux 3.0, positionner wakeup_events à 0
ne signalait aucun dépassement ; les noyaux plus
récents traitent 0 comme 1.
- bp_type (depuis
Linux 2.6.33)
- Cela choisit le type de point d'arrêt. Il s'agit d'un des
suivants :
- HW_BREAKPOINT_EMPTY
- pas de point d'arrêt ;
- HW_BREAKPOINT_R
- compte lors de la lecture de l'emplacement mémoire ;
- HW_BREAKPOINT_W
- compte lors de l'écriture à l'emplacement
mémoire ;
- HW_BREAKPOINT_RW
- compte lors de la lecture ou l'écriture à l'emplacement
mémoire ;
- HW_BREAKPOINT_X
- compte lors de l'exécution de code à l'emplacement
mémoire.
Les valeurs peuvent être combinées à l'aide
d'un OU binaire, mais les combinaisons de HW_BREAKPOINT_R ou
HW_BREAKPOINT_W avec HW_BREAKPOINT_X ne sont pas permises.
- bp_addr (depuis
Linux 2.6.33)
- Il s'agit de l'adresse du point d'arrêt. Pour les points
d'arrêt d'exécution, c'est l'adresse mémoire de
l'instruction d'intérêt ; pour les points
d'arrêt de lecture et écriture, c'est l'adresse
mémoire de l'emplacement mémoire
d'intérêt.
- config1 (depuis
Linux 2.6.39)
- config1 est utilisé pour définir des
événements qui ont besoin d'un registre
supplémentaire ou qui sinon ne rentrent pas dans le champ
config normal. OFFCORE_EVENTS brut sur Nehalem/Westmere/SandyBridge
utilise ce champ sur Linux 3.3 et les noyaux suivants.
- bp_len (depuis
Linux 2.6.33)
- bp_len est la taille du point d'arrêt mesuré si
type est PERF_TYPE_BREAKPOINT. Les options sont
HW_BREAKPOINT_LEN_1, HW_BREAKPOINT_LEN_2,
HW_BREAKPOINT_LEN_4 et HW_BREAKPOINT_LEN_8. Pour un point
d'arrêt, définissez-la à sizeof(long).
- config2 (depuis
Linux 2.6.39)
- config2 est une extension supplémentaire du champ
config1.
- branch_sample_type
(depuis Linux 3.4)
- Si PERF_SAMPLE_BRANCH_STACK est activé, alors cela indique
les branchements à inclure dans l’enregistrement de
branchements.
- La première partie de la valeur est le niveau de droits qui est une
combinaison d’une des valeurs suivantes. Si l’utilisateur ne
définit pas explicitement le niveau de droits, le noyau utilisera
celui de l’événement. Les niveaux de droits de
l’événement et du branchement ne doivent pas
nécessairement correspondre.
- sample_regs_user
(depuis Linux 3.7)
- Ce masque binaire définit l’ensemble des registres
processeur utilisateur à renvoyer dans les échantillons. La
disposition du masque de registre est spécifique à
l’architecture et définie dans l’en-tête du
noyau arch/ARCH/include/uapi/asm/perf_regs.h.
- sample_stack_user
(depuis Linux 3.7)
- Cela définit la taille de la pile utilisateur à renvoyer si
PERF_SAMPLE_STACK_USER est indiqué.
- clockid (depuis
Linux 4.1)
- Si use_clockid est positionné, ce champ sélectionne
l'horloge interne de Linux à utiliser pour les horodatages. Les
horloges disponibles sont définies dans linux/time.h,
où sont actuellement prises en charge CLOCK_MONOTONIC,
CLOCK_MONOTONIC_RAW, CLOCK_REALTIME, CLOCK_BOOTTIME
et CLOCK_TAI.
- aux_watermark
(depuis Linux 4.1)
- Cela indique la quantité de données nécessaires pour
récupérer un échantillonnage
PERF_RECORD_AUX.
- sample_max_stack
(depuis Linux 4.8)
- Quand sample_type comprend PERF_SAMPLE_CALLCHAIN, ce champ
indique le nombre de trames de pile à rendre compte lors de la
génération de la chaîne d'appels.
- aux_sample_size
(depuis Linux 5.5)
- Quand l'attribut PERF_SAMPLE_AUX est défini,
spécification de la taille souhaitée aux données AUX.
Notez qu'il peut recevoir des données plus petites que la taille
indiquée.
- sig_data
(depuis Linux 5.13)
- Cette donnée sera copiée vers le gestionnaire de signal de
l'utilisateur (au moyen de si_perf dans siginfo_t ) pour
disambiguïser l'événement qui a
déclenché le signal.
Une fois qu'un descripteur de fichier perf_event_open() a
été ouvert, les valeurs des événements peuvent
être lues depuis le descripteur de fichier. Les valeurs
présentes sont indiquées par le champ read_format de la
structure attr au moment de l'ouverture.
Si vous essayez de lire un tampon utilisé pour la lecture
qui n'est pas assez grand pour contenir les données, ENOSPC
est renvoyé.
Voici la disposition des données renvoyées par une
lecture :
- •
- Si PERF_FORMAT_GROUP a été indiqué pour
permettre de lire tous les événements d'un groupe en une
fois :
-
struct read_format {
u64 nr; /* Le nombre d'événements */
u64 time_enabled; /* si PERF_FORMAT_TOTAL_TIME_ENABLED */
u64 time_running; /* si PERF_FORMAT_TOTAL_TIME_RUNNING */
struct
u64 value; /* La valeur de l'événement */
u64 id; /* si PERF_FORMAT_ID */
u64 lost; /* si PERF_FORMAT_LOST */
} values[nr];
};
- •
- Si PERF_FORMAT_GROUP n'a pas été
indiqué :
-
struct read_format {
u64 value; /* La valeur de l'événement */
u64 time_enabled; /* si PERF_FORMAT_TOTAL_TIME_ENABLED */
u64 time_running; /* si PERF_FORMAT_TOTAL_TIME_RUNNING */
u64 id; /* si PERF_FORMAT_ID */
u64 lost; /* si PERF_FORMAT_LOST */
};
Les valeurs lues sont les suivantes.
- nr
- Le nombre d'événements dans le descripteur de fichier.
Seulement disponible si PERF_FORMAT_GROUP a été
indiqué.
- time_enabled,
time_running
- Temps total pendant lequel l'événement a été
activé et exécuté. Normalement ce sont les
mêmes. Si plus d'événements sont
démarrés que d'emplacements de compteur disponibles sur la
PMU, alors il y a multiplexage et les événements ne sont pas
exécutés tout le temps. Dans ce cas, les valeurs
time_enabled et time running peuvent être
utilisées pour estimer une valeur d'ordre de grandeur du
décompte.
- value
- Une valeur positive sur 64 bits contenant le résultat du
compteur.
- id
- Une valeur unique globale pour cet événement en particulier,
seulement si PERF_FORMAT_ID a été indiqué dans
read_format.
- lost
- Le nombre des échantillons perdus de cet
événement ; seulement si PERF_FORMAT_LOST a
été indiqué dans read_format.
En utilisant perf_event_open() en mode
d'échantillonnage, les événements asynchrones (comme un
dépassement de compteur ou un suivi mmap PROT_EXEC) sont
journalisés dans un tampon circulaire. Ce tampon circulaire est
créé et accédé à l'aide de
mmap(2).
La taille de mmap devrait être 1+2^n pages,
où la première page est une page de métadonnées
(struct perf_event_mmap_page) qui contient plusieurs informations
comme l'emplacement de la tête du tampon circulaire.
Avant Linux 2.6.39, un bogue oblige à allouer un
tampon circulaire mmap lors de l'échantillonnage même s'il
n'est pas prévu de l'utiliser.
La structure de la première page mmap de
métadonnées est la suivante :
struct perf_event_mmap_page {
__u32 version; /* numéro de version de la structure */
__u32 compat_version; /* plus petite version compatible */
__u32 lock; /* seqlock pour synchronisation */
__u32 index; /* identifiant de compteur matériel */
__s64 offset; /* ajouter au compteur matériel */
__u64 time_enabled; /* temps d'événement actif */
__u64 time_running; /* temps d'événement sur processeur */
union {
__u64 capabilities;
struct {
__u64 cap_usr_time / cap_usr_rdpmc / cap_bit0 : 1,
cap_bit0_is_deprecated : 1,
cap_user_rdpmc : 1,
cap_user_time : 1,
cap_user_time_zero : 1,
};
};
__u16 pmc_width;
__u16 time_shift;
__u32 time_mult;
__u64 time_offset;
__u64 __reserved[120]; /* remplissage à 1 k */
__u64 data_head; /* tête de la section de données */
__u64 data_tail; /* queue écrite en espace utilisateur */
__u64 data_offset; /* où commence le tampon */
__u64 data_size; /* taille du tampon de données */
__u64 aux_head;
__u64 aux_tail;
__u64 aux_offset;
__u64 aux_size;
}
}
La liste suivante décrit les champs de la structure
perf_event_mmap_page plus précisément.
- version
- Numéro de version de cette structure.
- compat_version
- La plus petite version avec laquelle elle est compatible.
- lock
- Un seqlock (sequence lock) pour la synchronisation.
- index
- Un identifiant unique de compteur matériel.
- décalage
- Quand l’instruction rdpmc est utilisée pour lire, cette
valeur de position doit être ajoutée à celle
renvoyée par rdpmc pour obtenir le décompte total actuel
d’événements.
- time_enabled
- Temps d'activité de l'événement.
- time_running
- Temps d'exécution de l'événement.
- cap_usr_time
/ cap_usr_rdpmc / cap_bit0 (depuis Linux 3.4)
- Un bogue existait dans la définition de cap_usr_time et
cap_usr_rdpmc de Linux 3.4 à Linux 3.11. Les
deux bits étaient définis pour pointer vers le même
endroit, il était donc impossible de savoir si cap_usr_time
ou cap_usr_rdpmc étaient vraiment définis.
- Depuis Linux 3.12, ils ont été renommés en
cap_bit0 et vous devriez plutôt utiliser les nouveaux champs
cap_user_time et cap_user_rdpmc à la place.
- cap_bit0_is_deprecated
(depuis Linux 3.12)
- Si défini, ce bit indique que le noyau est capable de gérer
les bits cap_user_time et cap_user_rdpmc
différenciés correctement.
- Si non, cela indique qu’il s’agit d’un ancien noyau
où cap_usr_time et cap_usr_rdpmc pointent vers le
même bit et donc que ces deux fonctionnalités devraient
être utilisées avec prudence.
- cap_usr_rdpmc
(depuis Linux 3.12)
- Si le matériel permet la lecture en espace utilisateur des
compteurs de performance sans appel système (c'est l'instruction
« rdpmc » sur x86), alors le code suivant peut
être utilisé pour faire une lecture :
-
u32 seq, time_mult, time_shift, idx, width;
u64 count, enabled, running;
u64 cyc, time_offset;
do {
seq = pc->lock;
barrier();
enabled = pc->time_enabled;
running = pc->time_running;
if (pc->cap_usr_time && enabled != running) {
cyc = rdtsc();
time_offset = pc->time_offset;
time_mult = pc->time_mult;
time_shift = pc->time_shift;
}
idx = pc->index;
count = pc->offset;
if (pc->cap_usr_rdpmc && idx) {
width = pc->pmc_width;
count += rdpmc(idx - 1);
}
barrier();
} while (pc->lock != seq);
- cap_user_time
(depuis Linux 3.12)
- Ce bit indique que le matériel a un compteur temporel sans
arrêt, constant (TSC sur x86).
- cap_usr_time_zero
(depuis Linux 3.12)
- Indique la présence de time_zero qui permet
d’associer les valeurs d’horodatage à
l’horloge matérielle.
- pmc_width
- Si cap_usr_rdpmc, ce champ fournit la taille en bit de la valeur
lue en utilisant l'instruction rdpmc ou équivalente. Cela permet
d'étendre avec signe le résultat comme ceci :
-
pmc <<= 64 - pmc_width;
pmc >>= 64 - pmc_width; // déplacement du signe à droite
count += pmc;
- time_shift,
time_mult, time_offset
- Si cap_usr_time, ces champs peuvent être utilisés
pour calculer la différence de temps depuis time_enabled (en
nanoseconde) en utilisant rdtsc ou similaire.
-
u64 quot, rem;
u64 delta;
quot = cyc >> time_shift;
rem = cyc & (((u64)1 << time_shift) - 1);
delta = time_offset + quot * time_mult +
((rem * time_mult) >> time_shift);
- Où time_offset, time_mult, time_shift et
cyc sont lus dans la boucle seqcount décrite ci-dessus.
Cette différence peut être ajoutée à
enabled et éventuellement running (si idx), pour
améliorer l'échelle :
-
enabled += delta;
if (idx)
running += delta;
quot = count / running;
rem = count % running;
count = quot * enabled + (rem * enabled) / running;
- time_zero
(depuis Linux 3.12)
- Si cap_usr_time_zero est défini, alors l'horloge
matérielle (le compteur temporel TSC sur x86) peut être
calculée à partir des valeurs time_zero,
time_mult et time_shift :
-
time = timestamp - time_zero;
quot = time / time_mult;
rem = time % time_mult;
cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
- et vice versa :
-
quot = cyc >> time_shift;
rem = cyc & (((u64)1 << time_shift) - 1);
timestamp = time_zero + quot * time_mult +
((rem * time_mult) >> time_shift);
- data_head
- Cela pointe vers la tête de la section de données. La valeur
augmente continuellement, elle n'est pas coupée. Vous devrez couper
vous-même la valeur à la taille du tampon mmap avant
d'accéder aux échantillons.
- Sur les plateformes compatibles SMP, après la lecture de la valeur
data_head, l'espace utilisateur devrait renvoyer un rmb().
- data_tail
- Quand l'association est PROT_WRITE, la valeur data_tail
devrait être écrite par l'espace utilisateur pour
refléter les dernières données lues. Dans ce cas, le
noyau n'écrasera pas les données non lues.
- data_offset
(depuis Linux 4.1)
- Contient la position de l'emplacement du tampon mmap où les
données de l'échantillon de perf commencent.
- data_size
(depuis Linux 4.1)
- Contient la taille de la zone de l'échantillon de perf dans le
tampon mmap.
- aux_head,
aux_tail, aux_offset, aux_size (depuis Linux
4.1)
- La zone AUX permet d'appliquer à un mmap(2) un tampon
d'échantillonnage distinct pour les flux de données à
forte bande passante (séparément du tampon
d'échantillonnage de perf principal). Un exemple de flux à
forte bande passante est la prise en charge du traçage d'une
instruction telle qu'elle se fait dans les nouveaux processeurs
Intel.
- Pour définir une zone AUX, il faut d'abord positionner
aux_offset à une position supérieure à
data_offset+data_size puis positionner aux_size
à la taille de tampon désirée. La position et la
taille désirée doivent être alignées sur la
page et la taille doit être une puissance de deux. Ces valeurs sont
alors passées à mmap pour projeter le tampon AUX. Les pages
du tampon AUX sont comprises dans la limite de ressource
RLIMIT_MEMLOCK (voir setrlimit(2)) et dans la gestion des
droits perf_event_mlock_kb.
- Par défaut, le tampon AUX sera tronqué s'il ne rentre pas
dans l'espace disponible du tampon circulaire. Si le tampon AUX est
projeté en tant que tampon en lecture seule, il agira dans le mode
du tampon circulaire là où les données seront
remplacées par de nouvelles. En mode remplacement, il se pourrait
qu'il ne soit pas possible de présumer l'endroit où
commencent les données et il appartient au consommateur de
désactiver la mesure pendant la lecture pour éviter les
possibles collisions de données.
- Les pointeurs de tampon circulaire aux_head et aux_tail ont
le même comportement et les mêmes règles
d'organisation que celles décrites précédemment pour
data_head et data_tail.
Les 2^n pages suivantes du tampon circulaire ont la
disposition décrite ci-dessous.
Si perf_event_attr.sample_id_all est défini, alors
tous les types d'événements auront les champs
sample_type sélectionnés relatifs à
l'emplacement et à la date (identité) où un
événement a eu lieu (TID, TIME, ID, CPU, STREAM_ID)
conformément à la description de PERF_RECORD_SAMPLE
ci-dessous, il sera stocké juste après le
perf_event_header et les champs déjà présents
pour les champs existants, c'est-à-dire à la fin de la charge
utile. De cette façon, un nouveau perf.data sera pris en charge par
les outils de performances plus anciens, avec ces nouveaux champs
facultatifs ignorés.
Les valeurs mmap commencent par un en-tête :
struct perf_event_header {
__u32 type;
__u16 misc;
__u16 size;
};
Les champs perf_event_header sont décrits plus
précisément ci-dessous. Par commodité de lecture, les
champs avec les descriptions les plus courtes sont d’abord
présentés.
- size
- Cela indique la taille de l'enregistrement.
- misc
- Le champ misc contient des renseignements supplémentaires
sur l'échantillon.
- Le mode de processeur peut être déterminé à
partir de cette valeur en la masquant avec
PERF_RECORD_MISC_CPUMODE_MASK et en recherchant un des suivants
(remarquez que ce ne sont pas des masques de bits, un seul peut
être défini à la fois).
- type
- La valeur type est une des suivantes. Les valeurs dans
l'enregistrement correspondant (qui suit l'en-tête)
dépendent du type sélectionné comme c'est
montré.
- PERF_RECORD_MMAP
- Les événements MMAP enregistrent les associations
PROT_EXEC pour pouvoir mettre en corrélation les pointeurs
d'instruction en espace utilisateur et le code. Ils ont la structure
suivante :
-
struct {
struct perf_event_header header;
u32 pid, tid;
u64 addr;
u64 len;
u64 pgoff;
char filename[];
};
- pid
- est l'identifiant de processus.
- tid
- est l'identifiant de thread.
- addr
- est l'adresse de la mémoire allouée. len est la
taille de la mémoire allouée. pgoff est la position
de la page de la mémoire allouée. filename est une
chaîne décrivant la base de la mémoire
allouée.
- PERF_RECORD_LOST
- Cet enregistrement indique quand des événements sont
perdus.
-
struct {
struct perf_event_header header;
u64 id;
u64 lost;
struct sample_id sample_id;
};
- id
- est l'identifiant unique d'événement pour les
échantillons perdus.
- lost
- est le nombre d'événements perdus.
- PERF_RECORD_COMM
- Cet enregistrement indique une modification du nom de processus.
-
struct {
struct perf_event_header header;
u32 pid;
u32 tid;
char comm[];
struct sample_id sample_id;
};
- pid
- est l'identifiant de processus.
- tid
- est l'identifiant de thread.
- comm
- est une chaîne contenant le nouveau nom du processus.
- PERF_RECORD_EXIT
- Cet enregistrement indique un événement de fin de
processus.
-
struct {
struct perf_event_header header;
u32 pid, ppid;
u32 tid, ptid;
u64 time;
struct sample_id sample_id;
};
- PERF_RECORD_THROTTLE,
PERF_RECORD_UNTHROTTLE
- Cet enregistrement indique un événement de variation de
fréquence du processeur.
-
struct {
struct perf_event_header header;
u64 time;
u64 id;
u64 stream_id;
struct sample_id sample_id;
};
- PERF_RECORD_FORK
- Cet enregistrement indique un événement de création
d’enfant.
-
struct {
struct perf_event_header header;
u32 pid, ppid;
u32 tid, ptid;
u64 time;
struct sample_id sample_id;
};
- PERF_RECORD_READ
- Cet enregistrement indique un événement de lecture.
-
struct {
struct perf_event_header header;
u32 pid, tid;
struct read_format values;
struct sample_id sample_id;
};
- PERF_RECORD_SAMPLE
- Cet enregistrement indique un échantillon.
-
struct {
struct perf_event_header header;
u64 sample_id; /* if PERF_SAMPLE_IDENTIFIER */
u64 ip; /* if PERF_SAMPLE_IP */
u32 pid, tid; /* if PERF_SAMPLE_TID */
u64 time; /* if PERF_SAMPLE_TIME */
u64 addr; /* if PERF_SAMPLE_ADDR */
u64 id; /* if PERF_SAMPLE_ID */
u64 stream_id; /* if PERF_SAMPLE_STREAM_ID */
u32 cpu, res; /* if PERF_SAMPLE_CPU */
u64 period; /* if PERF_SAMPLE_PERIOD */
struct read_format v;
/* if PERF_SAMPLE_READ */
u64 nr; /* if PERF_SAMPLE_CALLCHAIN */
u64 ips[nr]; /* if PERF_SAMPLE_CALLCHAIN */
u32 size; /* if PERF_SAMPLE_RAW */
char data[size]; /* if PERF_SAMPLE_RAW */
u64 bnr; /* if PERF_SAMPLE_BRANCH_STACK */
struct perf_branch_entry lbr[bnr];
/* if PERF_SAMPLE_BRANCH_STACK */
u64 abi; /* if PERF_SAMPLE_REGS_USER */
u64 regs[weight(mask)];
/* if PERF_SAMPLE_REGS_USER */
u64 size; /* if PERF_SAMPLE_STACK_USER */
char data[size]; /* if PERF_SAMPLE_STACK_USER */
u64 dyn_size; /* if PERF_SAMPLE_STACK_USER &&
size != 0 */
union perf_sample_weight weight;
/* if PERF_SAMPLE_WEIGHT */
/* || PERF_SAMPLE_WEIGHT_STRUCT */
u64 data_src; /* if PERF_SAMPLE_DATA_SRC */
u64 transaction; /* if PERF_SAMPLE_TRANSACTION */
u64 abi; /* if PERF_SAMPLE_REGS_INTR */
u64 regs[weight(mask)];
/* if PERF_SAMPLE_REGS_INTR */
u64 phys_addr; /* if PERF_SAMPLE_PHYS_ADDR */
u64 cgroup; /* if PERF_SAMPLE_CGROUP */
u64 data_page_size;
/* if PERF_SAMPLE_DATA_PAGE_SIZE */
u64 code_page_size;
/* if PERF_SAMPLE_CODE_PAGE_SIZE */
u64 size; /* if PERF_SAMPLE_AUX */
char data[size]; /* if PERF_SAMPLE_AUX */
};
- sample_id
- Si PERF_SAMPLE_IDENTIFIER est activé, un identifiant unique
sur 64 bits est inclus. C’est une copie de la valeur
id de PERF_SAMPLE_ID, mais incluse au début de
l’échantillon pour permettre aux analyseurs d’obtenir
facilement la valeur.
- ip
- Si PERF_SAMPLE_IP est activé, alors une valeur de pointeur
d'instruction sur 64 bits est incluse.
- pid,
tid
- Si PERF_SAMPLE_TID est activé, alors un identifiant de
processus sur 32 bits et un identifiant de thread sur
32 bits sont inclus.
- time
- Si PERF_SAMPLE_TIME est activé, alors un horodatage sur
64 bits est inclus. C'est obtenu à l'aide de local_clock()
qui est un horodatage matériel si disponible et la valeur
jiffy sinon.
- addr
- Si PERF_SAMPLE_ADDR est activé, alors une adresse sur
64 bits est incluse. C'est généralement l'adresse
d'un point de trace, point d'arrêt ou événement
logiciel ; sinon la valeur est 0.
- id
- Si PERF_SAMPLE_ID est activé, un identifiant unique sur
64 bits est inclus. Si l'événement est membre d'un
groupe d'événements, l'identifiant du leader de groupe est
renvoyé. Cet identifiant est le même que celui
renvoyé par PERF_FORMAT_ID.
- stream_id
- Si PERF_SAMPLE_STREAM_ID est activé, un identifiant unique
sur 64 bits est inclus. Contrairement à
PERF_SAMPLE_ID, le véritable identifiant est renvoyé,
pas celui du leader de groupe. Cet identifiant est le même que
celui renvoyé par PERF_FORMAT_ID.
- cpu, res
- Si PERF_SAMPLE_CPU est activé, c'est une valeur sur
32 bits indiquant le processeur qui a été
utilisé, en supplément d'une valeur réservée
(non utilisée) sur 32 bits.
- period
- Si PERF_SAMPLE_PERIOD est activé, une valeur sur
64 bits indiquant la période d'échantillonnage
actuelle est écrite.
- v
- Si PERF_SAMPLE_READ est activé, une structure de type
read_format est incluse avec des valeurs pour tous les
événements du groupe d'événements. Les valeurs
incluses dépendent de la valeur read_format utilisée
au moment de perf_event_open().
- nr,
ips[nr]
- Si PERF_SAMPLE_CALLCHAIN est activé, alors un nombre sur
64 bits est inclus, indiquant le nombre de pointeurs d'instruction
sur 64 bits qui suivent. C'est l'appel en chaîne
actuel.
- size,
data[size]
- Si PERF_SAMPLE_RAW est activé, alors une valeur sur
32 bits indiquant la taille est incluse, suivie par un tableau de
valeurs sur 8 bits de taille size. Les valeurs sont remplies
avec des 0 pour avoir un alignement à 64 bits.
- Ces données brutes d'enregistrement sont opaques du point de vue de
l'ABI. L'ABI ne fait pas de promesses sur la stabilité de son
contenu qui pourrait varier en fonction de l'événement, du
matériel ou de la version du noyau.
- bnr,
lbr[bnr]
- Si PERF_SAMPLE_BRANCH_STACK est activé, alors une valeur de
64 bits indiquant le nombre d'enregistrements est incluse, suivie
des structures bnr perf_branch_entry qui chacune contient
les champs suivants.
- from
- Cela indique l’instruction source (qui pourrait ne pas être
un branchement).
- to
- La cible de branchement.
- mispred
- La cible de branchement a été mal prédite.
- predicted
- La cible de branchement a été prédite.
- in_tx (depuis Linux
3.11)
- Le branchement était dans une transaction de mémoire
transactionnelle.
- abort (depuis Linux
3.11)
- Le branchement était dans une transaction abandonnée de
mémoire transactionnelle.
- cycles (depuis
Linux 4.3)
- Cela rend compte du nombre de cycles qui se sont déroulés
depuis la dernière mise à jour de la pile de
branchement.
Les entrées sont présentées dans
l’ordre chronologique, de telle sorte que la première
entrée a le branchement le plus récent.
La prise en charge de mispred, predicted et
cycles est facultative. En absence de prise en charge, les deux
valeurs seront 0.
Le type de branchements enregistrés est indiqué par
le champ branch_sample_type.
- abi,
regs[weight(mask)]
- Si PERF_SAMPLE_REGS_USER est activé, alors les registres
processeur utilisateur sont enregistrés.
- Le champ abi est parmi PERF_SAMPLE_REGS_ABI_NONE,
PERF_SAMPLE_REGS_ABI_32 ou PERF_SAMPLE_REGS_ABI_64.
- Le champ regs est un tableau de registres processeur qui ont
été indiqués par le champ attr
sample_regs_user. Le nombre de valeurs est le nombre de bits
définis dans le masque binaire sample_regs_user.
- size,
data[size], dyn_size
- Si PERF_SAMPLE_STACK_USER est activé, la pile utilisateur
est enregistrée. Cela peut être utilisé pour
générer les backtraces de la pile. size est la taille
demandée par l’utilisateur dans sample_stack_user ou
autrement la taille maximale d’enregistrement. data contient
les données de pile (un contenu brut de la mémoire
indiquée par le pointeur de pile au moment de
l'échantillonnage). dyn_size est la quantité de
données vraiment renvoyée (peut être
inférieure à size). Remarquez que dyn_size est
omis si size vaut 0.
- weight
- Si PERF_SAMPLE_WEIGHT ou PERF_SAMPLE_WEIGHT_STRUCT sont
activés, une valeur de 64 bits fournie par le
matériel est enregistrée pour indiquer le coût de
l’événement. Cela permet aux événements
coûteux de ressortir plus clairement dans les profils.
- data_src
- Si PERF_SAMPLE_DATA_SRC est activé, alors une valeur de
64 bits est enregistrée, constituée des champs
suivants.
- mem_op
- Type de code opération (opcode), une combinaison bit à bit
de :
- mem_lvl
- Niveau de hiérarchie de mémoire atteint ou raté, une
combinaison bit à bit de ce qui suit, envoyés à
gauche par PERF_MEM_LVL_SHIFT :
- mem_snoop
- Mode espionnage, une combinaison bit-à-bit de ce qui suit,
décalé vers la gauche par
PERF_MEM_SNOOP_SHIFT :
- mem_lock
- Instruction de verrouillage, une combinaison bit à bit de ce qui
suit, renvoyée vers la gauche par
PERF_MEM_LOCK_SHIFT :
- mem_dtlb
- Accès TLB atteint ou raté, une combinaison bit à bit
de ce qui suit, renvoyée vers la gauche par
PERF_MEM_TLB_SHIFT :
- transaction
- Si l’attribut PERF_SAMPLE_TRANSACTION est défini,
alors un champ de 64 bits est enregistré pour décrire
les sources de tous les abandons de mémoire transactionnelle.
- Le champ est une combinaison bit à bit des valeurs
suivantes :
- De plus, un code d’abandon spécifique à
l’utilisateur peut être obtenu à partir des premiers
32 bits du champ en déplaçant vers la droite avec
PERF_TXN_ABORT_SHIFT et en masquant avec
PERF_TXN_ABORT_MASK.
- abi,
regs[weight(mask)]
- Si PERF_SAMPLE_REGS_INTR est activé, alors les registres
processeur utilisateur sont enregistrés.
- Le champ abi est parmi PERF_SAMPLE_REGS_ABI_NONE,
PERF_SAMPLE_REGS_ABI_32 ou PERF_SAMPLE_REGS_ABI_64.
- Le champ regs est un tableau des registres processeur qui ont
été indiqués par le champ attr
sample_regs_intr. Le nombre de valeurs est le nombre de bits
définis dans le masque binaire sample_regs_intr.
- phys_addr
- Si l'attribut PERF_SAMPLE_PHYS_ADDR est positionné,
l'adresse physique en 64 bits est enregistrée.
- cgroup
- Si l'attribut PERF_SAMPLE_CGROUP est positionné,
l'identifiant de cgroup 64 bits (pour le sous-système
perf_event) est enregistré. Pour récupérer le chemin
du cgroup, l'identifiant doit correspondre à un de ceux se trouvant
dans PERF_RECORD_CGROUP.
- data_page_size
- Si l'attribut PERF_SAMPLE_DATA_PAGE_SIZE est positionné, la
valeur en 64 bits de la taille de la page de l'adresse de
data est enregistrée.
- code_page_size
- Si l'attribut PERF_SAMPLE_CODE_PAGE_SIZE est positionné, la
valeur en 64 bits de la taille de la page de l'adresse ip
est enregistrée.
- size
- data[size]
- Si PERF_SAMPLE_AUX est activé, alors un instantané du
tampon aux est enregistré.
- PERF_RECORD_MMAP2
- Cet enregistrement inclut des informations étendues sur les appels
mmap(2) renvoyant des projections exécutables. Le format est
identique à celui de l'enregistrement PERF_RECORD_MMAP mais
il comprend des valeurs supplémentaires qui permettent uniquement
d'identifier des projections partagées. Selon le bit
PERF_RECORD_MISC_MMAP_BUILD_ID dans l'en-tête, les valeurs
supplémentaires ont des présentations et des significations
différentes.
-
struct {
struct perf_event_header header;
u32 pid;
u32 tid;
u64 addr;
u64 len;
u64 pgoff;
union {
struct {
u32 maj;
u32 min;
u64 ino;
u64 ino_generation;
};
struct { /* if PERF_RECORD_MISC_MMAP_BUILD_ID */
u8 build_id_size;
u8 __reserved_1;
u16 __reserved_2;
u8 build_id[20];
};
};
u32 prot;
u32 flags;
char filename[];
struct sample_id sample_id;
};
- pid
- est l'identifiant de processus.
- tid
- est l'identifiant de thread.
- addr
- est l'adresse de la mémoire allouée.
- len
- est la taille de la mémoire allouée.
- pgoff
- est la position de la page de la mémoire allouée.
- maj
- est l'identifiant majeur du périphérique sous-jacent.
- min
- est l'identifiant mineur du périphérique sous-jacent.
- ino
- est le numéro d'inœud.
- ino_generation
- est la génération d'inœud.
- build_id_size
- est la taille réelle du champ build_id (jusqu'à
20).
- build_id
- ce sont des données brutes pour identifier un binaire.
- prot
- sont les informations de protection.
- drapeaux
- sont les informations d'attributs.
- filename
- est une chaîne décrivant la base de la mémoire
allouée.
- PERF_RECORD_AUX
(depuis Linux 4.1)
- Cet enregistrement rend compte des nouvelles données disponibles
dans la zone séparée du tampon AUX.
-
struct {
struct perf_event_header header;
u64 aux_offset;
u64 aux_size;
u64 flags;
struct sample_id sample_id;
};
- aux_offset
- position dans la zone mmap AUX où commencent les nouvelles
données.
- aux_size
- taille des données disponibles.
- drapeaux
- décrit la mise à jour AUX.
- PERF_AUX_FLAG_TRUNCATED
- s'il est positionné, les données renvoyées ont
été tronquées pour rentrer dans la taille du tampon
disponible.
- PERF_AUX_FLAG_OVERWRITE
- s'il est positionné, les données renvoyées ont
écrasé des données précédentes.
- PERF_RECORD_ITRACE_START
(depuis Linux 4.1)
- Cet enregistrement indique le processus qui a initié un
événement de traçage d'instruction, permettant aux
outils de corréler correctement les adresses d'instruction du
tampon AUX avec le bon exécutable.
-
struct {
struct perf_event_header header;
u32 pid;
u32 tid;
};
- pid
- identifiant de processus du thread ayant commencé un traçage
d'instruction.
- tid
- identifiant du thread ayant commencé le traçage
d'instruction.
- PERF_RECORD_LOST_SAMPLES
(depuis Linux 4.2)
- Lors de l'utilisation de l'échantillonnage matériel (comme
les PEBS d'Intel), cet enregistrement indique le nombre
d'échantillons qui peuvent avoir été perdus.
-
struct {
struct perf_event_header header;
u64 lost;
struct sample_id sample_id;
};
- lost
- est le nombre d'échantillons potentiellement perdus.
- PERF_RECORD_SWITCH
(depuis Linux 4.3)
- Cet enregistrement indique qu'un changement de contexte a eu lieu. Le bit
PERF_RECORD_MISC_SWITCH_OUT du champ misc indique si ce
changement s'est fait dans ou hors du processus.
-
struct {
struct perf_event_header header;
struct sample_id sample_id;
};
- PERF_RECORD_SWITCH_CPU_WIDE
(depuis Linux 4.3)
- Comme avec PERF_RECORD_SWITCH, cet enregistrement indique qu'un
changement de contexte a eu lieu mais il n'arrive que lors de
l'échantillonnage en mode processeur complet et il fournit des
informations supplémentaires sur le processus faisant l'objet du
changement. Le bit PERF_RECORD_MISC_SWITCH_OUT du champ misc
indique si le changement a eu lieu dans ou hors du processus actuel.
-
struct {
struct perf_event_header header;
u32 next_prev_pid;
u32 next_prev_tid;
struct sample_id sample_id;
};
- next_prev_pid
- L'identifiant du processus précédent ou suivant (selon le
sens du changement) sur le processeur.
- next_prev_tid
- L'identifiant du thread précédent ou suivant (selon le sens
du changement) sur le processeur.
- PERF_RECORD_NAMESPACES
(depuis Linux 4.11)
- Cet enregistrement comprend diverses informations sur l'espace de noms
d'un processus.
-
struct {
struct perf_event_header header;
u32 pid;
u32 tid;
u64 nr_namespaces;
struct { u64 dev, inode } [nr_namespaces];
struct sample_id sample_id;
};
- pid
- est l'identifiant de processus.
- tid
- est l'identifiant de thread.
- nr_namespace
- est le nombre d'espaces de noms de cet enregistrement.
- Chaque espace de noms a des champs dev et inode et il est
enregistré dans une position fixe comme celle
ci-dessous :
- PERF_RECORD_KSYMBOL
(depuis Linux 5.0)
- Cet enregistrement indique un événement
d'enregistrement/désenregistrement des symboles du noyau.
-
struct {
struct perf_event_header header;
u64 addr;
u32 len;
u16 ksym_type;
u16 flags;
char name[];
struct sample_id sample_id;
};
- addr
- est l'adresse du symbole du noyau.
- len
- est la taille du symbole du noyau.
- ksym_type
- est le type de symbole du noyau. Actuellement, les types suivants sont
disponibles :
- drapeaux
- Si PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER est positionné, cet
événement se produit lors du désenregistrement d'un
symbole du noyau.
- PERF_RECORD_BPF_EVENT
(depuis Linux 5.0)
- Cet enregistrement indique si un programme BPF est chargé ou
déchargé.
-
struct {
struct perf_event_header header;
u16 type;
u16 flags;
u32 id;
u8 tag[BPF_TAG_SIZE];
struct sample_id sample_id;
};
- type
- est une des valeurs suivantes :
- id
- est l'identifiant du programme BPF.
- tag
- est l'étiquette du programme BPF. Actuellement, BPF_TAG_SIZE
est défini à 8.
- PERF_RECORD_CGROUP
(depuis Linux 5.7)
- Cet enregistrement indique si un cgroup est créé et
activé.
-
struct {
struct perf_event_header header;
u64 id;
char path[];
struct sample_id sample_id;
};
- id
- est l'identifiant du cgroup. Il peut aussi être
récupéré à l'aide de
name_to_handle_at(2) sur le chemin du cgroup (en tant que gestion
de fichier).
- path
- est le chemin du cgroup depuis la racine.
- PERF_RECORD_TEXT_POKE
(depuis Linux 5.8)
- Cet enregistrement indique une modification dans le texte du noyau. Cela
comprend les ajouts et les suppressions de texte et la taille
correspondante est de zéro dans ce cas.
-
struct {
struct perf_event_header header;
u64 addr;
u16 old_len;
u16 new_len;
u8 bytes[];
struct sample_id sample_id;
};
- addr
- est l'adresse de la modification.
- old_len
- est l'ancienne taille.
- new_len
- est la nouvelle taille.
- bytes
- contient les anciens octets immédiatement suivis des nouveaux.
Des événements peuvent être
positionnés pour signaler quand on dépasse une limite,
indiquant un dépassement. Les conditions d'un dépassement
peuvent être récupérées avec poll(2),
select(2) ou epoll(7). Alternativement, les
évènements de dépassement peuvent être
capturés à l'aide d'un gestionnaire de signal en activant les
signaux d'E/S sur le descripteur de fichier ; voir le point sur les
opérations F_SETOWN et F_SETSIG dans
fcntl(2).
Les débordements ne sont générés que
par les événements d'échantillonnage
(sample_period doit avoir une valeur non nulle).
Deux façons permettent de générer des
notifications de débordement.
La première est de paramétrer une valeur
wakeup_events ou wakeup_watermark qui générera
un signal si un certain nombre d'échantillons ou d'octets ont
été écrits dans le tampon circulaire mmap. Dans ce cas,
un signal de type POLL_IN est envoyé.
L'autre façon est d'utiliser l'ioctl
PERF_EVENT_IOC_REFRESH. Cet ioctl ajoute à un compteur qui
décrémente à chaque fois que l'événement
dépasse. Quand il est non nul, un signal POLL_IN est
envoyé en cas de dépassement, mais une fois que la valeur a
atteint 0, un signal de type POLL_HUP est envoyé et
l'événement sous-jacent est désactivé.
Le rafraîchissement d'un leader de groupe
d'événements rafraîchit toute la fratrie, et un
rafraîchissement avec un paramètre de 0 active un
rafraîchissement infini. Ces comportements ne sont pas
gérés et ne devraient pas être utilisés.
À partir de Linux 3.18, POLL_HUP est
initié si l'événement à surveiller est
rattaché à un processus différent et que celui-ci se
termine.
À partir de Linux 3.4 sur x86, l'instruction
rdpmc permet d'obtenir des lectures à faible latence sans
avoir à entrer dans le noyau. Remarquez que l'utilisation de
rdpmc n'est pas nécessairement plus rapide que d'autres
méthodes pour lire des valeurs d'événement.
Cette prise en charge peut être détectée avec
le champ cap_usr_rdpmc dans la page mmap ; de la documentation
pour calculer les valeurs d'événement est disponible dans
cette section.
À l'origine, quand la prise en charge de rdpmc a
été activée, tout processus (pas seulement ceux ayant
un événement perf actif) pouvait utiliser l'instruction rdpmc
pour accéder aux compteurs. À partir de Linux 4.0, la
prise en charge de rdpmc n'est autorisée que si un
événement est actuellement activé dans le contexte d'un
processus. Pour restaurer l'ancien comportement, inscrivez la valeur
2 dans /sys/devices/cpu/rdpmc.
Plusieurs ioctls agissent sur les descripteurs de fichier de
perf_event_open().
- PERF_EVENT_IOC_ENABLE
- Cela active l'événement individuel ou le groupe
d'événements indiqué par l'argument de descripteur de
fichier.
- Si le bit PERF_IOC_FLAG_GROUP est défini dans
l’argument ioctl, alors tous les événements
d’un groupe sont activés, même si
l’événement indiqué n’est pas le leader
de groupe (mais consultez la section BOGUES).
- PERF_EVENT_IOC_DISABLE
- Cela désactive le compteur individuel ou le groupe
d'événements indiqué par l'argument de descripteur de
fichier.
- L'activation ou la désactivation du leader d'un groupe active ou
désactive la totalité du groupe. Autrement dit pendant que
le leader de groupe est désactivé, aucun des compteurs du
groupe ne compte. L'activation ou la désactivation d'un membre du
groupe qui n'est pas le leader arrête ce son compteur, mais
n'affecte aucun des autres compteurs.
- Si le bit PERF_IOC_FLAG_GROUP est défini dans
l’argument ioctl, alors tous les événements
d’un groupe sont désactivés, même si
l’événement indiqué n’est pas le leader
de groupe (mais consultez la section BOGUES).
- PERF_EVENT_IOC_REFRESH
- Les compteurs de dépassements non hérités peuvent
utiliser cela pour activer un compteur pour un nombre de
dépassements indiqué par l'argument, après lequel il
est désactivé. Les appels suivants de cet ioctl ajoutent la
valeur de l'argument au décompte actuel. Un signal avec
POLL_IN défini est envoyé à chaque
dépassement jusqu'à ce que ce compte atteigne
0 ; quand cela arrive, un signal avec POLL_HUP
défini est envoyé et l'événement est
désactivé. L'utilisation de 0 comme argument est
considéré comme un comportement indéfini.
- PERF_EVENT_IOC_RESET
- Redéfinir le compte d'événements indiqué par
l'argument à zéro. Cela ne réinitialise que les
décomptes ; réinitialiser les valeurs de multiplexage
time_enabled et time_running est impossible.
- Si le bit PERF_IOC_FLAG_GROUP est défini dans
l’argument ioctl, alors tous les événements
d’un groupe sont réinitialisés, même si
l’événement indiqué n’est pas le leader
de groupe (mais consultez la section BOGUES).
- PERF_EVENT_IOC_PERIOD
- Cela met à jour la période de dépassement pour
l’événement.
- Depuis Linux 3.7 (sur ARM) et Linux 3.14 (toutes les autres
architectures), la nouvelle période est effective
immédiatement. Sur les noyaux précédents, la nouvelle
période n’était effective qu’après le
dépassement suivant.
- L'argument est un pointeur vers une valeur sur 64 bits contenant la
nouvelle période voulue.
- Avant Linux 2.6.36, cet ioctl échouait toujours à
cause d’un bogue dans le noyau.
- PERF_EVENT_IOC_SET_OUTPUT
- Cela indique au noyau de signaler les notifications
d'événement dans le descripteur de fichier indiqué
plutôt que dans celui par défaut. Les descripteurs de
fichier doivent tous être sur le même processeur.
- L'argument indique le descripteur de fichier désiré ou
-1 si la sortie devrait être ignorée.
- PERF_EVENT_IOC_SET_FILTER
(depuis Linux 2.6.33)
- Cela ajoute un filtre ftrace à cet événement.
- L'argument est un pointeur vers le filtre ftrace voulu.
- PERF_EVENT_IOC_ID
(depuis Linux 3.12)
- Cela renvoie la valeur d’identifiant de
l’événement pour le descripteur de fichier
d’événement donné.
- L'argument est un pointeur vers un entier non signé de
64 bits pour garder le résultat.
- PERF_EVENT_IOC_SET_BPF
(depuis Linux 4.1)
- Cela permet de rattacher un programme Berkeley Packet Filter (BPF)
à un événement de traçage d'un kprobe
existant. Vous avez besoin des privilèges CAP_PERFMON
(depuis Linux 5.8) ou CAP_SYS_ADMIN pour utiliser cet
ioctl.
- Le paramètre est un descripteur de fichier de programme BPF
créé par un appel système bpf(2)
précédent.
- PERF_EVENT_IOC_PAUSE_OUTPUT
(depuis Linux 4.7)
- Cela permet de mettre en pause et de relancer le tampon circulaire d'un
événement. Un tampon mis en pause n'empêche pas la
génération d'échantillons mais il les
désactive. Les échantillons désactivés sont
considérés comme perdus et provoquent la
génération d'un PERF_RECORD_LOST si possible. Un
signal de dépassement peut toujours être
récupéré par l'échantillon
désactivé bien que le tampon circulaire reste vide.
- Le paramètre est un entier 32 bits non signé. Une
valeur autre que zéro met en pause le tampon circulaire alors
qu'une valeur de zéro réactive le tampon circulaire.
- PERF_EVENT_MODIFY_ATTRIBUTES
(depuis Linux 4.17)
- Cela permet de modifier un événement existant sans le
gaspillage de fermeture et réouverture d’un nouvel
événement. Actuellement, cela n'est pris en charge que pour
les événements de points d'arrêt.
- L'argument est un pointeur vers une structure perf_event_attr
contenant les paramètres de l'événement mis à
jour.
- PERF_EVENT_IOC_QUERY_BPF
(depuis Linux 4.16)
- Cela permet de chercher les programmes Berkeley Packet Filter (BPF)
rattachés à un point de traçage kprobe existant. Vous
ne pouvez rattacher qu'un programme BPF par événement mais
vous pouvez avoir plusieurs événements rattachés
à un point de traçage. Rechercher cette valeur sur un
événement de point de traçage renvoie l'identifiant
de tous les programmes BPF dans tous les événements
rattachés au point de traçage. Il vous faut les
privilèges CAP_PERFMON (depuis Linux 5.8) ou
CAP_SYS_ADMIN pour utiliser cet ioctl.
- L'argument est un pointeur vers une structure
struct perf_event_query_bpf {
__u32 ids_len;
__u32 prog_cnt;
__u32 ids[0];
};
- Le champ ids_len indique le nombre d'identifiants pouvant entrer
dans le tableau ids fourni. La valeur prog_cnt est remplie
par le noyau avec le nombre de programmes BPF rattachés. Le tableau
ids est rempli par l'identifiant de chaque programme BPF
rattaché. S'il y a plus de programmes que de place dans le tableau,
le noyau renverra ENOSPC et ids_len indiquera le nombre
d'identifiants de programme copiés avec succès.
Un processus peut activer ou désactiver tous les groupes
d'événements actuellement ouverts en utilisant les
opérations PR_TASK_PERF_EVENTS_ENABLE et
PR_TASK_PERF_EVENTS_DISABLE de prctl(2). Cela ne s'applique
qu'aux événements créés localement par le
processus appelant. Cela ne s'applique pas aux événements
créés par d'autres processus rattachés au processus
appelant ou aux événements d'un processus parent. Cela
n'active et désactive que les leaders de groupe, aucun autre des
membres des groupes.
Fichiers de /proc/sys/kernel/
- /proc/sys/kernel/perf_event_paranoid
- Le fichier perf_event_paranoid peut être défini pour
restreindre l'accès aux compteurs de performance :
- 2
- ne permettre que les mesures en espace utilisateur (par défaut
depuis Linux 4.6).
- 1
- permettre à la fois les mesures noyau et utilisateur (par
défaut avant Linux 4.6).
- 0
- permettre l'accès aux données spécifiques au
processeur sauf les échantillons de point de trace
bruts ;
- -1
- pas de restriction.
- L'existence du fichier perf_event_paranoid est la méthode
officielle pour déterminer si un noyau gère
perf_event_open().
- /proc/sys/kernel/perf_event_max_sample_rate
- Cela définit le taux d'échantillonnage maximal. Un
réglage trop haut peut permettre aux utilisateurs
d'échantillonner à un taux ayant un impact sur les
performances de la machine et éventuellement planter la machine. La
valeur par défaut est 100 000 (échantillons par
seconde).
- /proc/sys/kernel/perf_event_max_stack
- Ce fichier définit la profondeur maximale des entrées de
trame de pile signalées lors de la génération d'une
trace.
- /proc/sys/kernel/perf_event_mlock_kb
- Le nombre maximal de pages qu'un utilisateur sans droit peut verrouiller
avec mlock(2). La valeur par défaut est
516 (ko).
Fichiers de /sys/bus/event_source/devices/
Depuis Linux 2.6.34, le noyau permet d'avoir
plusieurs PMU disponibles pour la surveillance. Les informations sur la
façon de programmer ces PMU sont disponibles dans
/sys/bus/event_source/devices/. Tous les sous-répertoires
correspondent à une PMU différente.
- /sys/bus/event_source/devices/*/type (depuis Linux 2.6.38)
- Cela contient un entier qui peut être utilisé dans le champ
type de perf_event_attr pour indiquer la volonté
d'utiliser cette PMU.
- /sys/bus/event_source/devices/cpu/rdpmc (depuis Linux 3.4)
- Si ce fichier est 1, alors l’accès direct de
l’espace utilisateur aux registres de compteurs de performance est
permis à l’aide de l’instruction rdpmc. Cela peut
être désactivé en écrivant 0 dans le
fichier.
- À partir de Linux 4.0, le comportement a changé pour
que 1 n'autorise désormais que l'accès aux processus
ayant des événements perf actifs et que 2 indique
l'ancien comportement autorisant l'accès à n'importe
quoi.
- /sys/bus/event_source/devices/*/format/ (depuis Linux 3.4)
- Ce sous-répertoire contient des renseignements sur les sous-champs
spécifiques à l’architecture disponibles pour la
programmation des divers champs config de la structure
perf_event_attr.
- Le contenu de chaque fichier est le nom du champ de configuration, suivi
d’un deux-points, suivi d’une suite d’intervalles
d’entiers séparés par des virgules. Par exemple, le
fichier event pourrait contenir la valeur config1:1,6-10,44
qui indique que l’événement est un attribut qui
occupe les bits 1, 6 à 10 et 44 de
perf_event_attr::config1.
- /sys/bus/event_source/devices/*/events/ (depuis Linux 3.4)
- Ce sous-répertoire contient des fichiers avec des
événements prédéfinis. Les contenus sont des
chaînes décrivant les réglages
d'événements exprimés en termes des champs
trouvés dans le répertoire ./format/ mentionné
précédemment. Ce ne sont pas nécessairement des
listes complètes de tous les évènements pris en
charge par une PMU, mais généralement un sous-ensemble
d'événements jugés utiles ou
intéressants.
- Le contenu de chaque fichier est une liste de noms d’attribut
séparés par des virgules. Chaque entrée a une valeur
facultative (soit hexadécimale, soit décimale). Si aucune
valeur n’est indiquée, alors un champ d’un seul bit
de valeur 1 est supposé. Un exemple d’entrée
pourrait ressembler à event=0x2,inv,ldlat=3.
- /sys/bus/event_source/devices/*/uevent
- Ce fichier est l’interface standard de périphérique
du noyau pour l’injection d’événements de
branchement à chaud.
- /sys/bus/event_source/devices/*/cpumask (depuis
Linux 3.7)
- Le fichier cpumask contient une liste d’entiers
séparés par des virgules indiquant un numéro
représentatif de processeur pour chaque socket (boîtier) de
la carte mère. C’est nécessaire lors de la
définition d’événements uncore ou northbridge,
puisque ces PMU présentent des événements à
travers tous les sockets.
L'option F_SETOWN_EX de fcntl(2) est
nécessaire pour obtenir correctement les signaux de
dépassement dans les threads. Cela a été introduit dans
Linux 2.6.32.
Avant Linux 3.3 (en tout cas pour x86), le noyau ne
vérifiait pas si les événements pouvaient être
programmés ensemble avant le moment de la lecture. La même
chose arrive sur tous les noyaux connus si le watchdog NMI est
activé. Cela signifie que pour voir si un ensemble donné
d'événements fonctionne, il faut appeler
perf_event_open(), démarrer, puis lire avant d'être
sûr de pouvoir obtenir des mesures valables.
Avant Linux 2.6.34, les contraintes
d'événements n'étaient pas renforcées par le
noyau. Dans ce cas, certains événements renverraient
« 0 » silencieusement si le noyau les avait
programmés dans un emplacement de compteur incorrect.
Avant Linux 2.6.34, à cause d'un bogue lors du
multiplexage, de mauvais résultats pouvaient être
renvoyés.
Les noyaux de Linux 2.6.35 à Linux 2.6.39
peuvent planter rapidement si inherit est activé et que de
nombreux threads sont démarrés.
Avant Linux 2.6.35, PERF_FORMAT_GROUP ne
fonctionnait pas avec les processus attachés.
À cause d'un bogue dans le code du noyau entre
Linux 2.6.36 et Linux 3.0, le champ watermark
était ignoré et agissait comme si wakeup_event avait
été choisi si l'union contenait une valeur non nulle.
De Linux 2.6.31 à Linux 3.4,
l’argument ioctl PERF_IOC_FLAG_GROUP était cassé
et opérait à répétition sur
l’événement indiqué au lieu
d’itérer parmi tous les événements d’une
fratrie d’un groupe.
De Linux 3.4 à Linux 3.11, les bits mmap
cap_usr_rdpmc et cap_usr_time étaient associés
au même emplacement. Le code devrait plutôt être
modifié pour utiliser les nouveaux champs cap_user_rdpmc et
cap_user_time à la place.
Vérifiez toujours deux fois les résultats. Plusieurs
événements généralisés ont eu de fausses
valeurs. Par exemple, les branchements retirés ne mesuraient pas la
bonne chose sur les machines AMD jusqu'au noyau 2.6.35.
Ce qui suit est un court exemple qui mesure le décompte
total d'instructions d'un appel à printf(3).
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>
static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;
ret = syscall(SYS_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
int
main(void)
{
int fd;
long long count;
struct perf_event_attr pe;
memset(&pe, 0, sizeof(pe));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(pe);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.exclude_hv = 1;
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Erreur d'ouverture du leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
printf("Mesure du décompte d'instructions pour ce printf\n");
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(count));
printf("%lld instructions utilisées\n", count);
close(fd);
}