Arcane  4.2.3.0
Developer documentation
Loading...
Searching...
No Matches
ProfPerformanceService.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/* ProfPerformanceService.cc (C) 2000-2024 */
9/* */
10/* Performance information using profiling signals. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ValueConvert.h"
15#include "arcane/utils/NotImplementedException.h"
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/FatalErrorException.h"
18#include "arcane/utils/TraceInfo.h"
19
20#include "arcane/core/FactoryService.h"
21#include "arcane/core/AbstractService.h"
22
23#include "arcane/utils/IProfilingService.h"
24
25#include "arcane/std/ProfilingInfo.h"
26
27// NOTE: Since this file requires libunwind, it is only compiled on
28// UNIX-style OS.
29
30#define UNW_LOCAL_ONLY
31#include <libunwind.h>
32#include <stdio.h>
33#include <cxxabi.h>
34
35#include <sys/time.h>
36#include <signal.h>
37
38/*---------------------------------------------------------------------------*/
39/*---------------------------------------------------------------------------*/
40
41namespace Arcane
42{
43
44/*---------------------------------------------------------------------------*/
45/*---------------------------------------------------------------------------*/
46
50class ProfPerformanceService
51: public AbstractService
52, public IProfilingService
53{
54 public:
55
56 explicit ProfPerformanceService(const ServiceBuildInfo& sbi);
57 ~ProfPerformanceService() override;
58
59 public:
60
61 void initialize() override;
62 bool isInitialized() const override { return m_is_initialized; }
63 void startProfiling() override;
64 void switchEvent() override;
65 void stopProfiling() override;
66 bool isRunning() const override;
67 void printInfos(bool dump_file) override;
68 void getInfos(Int64Array&) override;
69 void dumpJSON(JSONWriter& writer) override;
70 void reset() override;
71 ITimerMng* timerMng() override { return nullptr; }
72
73 public:
74
75 bool m_is_initialized = false;
76};
77
78/*---------------------------------------------------------------------------*/
79/*---------------------------------------------------------------------------*/
80
81ARCANE_REGISTER_APPLICATION_FACTORY(ProfPerformanceService,
82 IProfilingService,
83 ProfProfilingService);
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88ProfPerformanceService::
89ProfPerformanceService(const ServiceBuildInfo& sbi)
90: AbstractService(sbi)
91{
92}
93
94/*---------------------------------------------------------------------------*/
95/*---------------------------------------------------------------------------*/
96
97ProfPerformanceService::
98~ProfPerformanceService()
99{
100}
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
104
105static void
106_setTimer(Integer usecond)
107{
108 struct itimerval time_val;
109 struct itimerval otime_val;
110 time_val.it_value.tv_sec = 0;
111 time_val.it_value.tv_usec = usecond;
112 time_val.it_interval.tv_sec = 0;
113 time_val.it_interval.tv_usec = 0;
114 int r = setitimer(ITIMER_PROF, &time_val, &otime_val);
115 if (r != 0)
116 cout << "** ERROR in setitimer r=" << r << '\n';
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122namespace
123{
124 int nb_total = 0;
125
126 ProfInfos* global_infos = nullptr;
127 bool global_is_active = false;
129 int global_timer_period = 10000;
130} // namespace
131
132extern "C" void
133arcane_prof_handler()
134{
135 static bool is_in_handler = false;
136 // On Linux with gcc, exceptions use libunwind contained
137 // in gcc, and this can cause deadlocks with our usage
138 // if this handler is called during exception unwinding.
139 // To avoid this problem, we do nothing as long as an exception is
140 // active.
142 cout << "** WARNING: ProfHandler in pending exception\n";
143 return;
144 }
145 if (is_in_handler) {
146 cout << "** In handler\n";
147 return;
148 }
149 is_in_handler = true;
150 ++nb_total;
151
152 int overflow_event[MAX_COUNTER];
153 int nb_overflow_event = 1;
154 overflow_event[0] = 0;
155
156 unw_word_t func_ip = 0;
157 unw_word_t offset = 0;
158 {
159 unw_cursor_t cursor;
160 unw_context_t uc;
161 unw_getcontext(&uc);
162 unw_init_local(&cursor, &uc);
163 int current_func = 0;
164 String message;
165
166 // 3 indicates the number of functions before the correct one
167 // (there is this function, then _arcaneProfilingSigFunc
168 // and the signal itself.
169 while (unw_step(&cursor) > 0 && current_func < 3) {
170 //while (current_func<3) {
171 //unw_step(&cursor);
172 unw_get_reg(&cursor, UNW_REG_IP, &func_ip);
173#if 0
174 char func_name_buf[10000];
175 unw_get_proc_name(&cursor,func_name_buf,10000,&offset);
176 cout << "** I=" << current_func << " FUNC NAME=" << func_name_buf
177 << " ip=" << (void*)func_ip << '\n';
178#endif
179 ++current_func;
180 }
181 }
182
183 global_infos->addEvent((void*)(func_ip + offset), overflow_event, nb_overflow_event);
184
185 is_in_handler = false;
186}
187
188/*---------------------------------------------------------------------------*/
189/*---------------------------------------------------------------------------*/
190
191extern "C" void
192_arcaneProfilingSigFunc(int signum)
193{
194 //cout << "**SIGPROF=" << global_is_active << "\n";
195 if (signum != SIGPROF)
196 return;
197 if (global_is_active) {
198 arcane_prof_handler();
199 // It is preferable to position the timer once
200 // the profiling function is called because if the timer is small,
201 // it can trigger in the loop
202 _setTimer(global_timer_period);
203 }
204}
205
206extern "C" void
207_arcaneProfilingSigactionFunc(int val, siginfo_t*, void*)
208{
209 _arcaneProfilingSigFunc(val);
210}
211
212/*---------------------------------------------------------------------------*/
213/*---------------------------------------------------------------------------*/
214
217{
218 if (m_is_initialized)
219 return;
220 m_is_initialized = true;
221
222 if (!global_infos)
223 global_infos = new ProfInfos(traceMng());
224 global_infos->setFunctionDepth(4);
225 global_infos->setNbEventBeforeGettingStack(100);
226}
227
228/*---------------------------------------------------------------------------*/
229/*---------------------------------------------------------------------------*/
230
233{
234 if (global_is_active)
235 ARCANE_FATAL("Profiling is already started");
236 global_is_active = true;
237 global_infos->startProfiling();
238
239 struct sigaction sa;
240 sa.sa_flags = SA_SIGINFO | SA_NODEFER;
241 sigemptyset(&sa.sa_mask);
242 sa.sa_sigaction = _arcaneProfilingSigactionFunc;
243 sigaction(SIGPROF, &sa, nullptr);
244
245 _setTimer(global_timer_period);
246}
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
251void ProfPerformanceService::
252switchEvent()
253{
254}
255
256/*---------------------------------------------------------------------------*/
257/*---------------------------------------------------------------------------*/
258
261{
262 if (!global_infos)
263 return;
264
265 global_is_active = false;
266 _setTimer(global_timer_period);
267
268 struct sigaction sa;
269 sa.sa_flags = SA_SIGINFO | SA_NODEFER;
270 sigemptyset(&sa.sa_mask);
271 sa.sa_handler = SIG_IGN;
272 sigaction(SIGPROF, &sa, nullptr);
273
274 //info() << "PROFILING: stop profiling nb_total=" << nb_total;
275 global_infos->stopProfiling();
276 //global_infos->printInfos();
277}
278
279/*---------------------------------------------------------------------------*/
280/*---------------------------------------------------------------------------*/
281
283printInfos(bool dump_file)
284{
285 if (global_infos)
286 global_infos->printInfos(dump_file);
287}
288
289/*---------------------------------------------------------------------------*/
290/*---------------------------------------------------------------------------*/
291
293dumpJSON(JSONWriter& writer)
294{
295 if (global_infos)
296 global_infos->dumpJSON(writer);
297}
298
299/*---------------------------------------------------------------------------*/
300/*---------------------------------------------------------------------------*/
301
302void ProfPerformanceService::
303getInfos(Int64Array&)
304{
305 throw NotImplementedException(A_FUNCINFO);
306}
307
308/*---------------------------------------------------------------------------*/
309/*---------------------------------------------------------------------------*/
310
312reset()
313{
314 if (global_infos)
315 global_infos->reset();
316}
317
318/*---------------------------------------------------------------------------*/
319/*---------------------------------------------------------------------------*/
320
322isRunning() const
323{
324 return global_is_active;
325}
326
327/*---------------------------------------------------------------------------*/
328/*---------------------------------------------------------------------------*/
329
330} // End namespace Arcane
331
332/*---------------------------------------------------------------------------*/
333/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCANE_REGISTER_APPLICATION_FACTORY(aclass, ainterface, aname)
Registers a factory service for the class aclass.
AbstractService(const ServiceBuildInfo &)
Constructor from a ServiceBuildInfo.
static bool hasPendingException()
Indicates if there are pending exceptions.
Interface of a profiling service.
Interface of a timer manager.
Definition ITimerMng.h:50
void startProfiling() override
Starts profiling.
void dumpJSON(JSONWriter &writer) override
Writes the profiling information to the writer writer.
void reset() override
Resets the counters.
bool isRunning() const override
Indicates if the profiling is running.
void initialize() override
Initializes the profiling service.
void stopProfiling() override
Stops profiling.
ITimerMng * timerMng() override
Timer using the features of this service if they exist. Can be null.
bool isInitialized() const override
Indicates if initialize() has already been called.
void printInfos(bool dump_file) override
Displays profiling information.
Structure containing the information to create a service.
ITraceMng * traceMng() const
Trace manager.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
Definition UtilsTypes.h:119
Int32 Integer
Type representing an integer.