Arcane  v3.14.10.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-2022 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-2022 */
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/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/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30namespace Arcane
31{
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
37: public TraceAccessor
39{
40 public:
41
43 : TraceAccessor(sbi.application()->traceMng())
44 {
45 }
47 {
48 _closeAll();
49 }
50
51 public:
52
53 void build() {}
54
55 void initialize() override
56 {
57 _checkInitialize();
58 }
59
61 bool _addEvent(int event_type, int event_config, bool is_optional = false)
62 {
63 struct perf_event_attr attr;
64 memset(&attr, 0, sizeof(attr));
65
66 attr.type = event_type,
67 attr.config = event_config;
68 attr.size = sizeof(struct perf_event_attr);
69 attr.exclude_kernel = 1;
70 attr.exclude_hv = 1;
71 attr.disabled = 1;
72 attr.inherit = 1;
73
74 int cpu = -1;
75 int group_fd = -1;
76 unsigned long flags = 0;
77 long long_fd = syscall(__NR_perf_event_open, &attr, m_process_id, cpu, group_fd, flags);
78 info(4) << "AddEvent type=" << attr.type << " id=" << attr.config << " fd=" << long_fd;
79 if (long_fd == (-1)){
80 if (is_optional)
81 return true;
82 ARCANE_FATAL("ERROR for event type={0} id={1} error={2}", attr.type, attr.config, strerror(errno));
83 }
84 int fd = static_cast<int>(long_fd);
85 m_events_file_descriptor.add(fd);
86 return false;
87 }
88
89 void start() override
90 {
91 if (m_is_started)
92 ARCANE_FATAL("start() has alredy been called");
93 _checkInitialize();
94 info(4) << "LinuxPerf: Start";
95 for (int fd : m_events_file_descriptor) {
96 int r = ::ioctl(fd, PERF_EVENT_IOC_ENABLE);
97 if (r != 0)
98 ARCANE_FATAL("Error starting event r={0} error={1}", r, strerror(errno));
99 }
100 m_is_started = true;
101 }
102 void stop() override
103 {
104 if (!m_is_started)
105 ARCANE_FATAL("start() has not been called");
106 info(4) << "LinuxPerf: Stop";
107 for (int fd : m_events_file_descriptor) {
108 int r = ::ioctl(fd, PERF_EVENT_IOC_DISABLE);
109 if (r != 0)
110 ARCANE_FATAL("Error stopping event r={0} error={1}", r, strerror(errno));
111 }
112 m_is_started = false;
113 }
114 bool isStarted() const override
115 {
116 return m_is_started;
117 }
118
119 Integer getCounters(Int64ArrayView counters, bool do_substract) override
120 {
121 Int32 index = 0;
122 for (Int32 index = 0, n = m_events_file_descriptor.size(); index < n; ++index) {
123 Int64 value = _getOneCounter(index);
124 Int64 current_value = counters[index];
125 counters[index] = (do_substract) ? value - current_value : value;
126 }
127 return index;
128 }
129
130 Int64 getCycles() override
131 {
132 return _getOneCounter(0);
133 }
134
135 private:
136
137 UniqueArray<int> m_events_file_descriptor;
138 bool m_is_started = false;
139 bool m_is_init = false;
140 pid_t m_process_id = -1;
141
142 private:
143
144 void _closeAll()
145 {
146 for (int fd : m_events_file_descriptor) {
147 if (fd >= 0)
148 ::close(fd);
149 }
150 m_events_file_descriptor.clear();
151 }
152
153 Int64 _getOneCounter(Int32 index)
154 {
155 int fd = m_events_file_descriptor[index];
156 uint64_t value[1] = { 0 };
157 const size_t s = sizeof(uint64_t);
158 size_t nb_read = ::read(fd, value, s);
159 if (nb_read != s)
160 ARCANE_FATAL("Can not read counter index={0}", index);
161 return value[0];
162 }
163
164 void _checkInitialize()
165 {
166 if (m_is_init)
167 return;
168
169 info() << "Initialize LinuxPerfPerformanceCounterService";
170 m_process_id = ::getpid();
171 // Nombre de cycles CPU. Ce compteur est indispensable.
172 _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES);
173 // Nombre d'instructions exécutées. Ce compteur est indispensable.
174 _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS);
175
176 // Les compteurs suivants ne sont pas indispensables et il n'est
177 // pas toujours facile de savoir ceux qui sont disponibles pour une
178 // plateforme donnée. On essaie dans l'ordre suivant:
179 // 1. Nombre de défaut du dernier niveau de cache (en général le cache L3)
180 // 2. Nombre de cycles où le CPU est en attente de quelque chose.
181 // 3. Nombre de défauts de cache (a priori pour tous les caches)
182 const bool is_optional = true;
183 bool is_bad = true;
184 {
185 int cache_access = (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16);
186 is_bad = _addEvent(PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_LL | cache_access, is_optional);
187 }
188 if (is_bad)
189 is_bad = _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, is_optional);
190 if (is_bad)
191 _addEvent(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, is_optional);
192
193 m_is_init = true;
194 }
195};
196
197/*---------------------------------------------------------------------------*/
198/*---------------------------------------------------------------------------*/
199
200ARCANE_REGISTER_SERVICE(LinuxPerfPerformanceCounterService,
201 ServiceProperty("LinuxPerfPerformanceCounterService", ST_Application),
202 ARCANE_SERVICE_INTERFACE(IPerformanceCounterService));
203
204/*---------------------------------------------------------------------------*/
205/*---------------------------------------------------------------------------*/
206
207} // End namespace Arcane
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
#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.
Interface d'un service d'accès aux compteurs de performance.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
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é)
Structure contenant les informations pour créer un service.
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
void add(ConstReferenceType val)
Ajoute l'élément val à la fin du tableau.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
#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 -*-
@ ST_Application
Le service s'utilise au niveau de l'application.