NEURON
profiler_interface.h
Go to the documentation of this file.
1 /*
2 # =============================================================================
3 # Copyright (c) 2016 - 2021 Blue Brain Project/EPFL
4 #
5 # See top-level LICENSE file for details.
6 # =============================================================================
7 */
8 
9 #pragma once
10 
11 #include <cstdlib>
12 #include <initializer_list>
13 #include <sstream>
14 #include <string>
15 #include <type_traits>
16 #include <unordered_set>
17 
18 #if defined(NRN_CALIPER)
19 #include <caliper/cali.h>
20 #endif
21 
22 #ifdef CORENEURON_CUDA_PROFILING
23 #include <cuda_profiler_api.h>
24 #endif
25 
26 #if defined(CRAYPAT)
27 #include <pat_api.h>
28 #endif
29 
30 #if defined(TAU)
31 #include <TAU.h>
32 #endif
33 
34 #if defined(LIKWID_PERFMON)
35 #include <likwid.h>
36 #endif
37 
38 namespace coreneuron {
39 
40 namespace detail {
41 
42 /*! \class Instrumentor
43  * \brief Instrumentation infrastructure for benchmarking and profiling.
44  *
45  * The Instrumentor class exposes static methods that can be used to
46  * toggle with fine-grained resolution the profiling of specific
47  * areas within the code.
48  */
49 template <class... TProfilerImpl>
50 struct Instrumentor {
51 #ifdef __clang__
52 #pragma clang diagnostic push
53 #pragma clang diagnostic ignored "-Wunused-value"
54 #endif // __clang__
55  /*! \fn phase_begin
56  * \brief Activate the collection of profiling data within a code region.
57  *
58  * This function semantically defines the beginning of a region
59  * of code that the user wishes to profile.
60  * Loops through all enabled profilers and calls the relevant
61  * `phase_begin` function.
62  * This function should have a non-empty implementation only for
63  * profilers that allow multiple code regions with different names
64  * to be profiled concurrently.
65  *
66  * @param name the (unique) identifier of the code region to be profiled
67  */
68  inline static void phase_begin(const char* name) {
69  if (is_region_to_track(name)) {
70  std::initializer_list<int>{(TProfilerImpl::phase_begin(name), 0)...};
71  }
72  }
73 
74  /*! \fn phase_end
75  * \brief Deactivate the collection of profiling data within a code region.
76  *
77  * This function semantically defines the end of a region
78  * of code that the user wishes to profile.
79  * Loops through all enabled profilers and calls the relevant
80  * `phase_end` function.
81  * This function should have a non-empty implementation only for
82  * profilers that allow multiple code regions with different names
83  * to be profiled concurrently.
84  *
85  * @param name the (unique) identifier of the code region to be profiled
86  */
87  inline static void phase_end(const char* name) {
88  if (is_region_to_track(name)) {
89  std::initializer_list<int>{(TProfilerImpl::phase_end(name), 0)...};
90  }
91  }
92 
93  /*! \fn start_profile
94  * \brief Globally activate the collection of profiling data.
95  *
96  * Activate the collection of profiler data without defining
97  * a region of interest with a given name, as opposed to `phase_begin`.
98  * Loops through all enabled profilers and calls the relevant
99  * `start_profile` function.
100  * This function should have a non-empty implementation only for
101  * profilers that expose simply a global begin/end interface, without
102  * named regions.
103  */
104  inline static void start_profile() {
105  std::initializer_list<int>{(TProfilerImpl::start_profile(), 0)...};
106  }
107 
108  /*! \fn stop_profile
109  * \brief Globally deactivate the collection of profiling data.
110  *
111  * Deactivate the collection of profiler data without defining
112  * a region of interest with a given name, as opposed to `phase_end`.
113  * Loops through all enabled profilers and calls the relevant
114  * `stop_profile` function.
115  * This function should have a non-empty implementation only for
116  * profilers that expose simply a global begin/end interface, without
117  * named regions.
118  */
119  inline static void stop_profile() {
120  std::initializer_list<int>{(TProfilerImpl::stop_profile(), 0)...};
121  }
122 
123  /*! \fn init_profile
124  * \brief Initialize the profiler.
125  *
126  * Initialize a profiler's internal structure, without activating yet
127  * any data collection, similar in concept to MPI_Init.
128  * Loops through all enabled profilers and calls the relevant
129  * `init_profile` function.
130  * This function should have a non-empty implementation only for
131  * profilers that require special initialization, typically before
132  * any memory allocation is done.
133  */
134  inline static void init_profile() {
136  std::initializer_list<int>{(TProfilerImpl::init_profile(), 0)...};
137  }
138 
139  /*! \fn finalize_profile
140  * \brief Finalize the profiler.
141  *
142  * Finalize a profiler's internal structure, without activating yet
143  * any data collection, similar in concept to MPI_Finalize.
144  * Loops through all enabled profilers and calls the relevant
145  * `finalize_profile` function.
146  * This function should have a non-empty implementation only for
147  * profilers that require special finalization.
148  */
149  inline static void finalize_profile() {
150  std::initializer_list<int>{(TProfilerImpl::finalize_profile(), 0)...};
151  }
152 #ifdef __clang__
153 #pragma clang diagnostic pop
154 #endif // __clang__
155 
156  private:
157  /*!
158  * \brief Initialize regions to track from the NRN_PROFILE_REGIONS environment variable.
159  *
160  * Checks if the `NRN_PROFILE_REGIONS` environment variable is set. If it is set,
161  * splits the value by "," and inserts each split string into the regions that should
162  * be measured during profiling.
163  */
165  const char* env_p = std::getenv("NRN_PROFILE_REGIONS");
166  if (env_p) {
167  std::string regions_str(env_p);
168  std::stringstream ss(regions_str);
169  std::string region;
170  regions_to_measure.clear();
171  while (std::getline(ss, region, ',')) {
172  regions_to_measure.insert(region);
173  }
174  }
175  }
176 
177  /*!
178  * \brief Check if a given region name should be tracked.
179  *
180  * By default the regions_to_measure set is empty and we measure all functions
181  * instrumented via Caliper instrumentation. But one might want to profile only
182  * particular region or "phase" (e.g. due to profiling overhead) and in that case
183  * we check `NRN_PROFILE_REGIONS` environment variable.
184  *
185  * \param name The name of the region to check.
186  * \return true if the regions set is empty or if the name exists in the regions set, false
187  * otherwise.
188  */
189  inline static bool is_region_to_track(const char* name) {
190  if (regions_to_measure.empty()) {
191  return true;
192  }
193  return regions_to_measure.find(name) != regions_to_measure.end();
194  }
195 
196  /*!
197  * \brief Caliper regions that we want to measure.
198  *
199  * Each string in the set represents the name of a region of interest that
200  * we have already defined via Instrumentor::phase API.
201  */
202  static std::unordered_set<std::string> regions_to_measure;
203 };
204 
205 template <class... TProfilerImpl>
206 inline std::unordered_set<std::string> Instrumentor<TProfilerImpl...>::regions_to_measure;
207 
208 #if defined(NRN_CALIPER)
209 
210 struct Caliper {
211  inline static void phase_begin(const char* name) {
212  CALI_MARK_BEGIN(name);
213  };
214 
215  inline static void phase_end(const char* name) {
216  CALI_MARK_END(name);
217  };
218 
219  inline static void start_profile(){};
220 
221  inline static void stop_profile(){};
222 
223  inline static void init_profile(){};
224 
225  inline static void finalize_profile(){};
226 };
227 
228 #endif
229 
230 #ifdef CORENEURON_CUDA_PROFILING
231 
232 struct CudaProfiling {
233  inline static void phase_begin(const char* name){};
234 
235  inline static void phase_end(const char* name){};
236 
237  inline static void start_profile() {
238  cudaProfilerStart();
239  };
240 
241  inline static void stop_profile() {
242  cudaProfilerStop();
243  };
244 
245  inline static void init_profile(){};
246 
247  inline static void finalize_profile(){};
248 };
249 
250 #endif
251 
252 #if defined(CRAYPAT)
253 
254 struct CrayPat {
255  inline static void phase_begin(const char* name){};
256 
257  inline static void phase_end(const char* name){};
258 
259  inline static void start_profile() {
260  PAT_record(PAT_STATE_ON);
261  };
262 
263  inline static void stop_profile() {
264  PAT_record(PAT_STATE_OFF);
265  };
266 
267  inline static void init_profile(){};
268 
269  inline static void finalize_profile(){};
270 };
271 #endif
272 
273 #if defined(TAU)
274 
275 struct Tau {
276  inline static void phase_begin(const char* name){};
277 
278  inline static void phase_end(const char* name){};
279 
280  inline static void start_profile() {
281  TAU_ENABLE_INSTRUMENTATION();
282  };
283 
284  inline static void stop_profile() {
285  TAU_DISABLE_INSTRUMENTATION();
286  };
287 
288  inline static void init_profile(){};
289 
290  inline static void finalize_profile(){};
291 };
292 
293 #endif
294 
295 #if defined(LIKWID_PERFMON)
296 
297 struct Likwid {
298  inline static void phase_begin(const char* name) {
299  LIKWID_MARKER_START(name);
300  };
301 
302  inline static void phase_end(const char* name) {
303  LIKWID_MARKER_STOP(name);
304  };
305 
306  inline static void start_profile(){};
307 
308  inline static void stop_profile(){};
309 
310  inline static void init_profile() {
311  LIKWID_MARKER_INIT;
312 
313 #pragma omp parallel
314  { LIKWID_MARKER_THREADINIT; }
315  };
316 
317  inline static void finalize_profile() {
318  LIKWID_MARKER_CLOSE;
319  };
320 };
321 
322 #endif
323 
325  inline static void phase_begin(const char* name){};
326  inline static void phase_end(const char* name){};
327  inline static void start_profile(){};
328  inline static void stop_profile(){};
329  inline static void init_profile(){};
330  inline static void finalize_profile(){};
331 };
332 
334 #if defined NRN_CALIPER
335  detail::Caliper,
336 #endif
337 #ifdef CORENEURON_CUDA_PROFILING
338  detail::CudaProfiling,
339 #endif
340 #if defined(CRAYPAT)
341  detail::CrayPat,
342 #endif
343 #if defined(TAU)
344  detail::Tau,
345 #endif
346 #if defined(LIKWID_PERFMON)
347  detail::Likwid,
348 #endif
350 } // namespace detail
351 
352 namespace Instrumentor {
353 struct phase {
354  const char* phase_name;
355  phase(const char* name)
356  : phase_name(name) {
358  }
359  ~phase() {
361  }
362 };
363 
364 inline static void start_profile() {
366 }
367 
368 inline static void stop_profile() {
370 }
371 
372 inline static void phase_begin(const char* name) {
374 }
375 
376 inline static void phase_end(const char* name) {
378 }
379 
380 inline static void init_profile() {
382 }
383 
384 inline static void finalize_profile() {
386 }
387 } // namespace Instrumentor
388 
389 } // namespace coreneuron
const char * name
Definition: init.cpp:16
static void phase_end(const char *name)
static void phase_begin(const char *name)
THIS FILE IS AUTO GENERATED DONT MODIFY IT.
Instrumentation infrastructure for benchmarking and profiling.
static void initialize_regions_from_env()
Initialize regions to track from the NRN_PROFILE_REGIONS environment variable.
static void start_profile()
Globally activate the collection of profiling data.
static void finalize_profile()
Finalize the profiler.
static void stop_profile()
Globally deactivate the collection of profiling data.
static bool is_region_to_track(const char *name)
Check if a given region name should be tracked.
static std::unordered_set< std::string > regions_to_measure
Caliper regions that we want to measure.
static void init_profile()
Initialize the profiler.
static void phase_end(const char *name)
Deactivate the collection of profiling data within a code region.
static void phase_begin(const char *name)
Activate the collection of profiling data within a code region.
static void phase_begin(const char *name)
static void phase_end(const char *name)