timemory 3.3.0
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"
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
42namespace tim
43{
44namespace component
45{
46//
47//--------------------------------------------------------------------------------------//
48//
49// Common PAPI configuration
50//
51//--------------------------------------------------------------------------------------//
52//
54{
55public:
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
71 {
72 TIMEMORY_DEFAULT_OBJECT(state_data)
73
77 };
78
79 //----------------------------------------------------------------------------------//
80
82 {
83 TIMEMORY_DEFAULT_OBJECT(common_data)
84
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 {
158 {
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 {
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
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 {
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 {
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 {
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());
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
348public:
349 TIMEMORY_DEFAULT_OBJECT(papi_common)
350
351protected:
353
354protected:
356 {
357 static auto _instance = vector_t<int>{};
358 return _instance;
359 }
360};
361} // namespace component
362} // namespace tim
Declare the papi component types.
return false
Definition: definition.hpp:326
const hash_alias_ptr_t hash_value_t std::string *& _ret
Definition: definition.hpp:300
void stop(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:386
void start(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:316
Definition: kokkosp.cpp:39
papi_multiplexing
Definition: settings.cpp:1711
papi_events
Definition: settings.cpp:1716
papi_overflow
Definition: settings.cpp:1718
papi_attach
Definition: settings.cpp:1717
void init(Args &&... args)
Definition: types.hpp:111
papi_fail_on_error
Definition: settings.cpp:1713
ContainerT delimit(const std::string &line, const std::string &delimiters="\"',;: ", PredicateT &&predicate=[](const std::string &s) -> std::string { return s;})
Definition: delimit.hpp:68
void consume_parameters(ArgsT &&...)
Definition: types.hpp:285
static vector_t< int > & get_events()
static common_data & data()
static vector_t< int > & private_events()
static state_data & state()
Definition: papi_common.hpp:93
typename value_type::value_type entry_type
Definition: papi_common.hpp:65
std::array< Tp, N > array_t
Definition: papi_common.hpp:60
static bool & is_configured()
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
vector_t< int > event_list
Definition: papi_common.hpp:63
static get_initializer_t & get_initializer()
vector_t< long long > value_type
Definition: papi_common.hpp:64
static void add_event(int evt)
generic functions for setting/accessing static properties on types
Definition: types.hpp:80
#define PRINT_HERE(...)
Definition: macros.hpp:152
#define TIMEMORY_EXCEPTION(...)
Definition: types.hpp:138