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