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