14#include "arcane/std/PapiPerformanceService.h"
16#include "arcane/utils/ValueConvert.h"
17#include "arcane/utils/PlatformUtils.h"
18#include "arcane/utils/FatalErrorException.h"
19#include "arcane/utils/CriticalSection.h"
20#include "arcane/utils/IPerformanceCounterService.h"
22#include "arcane/core/FactoryService.h"
23#include "arcane/core/IParallelSuperMng.h"
25#include "arcane/std/ProfilingInfo.h"
26#include "arcane/impl/TimerMng.h"
48 if (PAPI_is_initialized() == PAPI_NOT_INITED) {
49 int retval = PAPI_library_init(PAPI_VER_CURRENT);
50 if (retval != PAPI_VER_CURRENT && retval > 0)
51 ARCANE_FATAL(
"PAPI version mismatch r={0} current={1}", retval, PAPI_VER_CURRENT);
53 ARCANE_FATAL(
"Error in PAPI_library_init r={0} msg={1}", retval, PAPI_strerror(retval));
77PapiPerformanceService::
81, m_event_set(PAPI_NULL)
82, m_application(sbi.application())
89PapiPerformanceService::
90~PapiPerformanceService()
100 ProfInfos* global_infos =
nullptr;
101 int global_nb_total_call = 0;
107void PapiPerformanceService::
108arcane_papi_handler(
int EventSet,
void* address, long_long overflow_vector,
void* context)
110 ARCANE_UNUSED(context);
111 static bool is_in_handler =
false;
117 if (Exception::hasPendingException()) {
118 cout <<
"** WARNING: PapiHandler in pending exception\n";
124 is_in_handler =
true;
125 ++global_nb_total_call;
127 int overflow_event[MAX_COUNTER];
128 int nb_overflow_event = MAX_COUNTER;
129 PAPI_get_overflow_event_index(EventSet, overflow_vector, overflow_event, &nb_overflow_event);
130 global_infos->addEvent(address, overflow_event, nb_overflow_event);
131 is_in_handler =
false;
137bool PapiPerformanceService::
138_addEvent(
int event_code,
int event_index)
140 char event_name[PAPI_MAX_STR_LEN];
142 int retval = PAPI_add_event(m_event_set, event_code);
143 PAPI_event_code_to_name(event_code, event_name);
144 info() <<
"Adding Papi event name=" << event_name;
145 if (retval != PAPI_OK) {
146 pwarning() <<
"** ERROR in add_event (index=" << event_index <<
") r=" << retval
147 <<
" msg=" << PAPI_strerror(retval);
156void PapiPerformanceService::
160 if (m_is_initialized)
165 m_is_initialized =
true;
167 int major = PAPI_VERSION_MAJOR(PAPI_VERSION);
168 int minor = PAPI_VERSION_MINOR(PAPI_VERSION);
169 int sub_minor = PAPI_VERSION_REVISION(PAPI_VERSION);
170 info() <<
"PROFILING: start profiling using 'PAPI' version="
171 << major <<
"." << minor <<
"." << sub_minor;
176 global_infos->setNbEventBeforeGettingStack(2000);
177 global_infos->setFunctionDepth(5);
181 const PAPI_exe_info_t* prginfo;
185 retval = PAPI_thread_init((
unsigned long (*)(
void))(pthread_self));
186 if (retval != PAPI_OK)
187 ARCANE_FATAL(
"Error in PAPI_thread_init r={0} msg={1}", retval, PAPI_strerror(retval));
189 prginfo = PAPI_get_executable_info();
191 start =
reinterpret_cast<caddr_t
>(prginfo->address_info.text_start);
192 end =
reinterpret_cast<caddr_t
>(prginfo->address_info.text_end);
194 info() <<
"** PROGRAM INFOS: start=" << (long)start <<
" end=" << (
long)end <<
" length=" << (end - start);
196 if ((retval = PAPI_create_eventset(&m_event_set)) != PAPI_OK)
197 ARCANE_FATAL(
"ERROR in PAPI_create_eventset r={0}", retval);
199 const int NB_EVENT = 3;
200 int papi_events[NB_EVENT];
204 papi_events[0] = PAPI_TOT_CYC;
206 papi_events[1] = PAPI_RES_STL;
207 papi_events[2] = PAPI_DP_OPS;
210 int nb_event = NB_EVENT;
211 if (!papi_user_events.
null()) {
213 papi_user_events.
split(strs,
':');
214 int nb_str = strs.
size();
215 nb_str =
math::min(NB_EVENT - 1, nb_str);
216 for (
Integer i = 0; i < nb_str; ++i) {
217 const String& ename = strs[i];
218 info() <<
"USER_EVENT name=" << ename;
220 int retval = PAPI_event_name_to_code((
char*)ename.
localstr(), &new_event);
221 if (retval != PAPI_OK) {
222 pwarning() <<
"Can not set event from name=" << ename <<
" r=" << retval;
225 papi_events[i + 1] = new_event;
227 nb_event = nb_str + 1;
229 bool is_valid_event[NB_EVENT];
231 for (
Integer i = 0; i < nb_event; ++i)
232 is_valid_event[i] = _addEvent(papi_events[i], i);
236 if (!period_str.
null()) {
237 bool is_bad = builtInGetValue(m_period, period_str);
239 pwarning() <<
"Can not convert '" << period_str <<
"' to int";
243 if (!only_str.
null())
252 if (m_period < 100000)
254 for (
Integer i = 0; i < nb_event; ++i) {
255 if (is_valid_event[i]) {
256 retval = PAPI_overflow(m_event_set, papi_events[i], m_period, 0, arcane_papi_handler);
257 if (retval != PAPI_OK) {
260 fatal() <<
"** ERROR in papi_overflow i=" << i <<
" r=" << retval
261 <<
" msg=" << PAPI_strerror(retval);
264 pwarning() <<
"** ERROR in papi_overflow i=" << i <<
" r=" << retval
265 <<
" msg=" << PAPI_strerror(retval);
266 is_valid_event[i] =
false;
270 info() <<
"Sampling period: (in events) " << m_period;
277void PapiPerformanceService::
283 global_infos->startProfiling();
285 int retval = PAPI_start(m_event_set);
286 if (retval != PAPI_OK) {
296void PapiPerformanceService::
304void PapiPerformanceService::
307 float real_time = 0.0f;
308 float proc_time = 0.0f;
309 long long flpins = 0.0;
315#if PAPI_VERSION >= PAPI_VERSION_NUMBER(6, 0, 0, 0)
316 int retval = PAPI_flops_rate(PAPI_DP_OPS, &real_time, &proc_time, &flpins, &mflops);
318 int retval = PAPI_flops(&real_time, &proc_time, &flpins, &mflops);
320 if (retval != PAPI_OK)
321 error() <<
"** ERROR in PAPI_flops r=" << retval;
323 info() <<
"PAPI_Flops: real_time=" << real_time
324 <<
" proc_time=" << proc_time
325 <<
" flpins=" << flpins
326 <<
" mflips=" << mflops;
333void PapiPerformanceService::
347 int retval = PAPI_stop(m_event_set, 0);
348 if (retval != PAPI_OK) {
351 m_is_running =
false;
353 global_infos->stopProfiling();
359void PapiPerformanceService::
360printInfos(
bool dump_file)
363 global_infos->printInfos(dump_file);
369void PapiPerformanceService::
373 global_infos->dumpJSON(writer);
379void PapiPerformanceService::
383 global_infos->getInfos(array);
389void PapiPerformanceService::
393 global_infos->reset();
410 , m_event_set(PAPI_NULL)
411 , m_is_started(
false)
419 PAPI_stop(m_event_set, m_values.data());
425 void _addEvent(
int event);
427 Real stop(
const char* msg);
453 long_long m_elapsed_us;
454 long_long m_elapsed_cycle;
465 int retval = PAPI_thread_init((
unsigned long (*)(
void))(pthread_self));
466 if (retval != PAPI_OK)
469 retval = PAPI_create_eventset(&m_event_set);
470 if (retval != PAPI_OK)
473 _addEvent(PAPI_TOT_CYC);
474 _addEvent(PAPI_DP_OPS);
475 m_values.resize(m_nb_event);
477 m_start_values.resize(m_nb_event);
478 m_start_values.fill(0);
480 retval = PAPI_start(m_event_set);
481 if (retval != PAPI_OK)
492 int retval = PAPI_add_event(m_event_set, event);
493 if (retval != PAPI_OK) {
494 cerr <<
"** CAN NOT FIND EVENT " <<
event <<
'\n';
506 int retval = PAPI_read(m_event_set, m_start_values.data());
507 if (retval != PAPI_OK) {
508 cerr <<
"** CAN NOT START EVENT\n";
510 m_elapsed_us = PAPI_get_real_usec();
511 m_elapsed_cycle = PAPI_get_real_cyc();
520 int retval = PAPI_read(m_event_set, m_values.data());
521 if (retval != PAPI_OK) {
522 cerr <<
"** CAN NOT STOP EVENT\n";
524 long_long elapsed_us = PAPI_get_real_usec() - m_elapsed_us;
527 double sec_time = ((double)elapsed_us) / 1.0e6;
529 std::cout <<
" -- -- Time: ";
531 std::cout << msg <<
" = ";
533 std::cout << sec_time <<
" ";
537 long_long nb_cycle = m_values[0] - m_start_values[0];
538 long_long nb_flop = m_values[1] - m_start_values[1];
541 std::cout << nb_cycle <<
" ";
543 std::cout << nb_flop;
547 std::cout << nb_flop / elapsed_us;
579class PapiPerformanceCounterService
588 , m_event_set(PAPI_NULL)
589 , m_is_started(
false)
592 ~PapiPerformanceCounterService()
595 (void)PAPI_stop(m_event_set,
nullptr);
610 retval = PAPI_thread_init((
unsigned long (*)(
void))(pthread_self));
611 if (retval != PAPI_OK)
612 ARCANE_FATAL(
"Error in 'PAPI_thread_init' r={0}", retval);
616 retval = PAPI_create_eventset(&m_event_set);
617 if (retval != PAPI_OK)
618 ARCANE_FATAL(
"Error in 'PAPI_createeventset' r={0}", retval);
620 _addEvent(PAPI_TOT_CYC);
621 _addEvent(PAPI_RES_STL);
622 _addEvent(PAPI_L2_TCM);
624 void _addEvent(
int event)
626 int retval = PAPI_add_event(m_event_set, event);
627 if (retval != PAPI_OK) {
628 error() <<
"** CAN NOT FIND EVENT " <<
event <<
'\n';
637 int retval = PAPI_start(m_event_set);
638 if (retval != PAPI_OK)
646 int retval = PAPI_stop(m_event_set,
nullptr);
647 if (retval != PAPI_OK)
649 m_is_started =
false;
659 int retval = PAPI_read(m_event_set, values);
660 if (retval != PAPI_OK) {
661 error() <<
"Error in 'PAPI_read' during getCounters() r=" << retval;
665 for (
int i = 0; i < n; ++i)
666 counters[i] = (
Int64)values[i] - counters[i];
669 for (
int i = 0; i < n; ++i)
670 counters[i] = values[i];
676 std::array<Int64, MIN_COUNTER_SIZE> values;
686 bool m_is_started =
false;
693 ServiceProperty(
"PapiPerformanceCounterService", ST_Application),
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
Integer size() const
Number of elements in the vector.
Critical section in multi-thread.
virtual ITraceMng * traceMng() const =0
Trace manager.
Interface of a profiling service.
Interface of a timer manager.
Real _getRealTime() override
Returns the real time.
void _setRealTime() override
Sets a real timer.
IApplication * application() const
Access to the associated IApplication.
Structure containing the information to create a service.
Service creation properties.
Unicode character string.
bool null() const
Returns true if the string is null.
const char * localstr() const
Returns the conversion of the instance into UTF-8 encoding.
void split(StringContainer &str_array, char c) const
Splits the string based on the character c.
TimerMng(ITraceMng *msg)
Constructs a timer linked to the manager mng.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage fatal() const
Flow for a fatal error message.
TraceMessage info() const
Flow for an information message.
TraceMessage error() const
Flow for an error message.
ITraceMng * traceMng() const
Trace manager.
TraceMessage pwarning() const
1D data vector with value semantics (STL style).
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ ST_Application
The service is used at the application level.
double Real
Type representing a real number.
UniqueArray< String > StringUniqueArray
Dynamic 1D array of strings.