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_array.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 template <size_t MaxNumEvents>
47 struct papi_array
48 : public base<papi_array<MaxNumEvents>, std::array<long long, MaxNumEvents>>
49 , private policy::instance_tracker<papi_array<MaxNumEvents>>
50 , private papi_common
51 {
52  using size_type = size_t;
53  using event_list = std::vector<int>;
54  using value_type = std::array<long long, MaxNumEvents>;
55  using entry_type = typename value_type::value_type;
60  using get_initializer_t = std::function<event_list()>;
61  using common_type = void;
62 
63  static const short precision = 3;
64  static const short width = 8;
65 
66  template <typename Tp>
67  using array_t = std::array<Tp, MaxNumEvents>;
68 
69  friend struct operation::record<this_type>;
70  friend struct operation::start<this_type>;
71  friend struct operation::stop<this_type>;
72  friend struct operation::set_started<this_type>;
73  friend struct operation::set_stopped<this_type>;
74 
75  //----------------------------------------------------------------------------------//
76 
77  static auto& get_initializer() { return papi_common::get_initializer<common_type>(); }
78  static void configure()
79  {
80  if(!is_configured<common_type>())
81  papi_common::initialize<common_type>();
82  }
83  static void initialize() { configure(); }
84  static void thread_finalize()
85  {
86  papi_common::finalize<common_type>();
88  }
89  static void finalize() { papi_common::finalize<common_type>(); }
90 
91  //----------------------------------------------------------------------------------//
92 
93  papi_array() { events = get_events<common_type>(); }
94  ~papi_array() = default;
95  papi_array(const papi_array&) = default;
96  papi_array(papi_array&&) noexcept = default;
97  papi_array& operator=(const papi_array&) = default;
98  papi_array& operator=(papi_array&&) noexcept = default;
99 
100  using base_type::load;
101 
102  //----------------------------------------------------------------------------------//
103 
104  size_t size() { return events.size(); }
105 
106  //----------------------------------------------------------------------------------//
107 
109  {
110  value_type read_value{};
111  read_value.fill(0);
112  if(is_configured<common_type>())
113  papi::read(event_set<common_type>(), read_value.data());
114  return read_value;
115  }
116 
117  //----------------------------------------------------------------------------------//
118 
119  template <typename Tp = double>
120  std::vector<Tp> get() const
121  {
122  std::vector<Tp> values;
123  auto& _data = load();
124  values.reserve(_data.size());
125  for(auto& itr : _data)
126  values.emplace_back(itr);
127  values.resize(events.size());
128  return values;
129  }
130 
131  //----------------------------------------------------------------------------------//
132  // sample
133  //
134  void sample()
135  {
136  if(tracker_type::get_thread_started() == 0)
137  configure();
138  if(events.empty())
139  events = get_events<common_type>();
140 
142  value = record();
143  }
144 
145  //----------------------------------------------------------------------------------//
146  // start
147  //
148  void start()
149  {
150  if(tracker_type::get_thread_started() == 0 || events.size() == 0)
151  configure();
152 
153  events = get_events<common_type>();
155  value = record();
156  }
157 
158  //----------------------------------------------------------------------------------//
159 
160  void stop()
161  {
163  using namespace tim::component::operators;
164  value = (record() - value);
165  accum += value;
166  }
167 
168  //----------------------------------------------------------------------------------//
169 
171  {
172  for(size_type i = 0; i < events.size(); ++i)
173  accum[i] += rhs.accum[i];
174  for(size_type i = 0; i < events.size(); ++i)
175  value[i] += rhs.value[i];
176  return *this;
177  }
178 
179  //----------------------------------------------------------------------------------//
180 
182  {
183  for(size_type i = 0; i < events.size(); ++i)
184  accum[i] -= rhs.accum[i];
185  for(size_type i = 0; i < events.size(); ++i)
186  value[i] -= rhs.value[i];
187  return *this;
188  }
189 
190  //----------------------------------------------------------------------------------//
191 
192 protected:
193  using base_type::accum;
194  using base_type::laps;
197  using base_type::value;
198  using papi_common::events;
199 
200  friend struct base<this_type, value_type>;
201  friend class impl::storage<this_type,
202  trait::uses_value_storage<this_type, value_type>::value>;
203 
204 public:
205  //==================================================================================//
206  //
207  // data representation
208  //
209  //==================================================================================//
210 
212  {
213  return "papi_array" + std::to_string((event_set<common_type>() < 0)
214  ? 0
215  : event_set<common_type>());
216  }
217 
218  static std::string description() { return "Fixed-size array of PAPI HW counters"; }
219 
220  TIMEMORY_NODISCARD entry_type get_display(int evt_type) const
221  {
222  return accum.at(evt_type);
223  }
224 
225  //----------------------------------------------------------------------------------//
226  // serialization
227  //
228  template <typename Archive>
229  void load(Archive& ar, const unsigned int)
230  {
231  ar(cereal::make_nvp("laps", laps), cereal::make_nvp("value", value),
232  cereal::make_nvp("accum", accum), cereal::make_nvp("events", events));
233  }
234 
235  //----------------------------------------------------------------------------------//
236  // serialization
237  //
238  template <typename Archive>
239  void save(Archive& ar, const unsigned int) const
240  {
241  array_t<double> _disp;
242  for(size_type i = 0; i < events.size(); ++i)
243  _disp[i] = get_display(i);
244  ar(cereal::make_nvp("laps", laps), cereal::make_nvp("repr_data", _disp),
245  cereal::make_nvp("value", value), cereal::make_nvp("accum", accum),
246  cereal::make_nvp("display", _disp), cereal::make_nvp("events", events));
247  }
248 
249  //----------------------------------------------------------------------------------//
250  // array of descriptions
251  //
252  TIMEMORY_NODISCARD std::vector<std::string> label_array() const
253  {
254  std::vector<std::string> arr(events.size());
255  for(size_type i = 0; i < events.size(); ++i)
256  arr[i] = papi::get_event_info(events[i]).short_descr;
257 
258  for(auto& itr : arr)
259  {
260  size_t n = std::string::npos;
261  while((n = itr.find("L/S")) != std::string::npos)
262  itr.replace(n, 3, "Loads_Stores");
263  }
264 
265  for(auto& itr : arr)
266  {
267  size_t n = std::string::npos;
268  while((n = itr.find('/')) != std::string::npos)
269  itr.replace(n, 1, "_per_");
270  }
271 
272  for(auto& itr : arr)
273  {
274  size_t n = std::string::npos;
275  while((n = itr.find(' ')) != std::string::npos)
276  itr.replace(n, 1, "_");
277 
278  while((n = itr.find("__")) != std::string::npos)
279  itr.replace(n, 2, "_");
280  }
281 
282  return arr;
283  }
284 
285  //----------------------------------------------------------------------------------//
286  // array of labels
287  //
288  TIMEMORY_NODISCARD std::vector<std::string> description_array() const
289  {
290  std::vector<std::string> arr(events.size());
291  for(size_type i = 0; i < events.size(); ++i)
292  arr[i] = papi::get_event_info(events[i]).long_descr;
293  return arr;
294  }
295 
296  //----------------------------------------------------------------------------------//
297  // array of unit
298  //
299  TIMEMORY_NODISCARD std::vector<std::string> display_unit_array() const
300  {
301  std::vector<std::string> arr(events.size());
302  for(size_type i = 0; i < events.size(); ++i)
303  arr[i] = papi::get_event_info(events[i]).units;
304  return arr;
305  }
306 
307  //----------------------------------------------------------------------------------//
308  // array of unit values
309  //
310  TIMEMORY_NODISCARD std::vector<int64_t> unit_array() const
311  {
312  std::vector<int64_t> arr(events.size());
313  for(size_type i = 0; i < events.size(); ++i)
314  arr[i] = 1;
315  return arr;
316  }
317 
318  //----------------------------------------------------------------------------------//
319 
320  TIMEMORY_NODISCARD string_t get_display() const
321  {
322  if(events.size() == 0)
323  return "";
324  auto val = load();
325  auto _get_display = [&](std::ostream& os, size_type idx) {
326  auto _obj_value = val[idx];
327  auto _evt_type = events[idx];
328  string_t _label = papi::get_event_info(_evt_type).short_descr;
329  string_t _disp = papi::get_event_info(_evt_type).units;
330  auto _prec = base_type::get_precision();
331  auto _width = base_type::get_width();
332  auto _flags = base_type::get_format_flags();
333 
334  std::stringstream ss;
335  std::stringstream ssv;
336  std::stringstream ssi;
337  ssv.setf(_flags);
338  ssv << std::setw(_width) << std::setprecision(_prec) << _obj_value;
339  if(!_disp.empty())
340  ssv << " " << _disp;
341  if(!_label.empty())
342  ssi << " " << _label;
343  ss << ssv.str() << ssi.str();
344  os << ss.str();
345  };
346 
347  std::stringstream ss;
348  for(size_type i = 0; i < events.size(); ++i)
349  {
350  _get_display(ss, i);
351  if(i + 1 < events.size())
352  ss << ", ";
353  }
354  return ss.str();
355  }
356 
357  //----------------------------------------------------------------------------------//
358 
359  friend std::ostream& operator<<(std::ostream& os, const this_type& obj)
360  {
361  if(obj.events.size() == 0)
362  return os;
363  // output the metrics
364  auto _value = obj.get_display();
365  auto _label = this_type::get_label();
366  auto _disp = this_type::display_unit();
367  auto _prec = this_type::get_precision();
368  auto _width = this_type::get_width();
369  auto _flags = this_type::get_format_flags();
370 
371  std::stringstream ss_value;
372  std::stringstream ss_extra;
373  ss_value.setf(_flags);
374  ss_value << std::setw(_width) << std::setprecision(_prec) << _value;
375  if(!_disp.empty())
376  {
377  ss_extra << " " << _disp;
378  }
379  else if(!_label.empty())
380  {
381  ss_extra << " " << _label;
382  }
383  os << ss_value.str() << ss_extra.str();
384  return os;
385  }
386 };
387 } // namespace component
388 } // 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()
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
std::function< event_list()> get_initializer_t
Definition: papi_array.hpp:60
static std::string label()
Definition: papi_array.hpp:211
std::array< long long, MaxNumEvents > value_type
Definition: papi_array.hpp:54
std::vector< int64_t > unit_array() const
Definition: papi_array.hpp:310
string_t get_display() const
Definition: papi_array.hpp:320
papi_array(papi_array &&) noexcept=default
typename value_type::value_type entry_type
Definition: papi_array.hpp:55
std::vector< Tp > get() const
Definition: papi_array.hpp:120
static const short width
Definition: papi_array.hpp:64
std::vector< std::string > label_array() const
Definition: papi_array.hpp:252
static auto & get_initializer()
Definition: papi_array.hpp:77
std::array< Tp, MaxNumEvents > array_t
Definition: papi_array.hpp:67
this_type & operator+=(const this_type &rhs)
Definition: papi_array.hpp:170
typename base_type::storage_type storage_type
Definition: papi_array.hpp:58
static std::string description()
Definition: papi_array.hpp:218
static const short precision
Definition: papi_array.hpp:63
void save(Archive &ar, const unsigned int) const
Definition: papi_array.hpp:239
std::vector< std::string > description_array() const
Definition: papi_array.hpp:288
entry_type get_display(int evt_type) const
Definition: papi_array.hpp:220
void load(Archive &ar, const unsigned int)
Definition: papi_array.hpp:229
std::vector< int > event_list
Definition: papi_array.hpp:53
std::vector< std::string > display_unit_array() const
Definition: papi_array.hpp:299
papi_array(const papi_array &)=default
static value_type record()
Definition: papi_array.hpp:108
papi_array< MaxNumEvents > this_type
Definition: papi_array.hpp:56
friend std::ostream & operator<<(std::ostream &os, const this_type &obj)
Definition: papi_array.hpp:359
this_type & operator-=(const this_type &rhs)
Definition: papi_array.hpp:181
static void thread_finalize()
Definition: papi_array.hpp:84
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