Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
LinuxPerfPerformanceCounterService.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* LinuxPerfPerformanceCounterService.cc (C) 2000-2026 */
9/* */
10/* Récupération des compteurs hardware via l'API 'perf' de Linux. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/IPerformanceCounterService.h"
15#include "arcane/utils/TraceAccessor.h"
16#include "arcane/utils/FatalErrorException.h"
17
18#include "arcane/core/FactoryService.h"
19
20#include <linux/perf_event.h>
21#include <linux/hw_breakpoint.h>
22#include <sys/types.h>
23#include <unistd.h>
24#include <syscall.h>
25#include <sys/ioctl.h>
26
27#include <cstring>
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38class LinuxPerfPerformanceCounterService
39: public TraceAccessor
41{
42 public:
43
44 explicit LinuxPerfPerformanceCounterService(const ServiceBuildInfo& sbi)
46 {
47 }
48 ~LinuxPerfPerformanceCounterService()
49 {
50 _closeAll();
51 }
52
53 public:
54
55 void build() {}
56
57 void initialize() override
58 {
59 _checkInitialize();
60 }
61
63 bool _addEvent(int event_type, int event_config, bool is_optional = false)
64 {
65 struct perf_event_attr attr;
66 std::memset(&attr, 0, sizeof(attr));
67
68 attr.type = event_type,
69 attr.config = event_config;
70 attr.size = sizeof(struct perf_event_attr);
71 attr.exclude_kernel = 1;
72 attr.exclude_hv = 1;
73 attr.disabled = 1;
74 attr.inherit = 1;
75
76 int cpu = -1;
77 int group_fd = -1;
78 unsigned long flags = 0;
79 long long_fd = syscall(__NR_perf_event_open, &attr, m_process_id, cpu, group_fd, flags);
80 info(4) << "AddEvent type=" << attr.type << " id=" << attr.config << " fd=" << long_fd;
81 if (long_fd == (-1)) {
82 if (is_optional)
83 return true;
84 ARCANE_FATAL("ERROR for event type={0} id={1} error={2}", attr.type, attr.config, std::strerror(errno));
85 }
86 int fd = static_cast<int>(long_fd);
87 m_events_file_descriptor.add(fd);
88 return false;
89 }
90
91 void start() override
92 {
93 if (m_is_started)
94 ARCANE_FATAL("start() has alredy been called");
95 _checkInitialize();
96 info(4) << "LinuxPerf: Start";
97 for (int fd : m_events_file_descriptor) {
98 int r = ::ioctl(fd, PERF_EVENT_IOC_ENABLE);
99 if (r != 0)
100 ARCANE_FATAL("Error starting event r={0} error={1}", r, strerror(errno));
101 }
102 m_is_started = true;
103 }
104 void stop() override
105 {
106 if (!m_is_started)
107 ARCANE_FATAL("start() has not been called");
108 info(4) << "LinuxPerf: Stop";
109 for (int fd : m_events_file_descriptor) {
110 int r = ::ioctl(fd, PERF_EVENT_IOC_DISABLE);
111 if (r != 0)
112 ARCANE_FATAL("Error stopping event r={0} error={1}", r, strerror(errno));
113 }
114 m_is_started = false;
115 }
116 bool isStarted() const override
117 {
118 return m_is_started;
119 }
120
121 Integer getCounters(Int64ArrayView counters, bool do_substract) override
122 {
123 Int32 index = 0;
124 for (Int32 index = 0, n = m_events_file_descriptor.size(); index < n; ++index) {
125 Int64 value = _getOneCounter(index);
126 Int64 current_value = counters[index];
127 counters[index] = (do_substract) ? value - current_value : value;
128 }
129 return index;
130 }
131
132 Int64 getCycles() override
133 {
134 return _getOneCounter(0);
135 }
136
137 private:
138
139 UniqueArray<int> m_events_file_descriptor;
140 bool m_is_started = false;
141 bool m_is_init = false;
142 pid_t m_process_id = -1;
143
144 private:
145
146 void _closeAll()
147 {
148 for (int fd : m_events_file_descriptor) {
149 if (fd >= 0)
150 ::close(fd);
151 }
152 m_events_file_descriptor.clear();
153 }
154
155 Int64 _getOneCounter(Int32 index)
156 {
157 int fd = m_events_file_descriptor[index];
158 uint64_t value[1] = { 0 };
159 const size_t s = sizeof(uint64_t);
160 size_t nb_read = ::read(fd, value, s);
161 if (nb_read != s)
162 ARCANE_FATAL("Can not read counter index={0}", index);
163 return value[0];
164 }
165
166 void _checkInitialize()
167 {
168 if (m_is_init)
169 return;
170
171 info() << "Initialize LinuxPerfPerformanceCounterService";
172 m_process_id = ::getpid();
173 // Nombre de cycles CPU. Ce compteur est indispensable.
174 _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES);
175 // Nombre d'instructions exécutées. Ce compteur est indispensable.
176 _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS);
177
178 // Les compteurs suivants ne sont pas indispensables et il n'est
179 // pas toujours facile de savoir ceux qui sont disponibles pour une
180 // plateforme donnée. On essaie dans l'ordre suivant:
181 // 1. Nombre de défaut du dernier niveau de cache (en général le cache L3)
182 // 2. Nombre de cycles où le CPU est en attente de quelque chose.
183 // 3. Nombre de défauts de cache (a priori pour tous les caches)
184 const bool is_optional = true;
185 bool is_bad = true;
186 {
187 int cache_access = (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16);
188 is_bad = _addEvent(PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_LL | cache_access, is_optional);
189 }
190 if (is_bad)
191 is_bad = _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, is_optional);
192 if (is_bad)
193 _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, is_optional);
194
195 m_is_init = true;
196 }
197};
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
203 ServiceProperty("LinuxPerfPerformanceCounterService", ST_Application),
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
209} // End namespace Arcane
210
211/*---------------------------------------------------------------------------*/
212/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
void clear()
Supprime les éléments du tableau.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
Interface d'un service d'accès aux compteurs de performance.
Int64 getCycles() override
Valeur du compteur pour le nombre de cycles du CPU.
void stop() override
Arrête le suivi des compteurs de performance.
bool _addEvent(int event_type, int event_config, bool is_optional=false)
Ajoute un évènement et retourne true si cela ne fonctionne pas.
Integer getCounters(Int64ArrayView counters, bool do_substract) override
Récupère les valeurs actuelles des compteurs.
void start() override
Débute le suivi des compteurs de performance.
bool isStarted() const override
Indique si le service a démarré (start() a été appelé).
IApplication * application() const
Accès à l'application IApplication associé.
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
Vecteur 1D de données avec sémantique par valeur (style STL).
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
ArrayView< Int64 > Int64ArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:449
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
@ ST_Application
Le service s'utilise au niveau de l'application.
std::int32_t Int32
Type entier signé sur 32 bits.