xref: /petsc/src/sys/perfstubs/pstimer.c (revision 6c2b77d522d8aa5c8b27f04fddd7150d0d6755fb)
1 // Copyright (c) 2019 University of Oregon
2 // Distributed under the BSD Software License
3 // (See accompanying file LICENSE.txt)
4 
5 #ifndef _GNU_SOURCE
6 #define _GNU_SOURCE // needed to define RTLD_DEFAULT
7 #endif
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <math.h>
11 #ifdef __linux__
12 #include <dlfcn.h>
13 #else
14 #define PERFSTUBS_USE_STATIC 1
15 #endif
16 #define PERFSTUBS_USE_TIMERS
17 #include "timer.h"
18 
19 #define MAX_TOOLS 1
20 
21 #if defined(_WIN32)||defined(WIN32)||defined(_WIN64)||defined(WIN64)||defined(__CYGWIN__)||defined(__APPLE__)
22 #define PERFSTUBS_OFF
23 #endif
24 
25 /* Make sure that the Timer singleton is constructed when the
26  * library is loaded.  This will ensure (on linux, anyway) that
27  * we can assert that we have m_Initialized on the main thread. */
28 //static void __attribute__((constructor)) initialize_library(void);
29 
30 /* Globals for the plugin API */
31 
32 int perfstubs_initialized = PERFSTUBS_UNKNOWN;
33 int num_tools_registered = 0;
34 /* Keep track of whether the thread has been registered */
35 #ifndef PERFSTUBS_OFF
36 __thread int thread_seen = 0;
37 #endif
38 /* Function pointers */
39 
40 ps_initialize_t initialize_functions[MAX_TOOLS];
41 ps_register_thread_t register_thread_functions[MAX_TOOLS];
42 ps_finalize_t finalize_functions[MAX_TOOLS];
43 ps_dump_data_t dump_data_functions[MAX_TOOLS];
44 ps_timer_create_t timer_create_functions[MAX_TOOLS];
45 ps_timer_start_t timer_start_functions[MAX_TOOLS];
46 ps_timer_stop_t timer_stop_functions[MAX_TOOLS];
47 ps_set_parameter_t set_parameter_functions[MAX_TOOLS];
48 ps_dynamic_phase_start_t dynamic_phase_start_functions[MAX_TOOLS];
49 ps_dynamic_phase_stop_t dynamic_phase_stop_functions[MAX_TOOLS];
50 ps_create_counter_t create_counter_functions[MAX_TOOLS];
51 ps_sample_counter_t sample_counter_functions[MAX_TOOLS];
52 ps_set_metadata_t set_metadata_functions[MAX_TOOLS];
53 ps_get_timer_data_t get_timer_data_functions[MAX_TOOLS];
54 ps_get_counter_data_t get_counter_data_functions[MAX_TOOLS];
55 ps_get_metadata_t get_metadata_functions[MAX_TOOLS];
56 ps_free_timer_data_t free_timer_data_functions[MAX_TOOLS];
57 ps_free_counter_data_t free_counter_data_functions[MAX_TOOLS];
58 ps_free_metadata_t free_metadata_functions[MAX_TOOLS];
59 
60 #ifndef PERFSTUBS_OFF
61 
62 #ifdef PERFSTUBS_USE_STATIC
63 
64 #if defined(__clang__) && defined(__APPLE__)
65 #define PS_WEAK_PRE
66 #define PS_WEAK_POST __attribute__((weak_import))
67 #define PS_WEAK_POST_NULL __attribute__((weak_import))
68 #else
69 #define PS_WEAK_PRE __attribute__((weak))
70 #define PS_WEAK_POST
71 #define PS_WEAK_POST_NULL
72 #endif
73 
74 PS_WEAK_PRE void ps_tool_initialize(void) PS_WEAK_POST;
75 PS_WEAK_PRE void ps_tool_register_thread(void) PS_WEAK_POST;
76 PS_WEAK_PRE void ps_tool_finalize(void) PS_WEAK_POST;
77 PS_WEAK_PRE void ps_tool_dump_data(void) PS_WEAK_POST;
78 PS_WEAK_PRE void* ps_tool_timer_create(const char *) PS_WEAK_POST;
79 PS_WEAK_PRE void ps_tool_timer_start(const void *) PS_WEAK_POST;
80 PS_WEAK_PRE void ps_tool_timer_stop(const void *) PS_WEAK_POST;
81 PS_WEAK_PRE void ps_tool_set_parameter(const char *, int64_t) PS_WEAK_POST;
82 PS_WEAK_PRE void ps_tool_dynamic_phase_start(const char *, int) PS_WEAK_POST;
83 PS_WEAK_PRE void ps_tool_dynamic_phase_stop(const char *, int) PS_WEAK_POST;
84 PS_WEAK_PRE void* ps_tool_create_counter(const char *) PS_WEAK_POST;
85 PS_WEAK_PRE void ps_tool_sample_counter(const void *, double) PS_WEAK_POST;
86 PS_WEAK_PRE void ps_tool_set_metadata(const char *, const char *) PS_WEAK_POST;
87 PS_WEAK_PRE void ps_tool_get_timer_data(ps_tool_timer_data_t *) PS_WEAK_POST;
88 PS_WEAK_PRE void ps_tool_get_counter_data(ps_tool_counter_data_t *) PS_WEAK_POST;
89 PS_WEAK_PRE void ps_tool_get_metadata(ps_tool_metadata_t *) PS_WEAK_POST;
90 PS_WEAK_PRE void ps_tool_free_timer_data(ps_tool_timer_data_t *) PS_WEAK_POST;
91 PS_WEAK_PRE void ps_tool_free_counter_data(ps_tool_counter_data_t *) PS_WEAK_POST;
92 PS_WEAK_PRE void ps_tool_free_metadata(ps_tool_metadata_t *) PS_WEAK_POST;
93 #endif
94 
95 
96 // Disable pedantic, see https://stackoverflow.com/a/36385690
97 #pragma GCC diagnostic push  // Save actual diagnostics state
98 #pragma GCC diagnostic ignored "-Wpedantic" // Disable pedantic
99 
100 #endif //PERFSTUBS_OFF
101 
102 void initialize_library() {
103 #ifndef PERFSTUBS_OFF
104 #ifdef PERFSTUBS_USE_STATIC
105     /* The initialization function is the only required one */
106     initialize_functions[0] = &ps_tool_initialize;
107     if (initialize_functions[0] == NULL) {
108         return;
109     }
110     printf("Found ps_tool_initialize(), registering tool\n");
111     register_thread_functions[0] = &ps_tool_register_thread;
112     finalize_functions[0] = &ps_tool_finalize;
113     dump_data_functions[0] = &ps_tool_dump_data;
114     timer_create_functions[0] = &ps_tool_timer_create;
115     timer_start_functions[0] = &ps_tool_timer_start;
116     timer_stop_functions[0] = &ps_tool_timer_stop;
117     set_parameter_functions[0] = &ps_tool_set_parameter;
118     dynamic_phase_start_functions[0] = &ps_tool_dynamic_phase_start;
119     dynamic_phase_stop_functions[0] = &ps_tool_dynamic_phase_stop;
120     create_counter_functions[0] = &ps_tool_create_counter;
121     sample_counter_functions[0] = &ps_tool_sample_counter;
122     set_metadata_functions[0] = &ps_tool_set_metadata;
123     get_timer_data_functions[0] = &ps_tool_get_timer_data;
124     get_counter_data_functions[0] = &ps_tool_get_counter_data;
125     get_metadata_functions[0] = &ps_tool_get_metadata;
126     free_timer_data_functions[0] = &ps_tool_free_timer_data;
127     free_counter_data_functions[0] = &ps_tool_free_counter_data;
128     free_metadata_functions[0] = &ps_tool_free_metadata;
129 #else
130     initialize_functions[0] =
131         (ps_initialize_t)dlsym(RTLD_DEFAULT, "ps_tool_initialize");
132     if (initialize_functions[0] == NULL) {
133         perfstubs_initialized = PERFSTUBS_FAILURE;
134         return;
135     }
136     printf("Found ps_tool_initialize(), registering tool\n");
137     finalize_functions[0] =
138         (ps_finalize_t)dlsym(RTLD_DEFAULT, "ps_tool_finalize");
139     register_thread_functions[0] =
140         (ps_register_thread_t)dlsym(RTLD_DEFAULT, "ps_tool_register_thread");
141     dump_data_functions[0] =
142         (ps_dump_data_t)dlsym(RTLD_DEFAULT, "ps_tool_dump_data");
143     timer_create_functions[0] =
144         (ps_timer_create_t)dlsym(RTLD_DEFAULT,
145         "ps_tool_timer_create");
146     timer_start_functions[0] =
147         (ps_timer_start_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_start");
148     timer_stop_functions[0] =
149         (ps_timer_stop_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_stop");
150     set_parameter_functions[0] =
151         (ps_set_parameter_t)dlsym(RTLD_DEFAULT, "ps_tool_set_parameter");
152     dynamic_phase_start_functions[0] = (ps_dynamic_phase_start_t)dlsym(
153         RTLD_DEFAULT, "ps_tool_dynamic_phase_start");
154     dynamic_phase_stop_functions[0] = (ps_dynamic_phase_stop_t)dlsym(
155         RTLD_DEFAULT, "ps_tool_dynamic_phase_stop");
156     create_counter_functions[0] = (ps_create_counter_t)dlsym(
157         RTLD_DEFAULT, "ps_tool_create_counter");
158     sample_counter_functions[0] = (ps_sample_counter_t)dlsym(
159         RTLD_DEFAULT, "ps_tool_sample_counter");
160     set_metadata_functions[0] =
161         (ps_set_metadata_t)dlsym(RTLD_DEFAULT, "ps_tool_set_metadata");
162     get_timer_data_functions[0] = (ps_get_timer_data_t)dlsym(
163         RTLD_DEFAULT, "ps_tool_get_timer_data");
164     get_counter_data_functions[0] = (ps_get_counter_data_t)dlsym(
165         RTLD_DEFAULT, "ps_tool_get_counter_data");
166     get_metadata_functions[0] = (ps_get_metadata_t)dlsym(
167         RTLD_DEFAULT, "ps_tool_get_metadata");
168     free_timer_data_functions[0] = (ps_free_timer_data_t)dlsym(
169         RTLD_DEFAULT, "ps_tool_free_timer_data");
170     free_counter_data_functions[0] = (ps_free_counter_data_t)dlsym(
171         RTLD_DEFAULT, "ps_tool_free_counter_data");
172     free_metadata_functions[0] = (ps_free_metadata_t)dlsym(
173         RTLD_DEFAULT, "ps_tool_free_metadata");
174 #endif
175     perfstubs_initialized = PERFSTUBS_SUCCESS;
176     /* Increment the number of tools */
177     num_tools_registered = 1;
178 #endif //PERFSTUBS_OFF
179 }
180 #ifndef PERFSTUBS_OFF
181 #pragma GCC diagnostic pop  // Restore diagnostics state
182 #endif
183 
184 char * ps_make_timer_name_(const char * file,
185     const char * func, int line) {
186     #ifndef PERFSTUBS_OFF
187     /* The length of the line number as a string is floor(log10(abs(num))) */
188     int string_length = (strlen(file) + strlen(func) + floor(log10(abs(line))) + 11);
189     char * name = (char*)calloc(string_length, sizeof(char));
190     sprintf(name, "%s [{%s} {%d,0}]", func, file, line);
191     return (name);
192     #else
193     return NULL;
194     #endif
195 }
196 
197 // used internally to the class
198 void ps_register_thread_internal(void) {
199 #ifndef PERFSTUBS_OFF
200     	int i;
201     for (i = 0 ; i < num_tools_registered ; i++) {
202         register_thread_functions[i]();
203     }
204     thread_seen = 1;
205 #endif
206 }
207 
208 /* Initialization */
209 void ps_initialize_(void) {
210 #ifndef PERFSTUBS_OFF
211     int i;
212     initialize_library();
213     for (i = 0 ; i < num_tools_registered ; i++) {
214         initialize_functions[i]();
215     }
216     /* No need to register the main thread */
217     thread_seen = 1;
218 #endif
219 }
220 
221 void ps_finalize_(void) {
222     #ifndef PERFSTUBS_OFF
223     int i;
224     for (i = 0 ; i < num_tools_registered ; i++) {
225         finalize_functions[i]();
226     }
227     #endif
228 }
229 
230 void ps_register_thread_(void) {
231 #ifndef PERFSTUBS_OFF
232     if (thread_seen == 0) {
233         ps_register_thread_internal();
234     }
235 #endif
236 }
237 
238 void* ps_timer_create_(const char *timer_name) {
239     #ifndef PERFSTUBS_OFF
240     void ** objects = (void**)calloc(num_tools_registered, sizeof(void*));
241     int i;
242     for (i = 0 ; i < num_tools_registered ; i++) {
243         objects[i] = (void*)timer_create_functions[i](timer_name);
244     }
245     return (void*)(objects);
246     #else
247     return NULL;
248     #endif
249 }
250 
251 void ps_timer_create_fortran_(void ** object, const char *timer_name) {
252     #ifndef PERFSTUBS_OFF
253     *object = ps_timer_create_(timer_name);
254     #endif
255 }
256 
257 void ps_timer_start_(const void *timer) {
258     #ifndef PERFSTUBS_OFF
259     void ** objects = (void**)(timer);
260     int i;
261     for (i = 0; i < num_tools_registered ; i++) {
262         timer_start_functions[i](objects[i]);
263     }
264     #endif
265 }
266 
267 void ps_timer_start_fortran_(const void **timer) {
268     #ifndef PERFSTUBS_OFF
269     ps_timer_start_(*timer);
270     #endif
271 }
272 
273 void ps_timer_stop_(const void *timer) {
274     #ifndef PERFSTUBS_OFF
275     void ** objects = (void**)(timer);
276     int i;
277     for (i = 0; i < num_tools_registered ; i++) {
278         timer_stop_functions[i](objects[i]);
279     }
280     #endif
281 }
282 
283 void ps_timer_stop_fortran_(const void **timer) {
284     #ifndef PERFSTUBS_OFF
285     ps_timer_stop_(*timer);
286     #endif
287 }
288 
289 void ps_set_parameter_(const char * parameter_name, int64_t parameter_value) {
290     #ifndef PERFSTUBS_OFF
291     int i;
292     for (i = 0; i < num_tools_registered ; i++) {
293         set_parameter_functions[i](parameter_name, parameter_value);
294     }
295     #endif
296 }
297 
298 void ps_dynamic_phase_start_(const char *phase_prefix, int iteration_index) {
299     #ifndef PERFSTUBS_OFF
300     int i;
301     for (i = 0; i < num_tools_registered ; i++) {
302         dynamic_phase_start_functions[i](phase_prefix, iteration_index);
303     }
304     #endif
305 }
306 
307 void ps_dynamic_phase_stop_(const char *phase_prefix, int iteration_index) {
308     #ifndef PERFSTUBS_OFF
309     int i;
310     for (i = 0; i < num_tools_registered ; i++) {
311         dynamic_phase_stop_functions[i](phase_prefix, iteration_index);
312     }
313     #endif
314 }
315 
316 void* ps_create_counter_(const char *name) {
317     #ifndef PERFSTUBS_OFF
318     void ** objects = (void**)calloc(num_tools_registered, sizeof(void*));
319     int i;
320     for (i = 0 ; i < num_tools_registered ; i++) {
321         objects[i] = (void*)create_counter_functions[i](name);
322     }
323     return (void*)(objects);
324     #else
325     return NULL;
326     #endif
327 }
328 
329 void ps_create_counter_fortran_(void ** object, const char *name) {
330     #ifndef PERFSTUBS_OFF
331     *object = ps_create_counter_(name);
332     #endif
333 }
334 
335 void ps_sample_counter_(const void *counter, const double value) {
336     #ifndef PERFSTUBS_OFF
337     void ** objects = (void**)(counter);
338     int i;
339     for (i = 0; i < num_tools_registered ; i++) {
340         sample_counter_functions[i](objects[i], value);
341     }
342     #endif
343 }
344 
345 void ps_sample_counter_fortran_(const void **counter, const double value) {
346     #ifndef PERFSTUBS_OFF
347     ps_sample_counter_(*counter, value);
348     #endif
349 }
350 
351 void ps_set_metadata_(const char *name, const char *value) {
352     #ifndef PERFSTUBS_OFF
353     int i;
354     for (i = 0; i < num_tools_registered ; i++) {
355         set_metadata_functions[i](name, value);
356     }
357     #endif
358 }
359 
360 void ps_dump_data_(void) {
361     #ifndef PERFSTUBS_OFF
362     int i;
363     for (i = 0; i < num_tools_registered ; i++) {
364         dump_data_functions[i]();
365     }
366     #endif
367 }
368 
369 void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) {
370     #ifndef PERFSTUBS_OFF
371     if (tool_id < num_tools_registered) {
372         get_timer_data_functions[tool_id](timer_data);
373     }
374     #endif
375 }
376 
377 void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) {
378     #ifndef PERFSTUBS_OFF
379     if (tool_id < num_tools_registered) {
380         get_counter_data_functions[tool_id](counter_data);
381     }
382     #endif
383 }
384 
385 void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id) {
386     #ifndef PERFSTUBS_OFF
387     if (tool_id < num_tools_registered) {
388         get_metadata_functions[tool_id](metadata);
389     }
390     #endif
391 }
392 
393 void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) {
394     #ifndef PERFSTUBS_OFF
395     if (tool_id < num_tools_registered) {
396         free_timer_data_functions[tool_id](timer_data);
397     }
398     #endif
399 }
400 
401 void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) {
402     #ifndef PERFSTUBS_OFF
403     if (tool_id < num_tools_registered) {
404         free_counter_data_functions[tool_id](counter_data);
405     }
406     #endif
407 }
408 
409 void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id) {
410     #ifndef PERFSTUBS_OFF
411     if (tool_id < num_tools_registered) {
412         free_metadata_functions[tool_id](metadata);
413     }
414     #endif
415 }
416