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.
source_location.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 
29 #include "timemory/mpl/apply.hpp"
30 
31 #include <array>
32 #include <cstring>
33 #include <ostream>
34 #include <sstream>
35 #include <string>
36 #include <tuple>
37 #include <utility>
38 #include <vector>
39 
40 namespace tim
41 {
42 namespace impl
43 {
44 template <typename... Tp>
45 struct source_location_constant_char;
46 
47 template <>
48 struct source_location_constant_char<>
49 {
50  static constexpr bool value = true;
51 };
52 
53 template <>
54 struct source_location_constant_char<const char*>
55 {
56  static constexpr bool value = true;
57 };
58 
59 template <typename Tp>
60 struct source_location_constant_char<Tp>
61 {
62  static constexpr bool value = std::is_same<Tp, const char*>::value;
63 };
64 
65 template <typename Tp, typename Up, typename... Tail>
66 struct source_location_constant_char<Tp, Up, Tail...>
67 {
68  static constexpr bool value = source_location_constant_char<Tp>::value &&
69  source_location_constant_char<Up>::value &&
70  source_location_constant_char<Tail...>::value;
71 };
72 
73 } // namespace impl
74 
75 /// \class tim::source_location
76 /// \brief Provides source location information and variadic joining of source location
77 /// tags
79 {
80 public:
82  using result_type = std::tuple<std::string, size_t>;
83 
84 private:
85  template <typename... Tp>
86  static constexpr bool is_constant_char()
87  {
88  return impl::source_location_constant_char<decay_t<Tp>...>::value;
89  }
90 
91 public:
92  //
93  // Public types
94  //
95 
96  //==================================================================================//
97  //
98  enum class mode : short
99  {
100  blank = 0,
101  basic = 1,
102  full = 2,
103  complete = 3
104  };
105 
106  //==================================================================================//
107  //
108  struct captured
109  {
110  public:
111  const result_type& get() const { return m_result; }
112  const std::string& get_id() const { return std::get<0>(m_result); }
113  const hash_value_t& get_hash() const { return std::get<1>(m_result); }
114 
115  explicit captured(result_type _result)
116  : m_result(std::move(_result))
117  {}
118 
119  TIMEMORY_DEFAULT_OBJECT(captured)
120 
121  private:
122  friend class source_location;
123  result_type m_result = result_type("", 0);
124 
125  template <typename... ArgsT, enable_if_t<(sizeof...(ArgsT) > 0), int> = 0>
126  captured& set(const source_location& obj, ArgsT&&... _args)
127  {
128  switch(obj.m_mode)
129  {
130  case mode::blank:
131  {
132  auto&& _tmp = join_type::join("", std::forward<ArgsT>(_args)...);
133  m_result = result_type(_tmp, add_hash_id(_tmp));
134  break;
135  }
136  case mode::basic:
137  case mode::full:
138  case mode::complete:
139  {
140  auto&& _suffix = join_type::join("", std::forward<ArgsT>(_args)...);
141  if(_suffix.empty())
142  {
143  m_result = result_type(obj.m_prefix, add_hash_id(obj.m_prefix));
144  }
145  else
146  {
147  auto _tmp = join_type::join('/', obj.m_prefix.c_str(), _suffix);
148  m_result = result_type(_tmp, add_hash_id(_tmp));
149  }
150  break;
151  }
152  }
153  return *this;
154  }
155 
156  template <typename... ArgsT, enable_if_t<sizeof...(ArgsT) == 0, int> = 0>
157  captured& set(const source_location& obj, ArgsT&&... _args)
158  {
159  tim::consume_parameters(std::forward<ArgsT>(_args)...);
160  m_result = result_type(obj.m_prefix, add_hash_id(obj.m_prefix));
161  return *this;
162  }
163  };
164 
165 public:
166  //
167  // Static functions
168  //
169 
170  //==================================================================================//
171  //
172  template <typename... ArgsT>
173  static captured get_captured_inline(const mode& _mode, const char* _func, int _line,
174  const char* _fname, ArgsT&&... _args)
175  {
176  source_location _loc{ _mode, _func, _line, _fname,
177  std::forward<ArgsT>(_args)... };
178  return _loc.get_captured(std::forward<ArgsT>(_args)...);
179  }
180 
181 public:
182  //
183  // Constructors, destructors, etc.
184  //
185 
186  //----------------------------------------------------------------------------------//
187  //
188  template <typename... ArgsT, enable_if_t<!is_constant_char<ArgsT...>(), int> = 0>
189  source_location(const mode& _mode, const char* _func, int _line, const char* _fname,
190  ArgsT&&...)
191  : m_mode(_mode)
192  {
193  switch(m_mode)
194  {
195  case mode::blank: break;
196  case mode::basic: compute_data(_func); break;
197  case mode::complete:
198  case mode::full:
199  compute_data(_func, _line, _fname, m_mode == mode::full);
200  break;
201  }
202  }
203 
204  //----------------------------------------------------------------------------------//
205  // if a const char* is passed, assume it is constant
206  //
207  template <typename... ArgsT, enable_if_t<is_constant_char<ArgsT...>(), int> = 0>
208  source_location(const mode& _mode, const char* _func, int _line, const char* _fname,
209  ArgsT&&... _args)
210  : m_mode(_mode)
211  {
212  auto _arg = join_type::join("", _args...);
213  switch(m_mode)
214  {
215  case mode::blank:
216  {
217  // label and hash
218  auto&& _label = _arg;
219  auto&& _hash = add_hash_id(_label);
220  m_captured = captured(result_type{ _label, _hash });
221  break;
222  }
223  case mode::basic:
224  {
225  compute_data(_func);
226  auto&& _label = _join(_arg.c_str());
227  auto&& _hash = add_hash_id(_label);
228  m_captured = captured(result_type{ _label, _hash });
229  break;
230  }
231  case mode::full:
232  case mode::complete:
233  {
234  compute_data(_func, _line, _fname, m_mode == mode::full);
235  // label and hash
236  auto&& _label = _join(_arg.c_str());
237  auto&& _hash = add_hash_id(_label);
238  m_captured = captured(result_type{ _label, _hash });
239  break;
240  }
241  }
242  }
243 
244  //----------------------------------------------------------------------------------//
245  //
246  source_location() = delete;
247  ~source_location() = default;
252 
253 protected:
254  //----------------------------------------------------------------------------------//
255  //
256  void compute_data(const char* _func) { m_prefix = _func; }
257 
258  //----------------------------------------------------------------------------------//
259  //
260  void compute_data(const char* _func, int _line, const char* _fname, bool shorten)
261  {
262 #if defined(TIMEMORY_WINDOWS)
263  static const char delim = '\\';
264 #else
265  static const char delim = '/';
266 #endif
267  std::string _filename(_fname);
268  if(shorten)
269  {
270  if(_filename.find(delim) != std::string::npos)
271  _filename = _filename.substr(_filename.find_last_of(delim) + 1);
272  }
273 
274  if(_line < 0)
275  {
276  if(_filename.length() > 0)
277  {
278  m_prefix = join_type::join("", _func, '@', _filename);
279  }
280  else
281  {
282  m_prefix = _func;
283  }
284  }
285  else
286  {
287  if(_filename.length() > 0)
288  {
289  m_prefix = join_type::join("", _func, '@', _filename, ':', _line);
290  }
291  else
292  {
293  m_prefix = join_type::join("", _func, ':', _line);
294  }
295  }
296  }
297 
298 public:
299  //----------------------------------------------------------------------------------//
300  //
301  template <
302  typename... ArgsT,
303  enable_if_t<(sizeof...(ArgsT) > 0) && !is_constant_char<ArgsT...>(), int> = 0>
304  const captured& get_captured(ArgsT&&... _args)
305  {
306  return m_captured.set(*this, std::forward<ArgsT>(_args)...);
307  }
308 
309  //----------------------------------------------------------------------------------//
310  //
311  const captured& get_captured() const { return m_captured; }
312 
313  //----------------------------------------------------------------------------------//
314  //
315  template <
316  typename... ArgsT,
317  enable_if_t<(sizeof...(ArgsT) > 0) && is_constant_char<ArgsT...>(), int> = 0>
318  const captured& get_captured(ArgsT&&...)
319  {
320  return m_captured;
321  }
322 
323 private:
324  mode m_mode;
325  std::string m_prefix = {};
326  captured m_captured;
327 
328 private:
329  std::string _join(const char* _arg)
330  {
331  return (strcmp(_arg, "") == 0) ? m_prefix
332  : join_type::join('/', m_prefix.c_str(), _arg);
333  }
334 };
335 //
336 namespace internal
337 {
338 namespace
339 {
340 // anonymous namespace to make sure the static instance is local to each .cpp
341 // making it static also helps ensure this
342 template <size_t, size_t, typename... Args>
343 static inline auto&
344 get_static_source_location(Args&&... args)
345 {
346  static source_location _instance{ std::forward<Args>(args)... };
347  consume_parameters(std::forward<Args>(args)...);
348  return _instance;
349 }
350 } // namespace
351 } // namespace internal
352 //
353 // static function should be local to each .cpp
354 //
355 // LineN should be '__LINE__': this ensures that each use in a source file is unique
356 // CountN should be '__COUNTER__': this ensures that each source file has unique integer
357 template <size_t LineN, size_t CountN, typename... Args>
358 static inline auto&
359 get_static_source_location(Args&&... args)
360 {
361  return internal::get_static_source_location<LineN, CountN>(
362  std::forward<Args>(args)...);
363  consume_parameters(std::forward<Args>(args)...);
364 }
365 //
366 } // namespace tim
Provides source location information and variadic joining of source location tags.
const captured & get_captured() const
static captured get_captured_inline(const mode &_mode, const char *_func, int _line, const char *_fname, ArgsT &&... _args)
source_location(const source_location &)=delete
source_location(source_location &&)=default
mpl::apply< std::string > join_type
void compute_data(const char *_func, int _line, const char *_fname, bool shorten)
const captured & get_captured(ArgsT &&... _args)
void compute_data(const char *_func)
~source_location()=default
std::tuple< std::string, size_t > result_type
const captured & get_captured(ArgsT &&...)
source_location(const mode &_mode, const char *_func, int _line, const char *_fname, ArgsT &&... _args)
source_location & operator=(source_location &&)=default
source_location(const mode &_mode, const char *_func, int _line, const char *_fname, ArgsT &&...)
source_location & operator=(const source_location &)=delete
auto join(const char *sep, Arg &&arg, Args &&... args)
Definition: declaration.hpp:74
Definition: kokkosp.cpp:38
size_t hash_value_t
Definition: types.hpp:81
void consume_parameters(ArgsT &&...) TIMEMORY_HIDDEN
Definition: types.hpp:285
typename std::enable_if< B, T >::type enable_if_t
Alias template for enable_if.
Definition: types.hpp:190
tim::mpl::apply< std::string > string
Definition: macros.hpp:52
hash_value_t add_hash_id(hash_map_ptr_t &_hash_map, const string_view_t &_prefix)
add an string to the given hash-map (if it doesn't already exist) and return the hash
Definition: types.hpp:187
char const std::string const std::string & _suffix
Definition: definition.hpp:61
const std::string & get_id() const
const result_type & get() const
const hash_value_t & get_hash() const