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
initialize_library(void)108 void initialize_library(void) {
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) return;
114 printf("Found ps_tool_initialize(), registering tool\n");
115 register_thread_functions[0] = &ps_tool_register_thread;
116 finalize_functions[0] = &ps_tool_finalize;
117 dump_data_functions[0] = &ps_tool_dump_data;
118 timer_create_functions[0] = &ps_tool_timer_create;
119 timer_start_functions[0] = &ps_tool_timer_start;
120 timer_stop_functions[0] = &ps_tool_timer_stop;
121 set_parameter_functions[0] = &ps_tool_set_parameter;
122 dynamic_phase_start_functions[0] = &ps_tool_dynamic_phase_start;
123 dynamic_phase_stop_functions[0] = &ps_tool_dynamic_phase_stop;
124 create_counter_functions[0] = &ps_tool_create_counter;
125 sample_counter_functions[0] = &ps_tool_sample_counter;
126 set_metadata_functions[0] = &ps_tool_set_metadata;
127 get_timer_data_functions[0] = &ps_tool_get_timer_data;
128 get_counter_data_functions[0] = &ps_tool_get_counter_data;
129 get_metadata_functions[0] = &ps_tool_get_metadata;
130 free_timer_data_functions[0] = &ps_tool_free_timer_data;
131 free_counter_data_functions[0] = &ps_tool_free_counter_data;
132 free_metadata_functions[0] = &ps_tool_free_metadata;
133 #else
134 initialize_functions[0] =
135 (ps_initialize_t)dlsym(RTLD_DEFAULT, "ps_tool_initialize");
136 if (initialize_functions[0] == NULL) {
137 perfstubs_initialized = PERFSTUBS_FAILURE;
138 return;
139 }
140 printf("Found ps_tool_initialize(), registering tool\n");
141 finalize_functions[0] =
142 (ps_finalize_t)dlsym(RTLD_DEFAULT, "ps_tool_finalize");
143 register_thread_functions[0] =
144 (ps_register_thread_t)dlsym(RTLD_DEFAULT, "ps_tool_register_thread");
145 dump_data_functions[0] =
146 (ps_dump_data_t)dlsym(RTLD_DEFAULT, "ps_tool_dump_data");
147 timer_create_functions[0] =
148 (ps_timer_create_t)dlsym(RTLD_DEFAULT,
149 "ps_tool_timer_create");
150 timer_start_functions[0] =
151 (ps_timer_start_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_start");
152 timer_stop_functions[0] =
153 (ps_timer_stop_t)dlsym(RTLD_DEFAULT, "ps_tool_timer_stop");
154 set_parameter_functions[0] =
155 (ps_set_parameter_t)dlsym(RTLD_DEFAULT, "ps_tool_set_parameter");
156 dynamic_phase_start_functions[0] = (ps_dynamic_phase_start_t)dlsym(
157 RTLD_DEFAULT, "ps_tool_dynamic_phase_start");
158 dynamic_phase_stop_functions[0] = (ps_dynamic_phase_stop_t)dlsym(
159 RTLD_DEFAULT, "ps_tool_dynamic_phase_stop");
160 create_counter_functions[0] = (ps_create_counter_t)dlsym(
161 RTLD_DEFAULT, "ps_tool_create_counter");
162 sample_counter_functions[0] = (ps_sample_counter_t)dlsym(
163 RTLD_DEFAULT, "ps_tool_sample_counter");
164 set_metadata_functions[0] =
165 (ps_set_metadata_t)dlsym(RTLD_DEFAULT, "ps_tool_set_metadata");
166 get_timer_data_functions[0] = (ps_get_timer_data_t)dlsym(
167 RTLD_DEFAULT, "ps_tool_get_timer_data");
168 get_counter_data_functions[0] = (ps_get_counter_data_t)dlsym(
169 RTLD_DEFAULT, "ps_tool_get_counter_data");
170 get_metadata_functions[0] = (ps_get_metadata_t)dlsym(
171 RTLD_DEFAULT, "ps_tool_get_metadata");
172 free_timer_data_functions[0] = (ps_free_timer_data_t)dlsym(
173 RTLD_DEFAULT, "ps_tool_free_timer_data");
174 free_counter_data_functions[0] = (ps_free_counter_data_t)dlsym(
175 RTLD_DEFAULT, "ps_tool_free_counter_data");
176 free_metadata_functions[0] = (ps_free_metadata_t)dlsym(
177 RTLD_DEFAULT, "ps_tool_free_metadata");
178 #endif
179 perfstubs_initialized = PERFSTUBS_SUCCESS;
180 /* Increment the number of tools */
181 num_tools_registered = 1;
182 #endif //PERFSTUBS_OFF
183 }
184 #ifndef PERFSTUBS_OFF
185 #pragma GCC diagnostic pop // Restore diagnostics state
186 #endif
187
ps_make_timer_name_(const char * file,const char * func,int line)188 char * ps_make_timer_name_(const char * file,
189 const char * func, int line) {
190 #ifndef PERFSTUBS_OFF
191 /* The length of the line number as a string is floor(log10(abs(num))) */
192 int string_length = (int) ((strlen(file) + strlen(func) + floor(log10(abs(line))) + 11));
193 char * name = (char*)calloc(string_length, sizeof(char));
194 sprintf(name, "%s [{%s} {%d,0}]", func, file, line);
195 return (name);
196 #else
197 return NULL;
198 #endif
199 }
200
201 // used internally to the class
ps_register_thread_internal(void)202 void ps_register_thread_internal(void) {
203 #ifndef PERFSTUBS_OFF
204 int i;
205 for (i = 0 ; i < num_tools_registered ; i++) register_thread_functions[i]();
206 thread_seen = 1;
207 #endif
208 }
209
210 /* Initialization */
ps_initialize_(void)211 void ps_initialize_(void) {
212 #ifndef PERFSTUBS_OFF
213 int i;
214 initialize_library();
215 for (i = 0 ; i < num_tools_registered ; i++) initialize_functions[i]();
216 /* No need to register the main thread */
217 thread_seen = 1;
218 #endif
219 }
220
ps_finalize_(void)221 void ps_finalize_(void) {
222 #ifndef PERFSTUBS_OFF
223 int i;
224 for (i = 0 ; i < num_tools_registered ; i++) finalize_functions[i]();
225 #endif
226 }
227
ps_register_thread_(void)228 void ps_register_thread_(void) {
229 #ifndef PERFSTUBS_OFF
230 if (thread_seen == 0) ps_register_thread_internal();
231 #endif
232 }
233
ps_timer_create_(const char * timer_name)234 void* ps_timer_create_(const char *timer_name) {
235 #ifndef PERFSTUBS_OFF
236 void ** objects = (void**)calloc(num_tools_registered, sizeof(void*));
237 int i;
238 for (i = 0 ; i < num_tools_registered ; i++) objects[i] = timer_create_functions[i](timer_name);
239 return (void*)(objects);
240 #else
241 return NULL;
242 #endif
243 }
244
ps_timer_destroy_(void * objects)245 void ps_timer_destroy_(void *objects) {
246 #ifndef PERFSTUBS_OFF
247 free(objects);
248 #endif
249 }
250
ps_timer_create_fortran_(void ** object,const char * timer_name)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
ps_timer_start_(const void * timer)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++) timer_start_functions[i](objects[i]);
262 #endif
263 }
264
ps_timer_start_fortran_(const void ** timer)265 void ps_timer_start_fortran_(const void **timer) {
266 #ifndef PERFSTUBS_OFF
267 ps_timer_start_(*timer);
268 #endif
269 }
270
ps_timer_stop_(const void * timer)271 void ps_timer_stop_(const void *timer) {
272 #ifndef PERFSTUBS_OFF
273 void ** objects = (void**)(timer);
274 int i;
275 for (i = 0; i < num_tools_registered ; i++) timer_stop_functions[i](objects[i]);
276 #endif
277 }
278
ps_timer_stop_fortran_(const void ** timer)279 void ps_timer_stop_fortran_(const void **timer) {
280 #ifndef PERFSTUBS_OFF
281 ps_timer_stop_(*timer);
282 #endif
283 }
284
ps_set_parameter_(const char * parameter_name,int64_t parameter_value)285 void ps_set_parameter_(const char * parameter_name, int64_t parameter_value) {
286 #ifndef PERFSTUBS_OFF
287 int i;
288 for (i = 0; i < num_tools_registered ; i++) set_parameter_functions[i](parameter_name, parameter_value);
289 #endif
290 }
291
ps_dynamic_phase_start_(const char * phase_prefix,int iteration_index)292 void ps_dynamic_phase_start_(const char *phase_prefix, int iteration_index) {
293 #ifndef PERFSTUBS_OFF
294 int i;
295 for (i = 0; i < num_tools_registered ; i++) dynamic_phase_start_functions[i](phase_prefix, iteration_index);
296 #endif
297 }
298
ps_dynamic_phase_stop_(const char * phase_prefix,int iteration_index)299 void ps_dynamic_phase_stop_(const char *phase_prefix, int iteration_index) {
300 #ifndef PERFSTUBS_OFF
301 int i;
302 for (i = 0; i < num_tools_registered ; i++) dynamic_phase_stop_functions[i](phase_prefix, iteration_index);
303 #endif
304 }
305
ps_create_counter_(const char * name)306 void* ps_create_counter_(const char *name) {
307 #ifndef PERFSTUBS_OFF
308 void ** objects = (void**)calloc(num_tools_registered, sizeof(void*));
309 int i;
310 for (i = 0 ; i < num_tools_registered ; i++) objects[i] = create_counter_functions[i](name);
311 return (void*)(objects);
312 #else
313 return NULL;
314 #endif
315 }
316
ps_create_counter_fortran_(void ** object,const char * name)317 void ps_create_counter_fortran_(void ** object, const char *name) {
318 #ifndef PERFSTUBS_OFF
319 *object = ps_create_counter_(name);
320 #endif
321 }
322
ps_sample_counter_(const void * counter,const double value)323 void ps_sample_counter_(const void *counter, const double value) {
324 #ifndef PERFSTUBS_OFF
325 void ** objects = (void**)(counter);
326 int i;
327 for (i = 0; i < num_tools_registered ; i++) sample_counter_functions[i](objects[i], value);
328 #endif
329 }
330
ps_sample_counter_fortran_(const void ** counter,const double value)331 void ps_sample_counter_fortran_(const void **counter, const double value) {
332 #ifndef PERFSTUBS_OFF
333 ps_sample_counter_(*counter, value);
334 #endif
335 }
336
ps_set_metadata_(const char * name,const char * value)337 void ps_set_metadata_(const char *name, const char *value) {
338 #ifndef PERFSTUBS_OFF
339 int i;
340 for (i = 0; i < num_tools_registered ; i++) set_metadata_functions[i](name, value);
341 #endif
342 }
343
ps_dump_data_(void)344 void ps_dump_data_(void) {
345 #ifndef PERFSTUBS_OFF
346 int i;
347 for (i = 0; i < num_tools_registered ; i++) dump_data_functions[i]();
348 #endif
349 }
350
ps_get_timer_data_(ps_tool_timer_data_t * timer_data,int tool_id)351 void ps_get_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) {
352 #ifndef PERFSTUBS_OFF
353 if (tool_id < num_tools_registered) get_timer_data_functions[tool_id](timer_data);
354 #endif
355 }
356
ps_get_counter_data_(ps_tool_counter_data_t * counter_data,int tool_id)357 void ps_get_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) {
358 #ifndef PERFSTUBS_OFF
359 if (tool_id < num_tools_registered) get_counter_data_functions[tool_id](counter_data);
360 #endif
361 }
362
ps_get_metadata_(ps_tool_metadata_t * metadata,int tool_id)363 void ps_get_metadata_(ps_tool_metadata_t *metadata, int tool_id) {
364 #ifndef PERFSTUBS_OFF
365 if (tool_id < num_tools_registered) get_metadata_functions[tool_id](metadata);
366 #endif
367 }
368
ps_free_timer_data_(ps_tool_timer_data_t * timer_data,int tool_id)369 void ps_free_timer_data_(ps_tool_timer_data_t *timer_data, int tool_id) {
370 #ifndef PERFSTUBS_OFF
371 if (tool_id < num_tools_registered) free_timer_data_functions[tool_id](timer_data);
372 #endif
373 }
374
ps_free_counter_data_(ps_tool_counter_data_t * counter_data,int tool_id)375 void ps_free_counter_data_(ps_tool_counter_data_t *counter_data, int tool_id) {
376 #ifndef PERFSTUBS_OFF
377 if (tool_id < num_tools_registered) free_counter_data_functions[tool_id](counter_data);
378 #endif
379 }
380
ps_free_metadata_(ps_tool_metadata_t * metadata,int tool_id)381 void ps_free_metadata_(ps_tool_metadata_t *metadata, int tool_id) {
382 #ifndef PERFSTUBS_OFF
383 if (tool_id < num_tools_registered) free_metadata_functions[tool_id](metadata);
384 #endif
385 }
386