timemory  3.2.1
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
papi_common.hpp
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2020, The Regents of the University of California,
4 // through Lawrence Berkeley National Laboratory (subject to receipt of any
5 // required approvals from the U.S. Dept. of Energy). All rights reserved.
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 
25 #pragma once
26 
27 #include "timemory/components/papi/backends.hpp"
29 #include "timemory/mpl/apply.hpp"
30 #include "timemory/mpl/policy.hpp"
31 #include "timemory/mpl/types.hpp"
33 #include "timemory/units.hpp"
34 
35 #include <algorithm>
36 #include <array>
37 #include <functional>
38 #include <memory>
39 #include <string>
40 #include <vector>
41 
42 namespace tim
43 {
44 namespace component
45 {
46 //
47 //--------------------------------------------------------------------------------------//
48 //
49 // Common PAPI configuration
50 //
51 //--------------------------------------------------------------------------------------//
52 //
54 {
55 public:
56  template <typename Tp>
57  using vector_t = std::vector<Tp>;
58 
59  template <typename Tp, size_t N>
60  using array_t = std::array<Tp, N>;
61 
62  using size_type = size_t;
65  using entry_type = typename value_type::value_type;
66  using get_initializer_t = std::function<event_list()>;
67 
68  //----------------------------------------------------------------------------------//
69 
70  struct state_data
71  {
72  TIMEMORY_DEFAULT_OBJECT(state_data)
73 
74  bool is_initialized = false;
75  bool is_finalized = false;
76  bool is_working = false;
77  };
78 
79  //----------------------------------------------------------------------------------//
80 
81  struct common_data
82  {
83  TIMEMORY_DEFAULT_OBJECT(common_data)
84 
85  bool is_configured = false;
86  bool is_fixed = false;
87  int event_set = PAPI_NULL;
88  vector_t<int> events = {};
89  };
90 
91  //----------------------------------------------------------------------------------//
92 
93  static TIMEMORY_NOINLINE state_data& state()
94  {
95  static thread_local state_data _instance{};
96  return _instance;
97  }
98 
99  template <typename Tp>
100  static TIMEMORY_NOINLINE common_data& data()
101  {
102  static thread_local common_data _instance{};
103  return _instance;
104  }
105 
106  template <typename Tp>
107  static int& event_set()
108  {
109  return data<Tp>().event_set;
110  }
111 
112  template <typename Tp>
113  static bool& is_configured()
114  {
115  return data<Tp>().is_configured;
116  }
117 
118  template <typename Tp>
119  static bool& is_fixed()
120  {
121  return data<Tp>().is_fixed;
122  }
123 
124  template <typename Tp>
126  {
127  auto& _ret = data<Tp>().events;
128  if(!is_fixed<Tp>() && _ret.empty())
129  _ret = get_initializer<Tp>()();
130  return _ret;
131  }
132 
133  //----------------------------------------------------------------------------------//
134 
135  static void overflow_handler(int evt_set, void* address, long long overflow_vector,
136  void* context)
137  {
138  fprintf(stderr, "[papi_common%i]> Overflow at %p! bit=0x%llx \n", evt_set,
139  address, overflow_vector);
140  consume_parameters(context);
141  }
142 
143  //----------------------------------------------------------------------------------//
144 
145  static void add_event(int evt)
146  {
147  auto& pevents = private_events();
148  auto fitr = std::find(pevents.begin(), pevents.end(), evt);
149  if(fitr == pevents.end())
150  pevents.push_back(evt);
151  }
152 
153  //----------------------------------------------------------------------------------//
154 
155  static bool initialize_papi()
156  {
157  if(!state().is_initialized && !state().is_working)
158  {
159  if(settings::debug() || settings::verbose() > 2)
160  {
161  PRINT_HERE("Initializing papi. is initialized: %s, is working: %s",
162  state().is_initialized ? "y" : "n",
163  state().is_working ? "y" : "n");
164  }
165  papi::init();
166  papi::register_thread();
167  state().is_working = papi::working();
168  if(!state().is_working)
169  {
170  std::cerr << "Warning! PAPI failed to initialized!\n";
171  std::cerr << "The following PAPI events will not be reported: \n";
172  for(const auto& itr : get_events<void>())
173  std::cerr << " " << papi::get_event_info(itr).short_descr << "\n";
174  std::cerr << std::flush;
175  // disable all the papi APIs with concrete instantiations
177  tpls::papi, papi_array_t, papi_common, papi_vector, papi_array8_t,
178  papi_array16_t, papi_array32_t>(false);
179  }
180  else
181  {
182  state().is_initialized = true;
183  }
184  }
185  return state().is_initialized && state().is_working;
186  }
187 
188  //----------------------------------------------------------------------------------//
189 
190  static bool finalize_papi()
191  {
192  if(!state().is_finalized && state().is_working)
193  {
194  papi::unregister_thread();
195  state().is_working = papi::working();
196  if(state().is_working)
197  state().is_finalized = true;
198  }
199  return state().is_finalized && state().is_working;
200  }
201 
202  //----------------------------------------------------------------------------------//
203 
204  template <typename Tp>
206  {
207  static get_initializer_t _instance = []() {
209  {
210  fprintf(stderr, "[papi_common]> PAPI could not be initialized\n");
211  return vector_t<int>{};
212  }
213 
214  auto events_str = settings::papi_events();
215 
216  if(settings::verbose() > 1 || settings::debug())
217  {
218  printf("[papi_common]> TIMEMORY_PAPI_EVENTS: '%s'...\n",
219  events_str.c_str());
220  }
221 
222  // don't delimit colons!
223  vector_t<string_t> events_str_list = delimit(events_str, "\"',; ");
224  vector_t<int> events_list;
225 
226  auto& pevents = private_events();
227  for(int& pevent : pevents)
228  {
229  auto fitr = std::find(events_list.begin(), events_list.end(), pevent);
230  if(fitr == events_list.end())
231  events_list.push_back(pevent);
232  }
233 
234  for(const auto& itr : events_str_list)
235  {
236  if(itr.length() == 0)
237  continue;
238 
239  if(settings::debug())
240  {
241  printf("[papi_common]> Getting event code from '%s'...\n",
242  itr.c_str());
243  }
244 
245  int evt_code = papi::get_event_code(itr);
246  if(evt_code == PAPI_NOT_INITED) // defined as zero
247  {
248  std::stringstream ss;
249  ss << "[papi_common] Error creating event with ID: " << itr;
251  {
252  TIMEMORY_EXCEPTION(ss.str());
253  }
254  else
255  {
256  fprintf(stderr, "%s\n", ss.str().c_str());
257  }
258  }
259  else
260  {
261  auto fitr =
262  std::find(events_list.begin(), events_list.end(), evt_code);
263  if(fitr == events_list.end())
264  {
265  if(settings::debug() || settings::verbose() > 1)
266  {
267  printf("[papi_common] Successfully created event '%s' with "
268  "code '%i'...\n",
269  itr.c_str(), evt_code);
270  }
271  events_list.push_back(evt_code);
272  }
273  else
274  {
275  if(settings::debug() || settings::verbose() > 1)
276  {
277  printf("[papi_common] Event '%s' with code '%i' already "
278  "exists...\n",
279  itr.c_str(), evt_code);
280  }
281  }
282  }
283  }
284 
285  return events_list;
286  };
287  return _instance;
288  }
289 
290  //----------------------------------------------------------------------------------//
291 
292  template <typename Tp>
293  static void initialize()
294  {
295  if(!is_configured<Tp>() && initialize_papi())
296  {
297  auto& _event_set = event_set<Tp>();
298  auto& _events = get_events<Tp>();
299  if(!_events.empty())
300  {
301  if(settings::debug() || settings::verbose() > 1)
302  PRINT_HERE("configuring %i papi events", (int) _events.size());
303  papi::create_event_set(&_event_set, settings::papi_multiplexing());
304  papi::add_events(_event_set, _events.data(), _events.size());
305  if(settings::papi_overflow() > 0)
306  {
307  for(auto itr : _events)
308  {
309  papi::overflow(_event_set, itr, settings::papi_overflow(), 0,
311  }
312  }
314  papi::attach(_event_set, process::get_target_id());
315  papi::start(_event_set);
316  is_configured<Tp>() = papi::working();
317  }
318  if(!is_configured<Tp>())
319  {
320  PRINT_HERE("Warning! Configuring %i papi events failed",
321  (int) _events.size());
322  }
323  }
324  }
325 
326  //----------------------------------------------------------------------------------//
327 
328  template <typename Tp>
329  static void finalize()
330  {
331  if(!initialize_papi())
332  return;
333  auto& _event_set = event_set<Tp>();
334  auto& _events = get_events<Tp>();
335  if(!_events.empty() && _event_set != PAPI_NULL && _event_set >= 0)
336  {
337  value_type values(_events.size(), 0);
338  papi::stop(_event_set, values.data());
339  papi::remove_events(_event_set, _events.data(), _events.size());
340  papi::destroy_event_set(_event_set);
341  _event_set = PAPI_NULL;
342  _events.clear();
343  }
344  }
345 
346  //----------------------------------------------------------------------------------//
347 
348 public:
349  TIMEMORY_DEFAULT_OBJECT(papi_common)
350 
351 protected:
353 
354 protected:
356  {
357  static auto _instance = vector_t<int>{};
358  return _instance;
359  }
360 };
361 } // namespace component
362 } // namespace tim
Declare the papi component types.
void stop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:368
void start(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:298
Definition: kokkosp.cpp:38
papi_multiplexing
Definition: settings.cpp:1405
papi_events
Definition: settings.cpp:1410
papi_overflow
Definition: settings.cpp:1412
void consume_parameters(ArgsT &&...) TIMEMORY_HIDDEN
Definition: types.hpp:285
papi_attach
Definition: settings.cpp:1411
void init(Args &&... args)
Definition: types.hpp:111
papi_fail_on_error
Definition: settings.cpp:1407
ContainerT delimit(const std::string &line, const std::string &delimiters="\"',;: ", PredicateT &&predicate=[](const std::string &s) -> std::string { return s;})
Definition: utility.hpp:666
The declaration for the types for settings without definitions.
static bool & is_configured()
typename value_type::value_type entry_type
Definition: papi_common.hpp:65
static get_initializer_t & get_initializer()
std::array< Tp, N > array_t
Definition: papi_common.hpp:60
static vector_t< int > & get_events()
static void overflow_handler(int evt_set, void *address, long long overflow_vector, void *context)
std::vector< Tp > vector_t
Definition: papi_common.hpp:57
std::function< event_list()> get_initializer_t
Definition: papi_common.hpp:66
static vector_t< int > & private_events()
vector_t< int > event_list
Definition: papi_common.hpp:63
vector_t< long long > value_type
Definition: papi_common.hpp:64
static common_data & data()
static void add_event(int evt)
static state_data & state()
Definition: papi_common.hpp:93
generic functions for setting/accessing static properties on types
Definition: types.hpp:80
#define PRINT_HERE(...)
Definition: macros.hpp:147
#define TIMEMORY_EXCEPTION(...)
Definition: types.hpp:137