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