xref: /petsc/src/sys/perfstubs/timer.h (revision a0c7f9aa3b59be96b422b2e54790cd20c111f46e)
1*a0c7f9aaSSamuel Khuvis // Copyright (c) 2019 University of Oregon
2*a0c7f9aaSSamuel Khuvis // Distributed under the BSD Software License
3*a0c7f9aaSSamuel Khuvis // (See accompanying file LICENSE.txt)
4*a0c7f9aaSSamuel Khuvis 
5*a0c7f9aaSSamuel Khuvis #pragma once
6*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_USE_TIMERS
7*a0c7f9aaSSamuel Khuvis 
8*a0c7f9aaSSamuel Khuvis #include <stdint.h>
9*a0c7f9aaSSamuel Khuvis #include <stdlib.h>
10*a0c7f9aaSSamuel Khuvis #include <string.h>
11*a0c7f9aaSSamuel Khuvis #include <stdio.h>
12*a0c7f9aaSSamuel Khuvis #include "config.h"
13*a0c7f9aaSSamuel Khuvis #include "tool.h"
14*a0c7f9aaSSamuel Khuvis 
15*a0c7f9aaSSamuel Khuvis /* These macros help generate unique variable names within a function
16*a0c7f9aaSSamuel Khuvis  * based on the source code line number */
17*a0c7f9aaSSamuel Khuvis #define CONCAT_(x,y) x##y
18*a0c7f9aaSSamuel Khuvis #define CONCAT(x,y) CONCAT_(x,y)
19*a0c7f9aaSSamuel Khuvis 
20*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */
21*a0c7f9aaSSamuel Khuvis /* Define the C API and PerfStubs glue class first */
22*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */
23*a0c7f9aaSSamuel Khuvis 
24*a0c7f9aaSSamuel Khuvis /* Pretty functions will include the return type and argument types,
25*a0c7f9aaSSamuel Khuvis  * not just the function name.  If the compiler doesn't support it,
26*a0c7f9aaSSamuel Khuvis  * just use the function name. */
27*a0c7f9aaSSamuel Khuvis 
28*a0c7f9aaSSamuel Khuvis #if defined(__GNUC__)
29*a0c7f9aaSSamuel Khuvis #define __PERFSTUBS_FUNCTION__ __PRETTY_FUNCTION__
30*a0c7f9aaSSamuel Khuvis #else
31*a0c7f9aaSSamuel Khuvis #define __PERFSTUBS_FUNCTION__ __func__
32*a0c7f9aaSSamuel Khuvis #endif
33*a0c7f9aaSSamuel Khuvis 
34*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_UNKNOWN 0
35*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SUCCESS 1
36*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FAILURE 2
37*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FINALIZED 3
38*a0c7f9aaSSamuel Khuvis 
39*a0c7f9aaSSamuel Khuvis extern int perfstubs_initialized;
40*a0c7f9aaSSamuel Khuvis 
41*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */
42*a0c7f9aaSSamuel Khuvis /* Now define the C API */
43*a0c7f9aaSSamuel Khuvis /* ------------------------------------------------------------------ */
44*a0c7f9aaSSamuel Khuvis 
45*a0c7f9aaSSamuel Khuvis #if defined(PERFSTUBS_USE_TIMERS)
46*a0c7f9aaSSamuel Khuvis 
47*a0c7f9aaSSamuel Khuvis /* regular C API */
48*a0c7f9aaSSamuel Khuvis 
49*a0c7f9aaSSamuel Khuvis #ifdef __cplusplus
50*a0c7f9aaSSamuel Khuvis extern "C" {
51*a0c7f9aaSSamuel Khuvis #endif
52*a0c7f9aaSSamuel Khuvis 
53*a0c7f9aaSSamuel Khuvis void  ps_initialize_(void);
54*a0c7f9aaSSamuel Khuvis void  ps_finalize_(void);
55*a0c7f9aaSSamuel Khuvis void  ps_register_thread_(void);
56*a0c7f9aaSSamuel Khuvis void  ps_dump_data_(void);
57*a0c7f9aaSSamuel Khuvis void* ps_timer_create_(const char *timer_name);
58*a0c7f9aaSSamuel Khuvis void  ps_timer_create_fortran_(void ** object, const char *timer_name);
59*a0c7f9aaSSamuel Khuvis void  ps_timer_start_(const void *timer);
60*a0c7f9aaSSamuel Khuvis void  ps_timer_start_fortran_(const void **timer);
61*a0c7f9aaSSamuel Khuvis void  ps_timer_stop_(const void *timer);
62*a0c7f9aaSSamuel Khuvis void  ps_timer_stop_fortran_(const void **timer);
63*a0c7f9aaSSamuel Khuvis void  ps_set_parameter_(const char *parameter_name, int64_t parameter_value);
64*a0c7f9aaSSamuel Khuvis void  ps_dynamic_phase_start_(const char *phasePrefix, int iterationIndex);
65*a0c7f9aaSSamuel Khuvis void  ps_dynamic_phase_stop_(const char *phasePrefix, int iterationIndex);
66*a0c7f9aaSSamuel Khuvis void* ps_create_counter_(const char *name);
67*a0c7f9aaSSamuel Khuvis void  ps_create_counter_fortran_(void ** object, const char *name);
68*a0c7f9aaSSamuel Khuvis void  ps_sample_counter_(const void *counter, const double value);
69*a0c7f9aaSSamuel Khuvis void  ps_sample_counter_fortran_(const void **counter, const double value);
70*a0c7f9aaSSamuel Khuvis void  ps_set_metadata_(const char *name, const char *value);
71*a0c7f9aaSSamuel Khuvis 
72*a0c7f9aaSSamuel Khuvis /* data query API */
73*a0c7f9aaSSamuel Khuvis 
74*a0c7f9aaSSamuel Khuvis void  ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id);
75*a0c7f9aaSSamuel Khuvis void  ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id);
76*a0c7f9aaSSamuel Khuvis void  ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id);
77*a0c7f9aaSSamuel Khuvis void  ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id);
78*a0c7f9aaSSamuel Khuvis void  ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id);
79*a0c7f9aaSSamuel Khuvis void  ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id);
80*a0c7f9aaSSamuel Khuvis 
81*a0c7f9aaSSamuel Khuvis char* ps_make_timer_name_(const char * file, const char * func, int line);
82*a0c7f9aaSSamuel Khuvis 
83*a0c7f9aaSSamuel Khuvis #ifdef __cplusplus
84*a0c7f9aaSSamuel Khuvis }
85*a0c7f9aaSSamuel Khuvis #endif
86*a0c7f9aaSSamuel Khuvis 
87*a0c7f9aaSSamuel Khuvis /* Macro API for option of entirely disabling at compile time
88*a0c7f9aaSSamuel Khuvis  * To use this API, set the Macro PERFSTUBS_USE_TIMERS on the command
89*a0c7f9aaSSamuel Khuvis  * line or in a config.h file, however your project does it
90*a0c7f9aaSSamuel Khuvis  */
91*a0c7f9aaSSamuel Khuvis 
92*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INITIALIZE() ps_initialize_();
93*a0c7f9aaSSamuel Khuvis 
94*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FINALIZE() ps_finalize_();
95*a0c7f9aaSSamuel Khuvis 
96*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_REGISTER_THREAD() ps_register_thread_();
97*a0c7f9aaSSamuel Khuvis 
98*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DUMP_DATA() ps_dump_data_();
99*a0c7f9aaSSamuel Khuvis 
100*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START(_timer, _timer_name) \
101*a0c7f9aaSSamuel Khuvis     static void * _timer = NULL; \
102*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \
103*a0c7f9aaSSamuel Khuvis         if (_timer == NULL) { \
104*a0c7f9aaSSamuel Khuvis             _timer = ps_timer_create_(_timer_name); \
105*a0c7f9aaSSamuel Khuvis         } \
106*a0c7f9aaSSamuel Khuvis         ps_timer_start_(_timer); \
107*a0c7f9aaSSamuel Khuvis     };
108*a0c7f9aaSSamuel Khuvis 
109*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP(_timer) \
110*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(_timer); \
111*a0c7f9aaSSamuel Khuvis 
112*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SET_PARAMETER(_parameter, _value) \
113*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_set_parameter_(_parameter, _value);
114*a0c7f9aaSSamuel Khuvis 
115*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_START(_phase_prefix, _iteration_index) \
116*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) \
117*a0c7f9aaSSamuel Khuvis     ps_dynamic_phase_start_(_phase_prefix, _iteration_index);
118*a0c7f9aaSSamuel Khuvis 
119*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_STOP(_phase_prefix, _iteration_index) \
120*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) \
121*a0c7f9aaSSamuel Khuvis     ps_dynamic_phase_stop_(_phase_prefix, _iteration_index);
122*a0c7f9aaSSamuel Khuvis 
123*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START_FUNC(_timer) \
124*a0c7f9aaSSamuel Khuvis     static void * _timer = NULL; \
125*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \
126*a0c7f9aaSSamuel Khuvis         if (_timer == NULL) { \
127*a0c7f9aaSSamuel Khuvis             char * tmpstr = ps_make_timer_name_(__FILE__, \
128*a0c7f9aaSSamuel Khuvis             __PERFSTUBS_FUNCTION__, __LINE__); \
129*a0c7f9aaSSamuel Khuvis             _timer = ps_timer_create_(tmpstr); \
130*a0c7f9aaSSamuel Khuvis             free(tmpstr); \
131*a0c7f9aaSSamuel Khuvis         } \
132*a0c7f9aaSSamuel Khuvis         ps_timer_start_(_timer); \
133*a0c7f9aaSSamuel Khuvis     };
134*a0c7f9aaSSamuel Khuvis 
135*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP_FUNC(_timer) \
136*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(_timer);
137*a0c7f9aaSSamuel Khuvis 
138*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SAMPLE_COUNTER(_name, _value) \
139*a0c7f9aaSSamuel Khuvis     static void * CONCAT(__var,__LINE__) =  NULL; \
140*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) { \
141*a0c7f9aaSSamuel Khuvis         if (CONCAT(__var,__LINE__) == NULL) { \
142*a0c7f9aaSSamuel Khuvis             CONCAT(__var,__LINE__) = ps_create_counter_(_name); \
143*a0c7f9aaSSamuel Khuvis         } \
144*a0c7f9aaSSamuel Khuvis         ps_sample_counter_(CONCAT(__var,__LINE__), _value); \
145*a0c7f9aaSSamuel Khuvis     };
146*a0c7f9aaSSamuel Khuvis 
147*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_METADATA(_name, _value) \
148*a0c7f9aaSSamuel Khuvis     if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_set_metadata_(_name, _value);
149*a0c7f9aaSSamuel Khuvis 
150*a0c7f9aaSSamuel Khuvis #else // defined(PERFSTUBS_USE_TIMERS)
151*a0c7f9aaSSamuel Khuvis 
152*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INITIALIZE()
153*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_FINALIZE()
154*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_REGISTER_THREAD()
155*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DUMP_DATA()
156*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START(_timer, _timer_name)
157*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP(_timer_name)
158*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SET_PARAMETER(_parameter, _value)
159*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_START(_phase_prefix, _iteration_index)
160*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_DYNAMIC_PHASE_STOP(_phase_prefix, _iteration_index)
161*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_START_FUNC(_timer)
162*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_TIMER_STOP_FUNC(_timer)
163*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SAMPLE_COUNTER(_name, _value)
164*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_METADATA(_name, _value)
165*a0c7f9aaSSamuel Khuvis 
166*a0c7f9aaSSamuel Khuvis #endif // defined(PERFSTUBS_USE_TIMERS)
167*a0c7f9aaSSamuel Khuvis 
168*a0c7f9aaSSamuel Khuvis #ifdef __cplusplus
169*a0c7f9aaSSamuel Khuvis 
170*a0c7f9aaSSamuel Khuvis #if defined(PERFSTUBS_USE_TIMERS)
171*a0c7f9aaSSamuel Khuvis 
172*a0c7f9aaSSamuel Khuvis /*
173*a0c7f9aaSSamuel Khuvis  * We allow the namespace to be changed, so that different libraries
174*a0c7f9aaSSamuel Khuvis  * can include their own implementation and not have a namespace collision.
175*a0c7f9aaSSamuel Khuvis  * For example, library A and executable B could both include the
176*a0c7f9aaSSamuel Khuvis  * perfstubs_api code in their source tree, and change the namespace
177*a0c7f9aaSSamuel Khuvis  * respectively, instead of linking in the perfstubs library.
178*a0c7f9aaSSamuel Khuvis  */
179*a0c7f9aaSSamuel Khuvis 
180*a0c7f9aaSSamuel Khuvis #if defined(PERFSTUBS_NAMESPACE)
181*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INTERNAL_NAMESPACE PERFSTUBS_NAMESPACE
182*a0c7f9aaSSamuel Khuvis #else
183*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_INTERNAL_NAMESPACE perfstubs_profiler
184*a0c7f9aaSSamuel Khuvis #endif
185*a0c7f9aaSSamuel Khuvis 
186*a0c7f9aaSSamuel Khuvis #include <memory>
187*a0c7f9aaSSamuel Khuvis #include <sstream>
188*a0c7f9aaSSamuel Khuvis #include <string>
189*a0c7f9aaSSamuel Khuvis 
190*a0c7f9aaSSamuel Khuvis namespace external
191*a0c7f9aaSSamuel Khuvis {
192*a0c7f9aaSSamuel Khuvis 
193*a0c7f9aaSSamuel Khuvis namespace PERFSTUBS_INTERNAL_NAMESPACE
194*a0c7f9aaSSamuel Khuvis {
195*a0c7f9aaSSamuel Khuvis 
196*a0c7f9aaSSamuel Khuvis class ScopedTimer
197*a0c7f9aaSSamuel Khuvis {
198*a0c7f9aaSSamuel Khuvis private:
199*a0c7f9aaSSamuel Khuvis     const void * m_timer;
200*a0c7f9aaSSamuel Khuvis 
201*a0c7f9aaSSamuel Khuvis public:
202*a0c7f9aaSSamuel Khuvis     ScopedTimer(const void * timer) : m_timer(timer)
203*a0c7f9aaSSamuel Khuvis     {
204*a0c7f9aaSSamuel Khuvis         if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_start_(m_timer);
205*a0c7f9aaSSamuel Khuvis     }
206*a0c7f9aaSSamuel Khuvis     ~ScopedTimer()
207*a0c7f9aaSSamuel Khuvis     {
208*a0c7f9aaSSamuel Khuvis         if (perfstubs_initialized == PERFSTUBS_SUCCESS) ps_timer_stop_(m_timer);
209*a0c7f9aaSSamuel Khuvis     }
210*a0c7f9aaSSamuel Khuvis };
211*a0c7f9aaSSamuel Khuvis 
212*a0c7f9aaSSamuel Khuvis } // namespace PERFSTUBS_INTERNAL_NAMESPACE
213*a0c7f9aaSSamuel Khuvis 
214*a0c7f9aaSSamuel Khuvis } // namespace external
215*a0c7f9aaSSamuel Khuvis 
216*a0c7f9aaSSamuel Khuvis namespace PSNS = external::PERFSTUBS_INTERNAL_NAMESPACE;
217*a0c7f9aaSSamuel Khuvis 
218*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER(__name) \
219*a0c7f9aaSSamuel Khuvis     static void * CONCAT(__var,__LINE__) = ps_timer_create_(__name); \
220*a0c7f9aaSSamuel Khuvis     PSNS::ScopedTimer CONCAT(__var2,__LINE__)(CONCAT(__var,__LINE__));
221*a0c7f9aaSSamuel Khuvis 
222*a0c7f9aaSSamuel Khuvis /* The string created by ps_make_timer_name is a memory leak, but
223*a0c7f9aaSSamuel Khuvis  * it is only created once per function, since it is called when the
224*a0c7f9aaSSamuel Khuvis  * static variable is first initialized. */
225*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER_FUNC() \
226*a0c7f9aaSSamuel Khuvis     static void * CONCAT(__var,__LINE__) = \
227*a0c7f9aaSSamuel Khuvis         ps_timer_create_(ps_make_timer_name_(__FILE__, \
228*a0c7f9aaSSamuel Khuvis         __PERFSTUBS_FUNCTION__, __LINE__)); \
229*a0c7f9aaSSamuel Khuvis     PSNS::ScopedTimer CONCAT(__var2,__LINE__)(CONCAT(__var,__LINE__));
230*a0c7f9aaSSamuel Khuvis 
231*a0c7f9aaSSamuel Khuvis #else // defined(PERFSTUBS_USE_TIMERS)
232*a0c7f9aaSSamuel Khuvis 
233*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER(__name)
234*a0c7f9aaSSamuel Khuvis #define PERFSTUBS_SCOPED_TIMER_FUNC()
235*a0c7f9aaSSamuel Khuvis 
236*a0c7f9aaSSamuel Khuvis #endif // defined(PERFSTUBS_USE_TIMERS)
237*a0c7f9aaSSamuel Khuvis 
238*a0c7f9aaSSamuel Khuvis #endif // ifdef __cplusplus
239