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_tuple.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 
28 #include "timemory/components/papi/backends.hpp"
31 #include "timemory/mpl/policy.hpp"
32 #include "timemory/mpl/types.hpp"
33 #include "timemory/units.hpp"
34 
35 #include <array>
36 #include <functional>
37 #include <memory>
38 #include <sstream>
39 #include <string>
40 #include <vector>
41 
42 namespace tim
43 {
44 namespace component
45 {
46 /// \struct tim::component::papi_tuple
47 /// \tparam EventTypes Compile-time constant list of PAPI event identifiers
48 ///
49 /// \brief This component is useful for bundling together a fixed set of hardware counter
50 /// identifiers which require no runtime configuration
51 ///
52 /// \code{.cpp}
53 /// // the "Instructions" alias below explicitly collects the total instructions,
54 /// // the number of load instructions, the number of store instructions
55 /// using Instructions = papi_tuple<PAPI_TOT_INS, PAPI_LD_INS, PAPI_SR_INS>;
56 ///
57 /// Instructions inst{};
58 /// inst.start();
59 /// ...
60 /// inst.stop();
61 /// std::vector<double> data = inst.get();
62 ///
63 /// \endcode
64 template <int... EventTypes>
65 struct papi_tuple
66 : public base<papi_tuple<EventTypes...>, std::array<long long, sizeof...(EventTypes)>>
67 , private policy::instance_tracker<papi_tuple<EventTypes...>>
68 , private papi_common
69 {
70  using size_type = std::size_t;
71  using value_type = std::array<long long, sizeof...(EventTypes)>;
72  using entry_type = typename value_type::value_type;
73  using this_type = papi_tuple<EventTypes...>;
78 
79  static const size_type num_events = sizeof...(EventTypes);
80  template <typename Tp>
81  using array_t = std::array<Tp, num_events>;
82 
83  friend struct operation::record<this_type>;
84  friend struct operation::start<this_type>;
85  friend struct operation::stop<this_type>;
86  friend struct operation::set_started<this_type>;
87  friend struct operation::set_stopped<this_type>;
88 
89 public:
90  //----------------------------------------------------------------------------------//
91 
92  static void configure()
93  {
94  if(!is_configured<common_type>())
95  {
96  papi_common::get_initializer<common_type>() = []() {
97  return std::vector<int>({ EventTypes... });
98  };
99  papi_common::get_events<common_type>() = { EventTypes... };
100  papi_common::initialize<common_type>();
101  }
102  }
103  static void thread_init() { this_type::configure(); }
104  static void thread_finalize()
105  {
106  papi_common::finalize<common_type>();
108  }
109  static void initialize() { configure(); }
110  static void finalize() { papi_common::finalize<common_type>(); }
111 
112  //----------------------------------------------------------------------------------//
113 
115  {
116  if(is_configured<common_type>())
117  tim::papi::read(event_set<common_type>(), get_read_values().data());
118  return get_read_values();
119  }
120 
121 private:
122  static value_type& get_read_values()
123  {
124  static thread_local value_type _instance = []() {
125  value_type values;
126  mpl::apply<void>::set_value(values, 0);
127  return values;
128  }();
129  return _instance;
130  }
131 
132 protected:
133  using base_type::accum;
134  using base_type::laps;
137  using base_type::value;
138 
139  friend struct base<this_type, value_type>;
140  friend class impl::storage<this_type,
141  trait::uses_value_storage<this_type, value_type>::value>;
142 
143 public:
144  //==================================================================================//
145  //
146  // construction
147  //
148  //==================================================================================//
149 
150  TIMEMORY_DEFAULT_OBJECT(papi_tuple)
151 
152  using base_type::load;
153 
154  //----------------------------------------------------------------------------------//
155  // sample
156  //
157  void sample()
158  {
159  if(tracker_type::get_thread_started() == 0)
160  configure();
161  if(events.empty())
162  events = get_events<common_type>();
163 
165  value = record();
166  }
167 
168  //----------------------------------------------------------------------------------//
169  // start
170  //
171  void start()
172  {
173  if(tracker_type::get_thread_started() == 0 || events.size() == 0)
174  {
175  configure();
176  events = get_events<common_type>();
177  }
178 
180  value = record();
181  }
182 
183  //----------------------------------------------------------------------------------//
184  // start
185  //
186  void stop()
187  {
189  using namespace tim::component::operators;
190  value = (record() - value);
191  accum += value;
192  }
193 
194  //----------------------------------------------------------------------------------//
195  // operators
196  //
198  {
199  for(size_type i = 0; i < num_events; ++i)
200  accum[i] += rhs.accum[i];
201  for(size_type i = 0; i < num_events; ++i)
202  value[i] += rhs.value[i];
203  return *this;
204  }
205 
207  {
208  for(size_type i = 0; i < num_events; ++i)
209  accum[i] -= rhs.accum[i];
210  for(size_type i = 0; i < num_events; ++i)
211  value[i] -= rhs.value[i];
212  return *this;
213  }
214 
215 public:
216  //==================================================================================//
217  //
218  // data representation
219  //
220  //==================================================================================//
221  static const short precision = 3;
222  static const short width = 12;
223 
224  // leave these empty
226  {
227  return "papi" + std::to_string(event_set<common_type>());
228  }
229  static std::string description() { return ""; }
230  static std::string display_unit() { return ""; }
231  static int64_t unit() { return 1; }
232 
233  //----------------------------------------------------------------------------------//
234  // serialization
235  //
236  template <typename Archive>
237  void serialize(Archive& ar, const unsigned int)
238  {
239  array_t<double> _disp;
240  array_t<double> _value;
241  array_t<double> _accum;
242  for(size_type i = 0; i < num_events; ++i)
243  {
244  _disp[i] = get_display(i);
245  _value[i] = value[i];
246  _accum[i] = accum[i];
247  }
248  ar(cereal::make_nvp("laps", laps), cereal::make_nvp("repr_data", _disp),
249  cereal::make_nvp("value", _value), cereal::make_nvp("accum", _accum),
250  cereal::make_nvp("display", _disp));
251  }
252 
253  entry_type get_display(int evt_type) const { return accum[evt_type]; }
254 
255  TIMEMORY_NODISCARD string_t get_display() const
256  {
257  auto val = load();
258  auto _get_display = [&](std::ostream& os, size_type idx) {
259  auto _obj_value = val[idx];
260  auto _evt_type = std::vector<int>({ EventTypes... }).at(idx);
261  string_t _label = papi::get_event_info(_evt_type).short_descr;
262  string_t _disp = papi::get_event_info(_evt_type).units;
263  auto _prec = base_type::get_precision();
264  auto _width = base_type::get_width();
265  auto _flags = base_type::get_format_flags();
266 
267  std::stringstream ss;
268  std::stringstream ssv;
269  std::stringstream ssi;
270  ssv.setf(_flags);
271  ssv << std::setw(_width) << std::setprecision(_prec) << _obj_value;
272  if(!_disp.empty())
273  {
274  ssv << " " << _disp;
275  }
276  else if(!_label.empty())
277  {
278  ssi << " " << _label;
279  }
280  ss << ssv.str() << ssi.str();
281  os << ss.str();
282  };
283  std::stringstream ss;
284  for(size_type i = 0; i < num_events; ++i)
285  {
286  _get_display(ss, i);
287  if(i + 1 < num_events)
288  ss << ", ";
289  }
290  return ss.str();
291  }
292 
293  template <typename Lhs, typename Rhs, size_t N, size_t... Idx>
294  static void convert(std::array<Lhs, N>& lhs, const std::array<Rhs, N>& rhs,
295  std::index_sequence<Idx...>)
296  {
297  TIMEMORY_FOLD_EXPRESSION(std::get<Idx>(lhs) =
298  static_cast<Lhs>(std::get<Idx>(rhs)));
299  }
300  template <typename Tp = double>
301  auto get() const
302  {
303  std::array<Tp, num_events> values;
304  auto& _data = load();
305  convert(values, _data, std::make_index_sequence<num_events>{});
306  return values;
307  }
308 
309  //----------------------------------------------------------------------------------//
310  // array of descriptions
311  //
313  {
315  for(size_type i = 0; i < num_events; ++i)
316  arr[i] = papi::get_event_info(get_events<common_type>().at(i)).short_descr;
317  return arr;
318  }
319 
320  //----------------------------------------------------------------------------------//
321  // array of labels
322  //
324  {
326  for(size_type i = 0; i < num_events; ++i)
327  arr[i] = papi::get_event_info(get_events<common_type>().at(i)).long_descr;
328  return arr;
329  }
330 
331  //----------------------------------------------------------------------------------//
332  // array of unit
333  //
335  {
337  for(size_type i = 0; i < num_events; ++i)
338  arr[i] = papi::get_event_info(get_events<common_type>().at(i)).units;
339  return arr;
340  }
341 
342  //----------------------------------------------------------------------------------//
343  // array of unit values
344  //
346  {
347  array_t<int64_t> arr;
348  for(size_type i = 0; i < num_events; ++i)
349  arr[i] = 1;
350  return arr;
351  }
352 };
353 } // namespace component
354 } // 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
Inherit from this policy to add reference counting support. Useful if you want to turn a global setti...
Definition: types.hpp:367
Definition: kokkosp.cpp:38
std::string string_t
Definition: utility.hpp:105
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
static short get_precision()
decltype(auto) load()
void set_stopped()
store that stop has been called
static short get_width()
static fmtflags get_format_flags()
storage< Tp, Value > storage_type
Definition: declaration.hpp:90
void set_started()
store that start has been called
typename value_type::value_type entry_type
Definition: papi_common.hpp:65
std::array< Tp, N > array_t
Definition: papi_common.hpp:60
vector_t< long long > value_type
Definition: papi_common.hpp:64
static common_data & data()
This component is useful for bundling together a fixed set of hardware counter identifiers which requ...
Definition: papi_tuple.hpp:69
std::array< long long, sizeof...(EventTypes)> value_type
Definition: papi_tuple.hpp:71
papi_tuple< EventTypes... > this_type
Definition: papi_tuple.hpp:73
this_type & operator+=(const this_type &rhs)
Definition: papi_tuple.hpp:197
static std::string label()
Definition: papi_tuple.hpp:225
static void convert(std::array< Lhs, N > &lhs, const std::array< Rhs, N > &rhs, std::index_sequence< Idx... >)
Definition: papi_tuple.hpp:294
entry_type get_display(int evt_type) const
Definition: papi_tuple.hpp:253
static array_t< std::string > display_unit_array()
Definition: papi_tuple.hpp:334
this_type & operator-=(const this_type &rhs)
Definition: papi_tuple.hpp:206
static value_type record()
Definition: papi_tuple.hpp:114
void serialize(Archive &ar, const unsigned int)
Definition: papi_tuple.hpp:237
static const short precision
Definition: papi_tuple.hpp:221
static array_t< std::string > description_array()
Definition: papi_tuple.hpp:323
static const short width
Definition: papi_tuple.hpp:222
typename base_type::storage_type storage_type
Definition: papi_tuple.hpp:75
static std::string description()
Definition: papi_tuple.hpp:229
static array_t< int64_t > unit_array()
Definition: papi_tuple.hpp:345
static array_t< std::string > label_array()
Definition: papi_tuple.hpp:312
static const size_type num_events
Definition: papi_tuple.hpp:79
string_t get_display() const
Definition: papi_tuple.hpp:255
static std::string display_unit()
Definition: papi_tuple.hpp:230
static void thread_finalize()
Definition: papi_tuple.hpp:104
This operation attempts to call a member function which the component provides to internally store wh...
Definition: types.hpp:472
This operation attempts to call a member function which the component provides to internally store wh...
Definition: types.hpp:505
#define TIMEMORY_FOLD_EXPRESSION(...)
Definition: types.hpp:55