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.
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
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
40namespace tim
41{
42namespace impl
43{
44template <typename... Tp>
45struct source_location_constant_char;
46
47template <>
48struct source_location_constant_char<>
49{
50 static constexpr bool value = true;
51};
52
53template <>
54struct source_location_constant_char<const char*>
55{
56 static constexpr bool value = true;
57};
58
59template <typename Tp>
60struct source_location_constant_char<Tp>
61{
62 static constexpr bool value = std::is_same<Tp, const char*>::value;
63};
64
65template <typename Tp, typename Up, typename... Tail>
66struct 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{
80public:
82 using result_type = std::tuple<std::string, size_t>;
83
84private:
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
91public:
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
165public:
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
181public:
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
253protected:
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
298public:
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
323private:
324 mode m_mode;
325 std::string m_prefix = {};
326 captured m_captured;
327
328private:
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//
336namespace internal
337{
338namespace
339{
340// anonymous namespace to make sure the static instance is local to each .cpp
341// making it static also helps ensure this
342template <size_t, size_t, typename... Args>
343static inline auto&
344get_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
357template <size_t LineN, size_t CountN, typename... Args>
358static inline auto&
359get_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.
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
source_location & operator=(source_location &&)=default
mpl::apply< std::string > join_type
void compute_data(const char *_func, int _line, const char *_fname, bool shorten)
void compute_data(const char *_func)
~source_location()=default
const captured & get_captured() const
const captured & get_captured(ArgsT &&... _args)
std::tuple< std::string, size_t > result_type
source_location & operator=(const source_location &)=delete
source_location(const mode &_mode, const char *_func, int _line, const char *_fname, ArgsT &&... _args)
source_location(const mode &_mode, const char *_func, int _line, const char *_fname, ArgsT &&...)
const captured & get_captured(ArgsT &&...)
STL namespace.
hash_value_t add_hash_id(hash_map_ptr_t &_hash_map, string_view_cref_t _prefix)
add an string to the given hash-map (if it doesn't already exist) and return the hash
Definition: types.hpp:190
size_t hash_value_t
Definition: types.hpp:84
auto join(const char *sep, Arg &&arg, Args &&... args)
Definition: declaration.hpp:74
Definition: kokkosp.cpp:39
std::array< char *, 4 > _args
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:53
void consume_parameters(ArgsT &&...)
Definition: types.hpp:285
char const std::string const std::string & _suffix
Definition: config.cpp:57
const std::string & get_id() const
const hash_value_t & get_hash() const
const result_type & get() const