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