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.
graph_data.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//--------------------------------------------------------------------------------------//
28
29#include "timemory/backends/process.hpp"
30#include "timemory/backends/threading.hpp"
34
35#include <algorithm>
36#include <cstdint>
37#include <memory>
38#include <numeric>
39#include <sstream>
40#include <string>
41#include <unordered_map>
42
43//--------------------------------------------------------------------------------------//
44//
45namespace tim
46{
47//--------------------------------------------------------------------------------------//
48//
49// graph instance + current node + head node
50//
51//--------------------------------------------------------------------------------------//
52/// \class tim::graph_data
53/// \brief \ref tim::graph instance + current node + head note + sea-level. Sea-level is
54/// defined as the node depth after a fork from another graph instance and is only
55/// relevant for worker-threads)
56
57template <typename NodeT>
59{
60public:
63 using iterator = typename graph_t::iterator;
65 using inverse_insert_t = std::vector<std::pair<int64_t, iterator>>;
66 using pre_order_iterator = typename graph_t::pre_order_iterator;
67 using sibling_iterator = typename graph_t::sibling_iterator;
68
69public:
70 // graph_data() = default;
71
72 explicit graph_data(const NodeT& rhs, int64_t _depth, graph_data* _master = nullptr)
73 : m_has_head(true)
74 , m_depth(_depth)
75 , m_sea_level(_depth)
76 , m_master(_master)
77 {
78 m_head = m_graph.set_head(rhs);
79 m_current = m_head;
80 m_dummies.insert({ m_depth, m_current });
81 }
82
83 ~graph_data() { m_graph.clear(); }
84
85 // allow move and copy construct
86 graph_data(this_type&&) = delete;
88
89 // delete copy-assignment
90 graph_data(const this_type&) = delete;
91 graph_data& operator=(const this_type&) = delete;
92
93 TIMEMORY_NODISCARD bool has_head() const { return m_has_head; }
94 TIMEMORY_NODISCARD auto dummy_count() const { return m_dummies.size(); }
95 TIMEMORY_NODISCARD bool at_sea_level() const { return (m_depth == m_sea_level); }
96
97 int64_t& depth() { return m_depth; }
98 TIMEMORY_NODISCARD int64_t depth() const { return m_depth; }
99 int64_t& sea_level() { return m_sea_level; }
100 TIMEMORY_NODISCARD int64_t sea_level() const { return m_sea_level; }
101
102 graph_t& graph() { return m_graph; }
103 TIMEMORY_NODISCARD const graph_t& graph() const { return m_graph; }
104
105 iterator& head() { return m_head; }
106 iterator& current() { return m_current; }
107
108 iterator begin() { return m_graph.begin(); }
109 iterator end() { return m_graph.end(); }
110 TIMEMORY_NODISCARD const_iterator begin() const { return m_graph.begin(); }
111 TIMEMORY_NODISCARD const_iterator end() const { return m_graph.end(); }
112
113 inline void sync_sea_level()
114 {
115 if(m_master)
116 {
117 DEBUG_PRINT_HERE("[%s][%i]> synchronizing sea-level for depth = %i, master "
118 "depth = %i",
119 demangle<NodeT>().c_str(), (int) threading::get_id(),
120 (int) depth(), (int) m_master->depth());
121 add_dummy();
122 }
123 }
124
125 inline void clear()
126 {
127 m_graph.clear();
128 m_has_head = false;
129 m_depth = 0;
130 m_sea_level = 0;
131 m_current = nullptr;
132 m_dummies.clear();
133 }
134
135 inline void set_master(graph_data* _master)
136 {
137 if(_master != this)
138 m_master = _master;
139 }
140
141 inline void add_dummy()
142 {
143 if(!m_master)
144 return;
145
146 if(depth() == m_master->depth())
147 return;
148
149 DEBUG_PRINT_HERE("[%s][%i]> Adding dummy for depth = %i, master depth = %i",
150 demangle<NodeT>().c_str(), (int) threading::get_id(),
151 (int) depth(), (int) m_master->depth());
152
153 auto _current = m_master->current();
154 auto _id = _current->id();
155 auto _depth = _current->depth();
156
157 NodeT node(_id, NodeT::get_dummy(), _depth, threading::get_id(),
158 process::get_id(), true);
159 m_depth = _depth;
160 m_sea_level = _depth;
161 m_current = m_graph.insert_after(m_head, std::move(node));
162
163 m_dummies.insert({ m_depth, m_current });
164 }
165
166 inline void reset()
167 {
168 // for(auto& itr : m_dummies)
169 // m_graph.erase(itr.second);
170 m_graph.erase_children(m_head);
171 m_depth = 0;
172 m_current = m_head;
173 }
174
176 {
177 if(m_depth > 0 && !m_graph.is_head(m_current))
178 {
179 --m_depth;
180 m_current = graph_t::parent(m_current);
181 }
182 else if(m_depth == 0)
183 {
184 m_current = m_head;
185 }
186 return m_current;
187 }
188
189 TIMEMORY_NODISCARD inline iterator find(iterator itr) const
190 {
191 if(!itr)
192 return end();
193
194 for(pre_order_iterator fitr = begin(); fitr != end(); ++fitr)
195 {
196 if(fitr && *itr == *fitr && get_rolling_hash(itr) == get_rolling_hash(fitr))
197 return fitr;
198 sibling_iterator entry = fitr;
199 for(auto sitr = entry.begin(); sitr != entry.end(); ++sitr)
200 {
201 if(sitr && *itr == *sitr &&
203 return sitr;
204 }
205 }
206 return end();
207 }
208
209 TIMEMORY_NODISCARD inline int64_t get_rolling_hash(iterator itr) const
210 {
211 int64_t _accum = 0;
212 if(itr)
213 return _accum;
214 _accum += itr->id();
215 auto _parent = graph_t::parent(itr);
216 while(_parent)
217 {
218 _accum += _parent->id();
219 _parent = graph_t::parent(_parent);
220 if(!_parent)
221 break;
222 }
223 return _accum;
224 }
225
226 inline iterator append_child(const NodeT& node)
227 {
228 ++m_depth;
229 return (m_current = m_graph.append_child(m_current, node));
230 }
231
232 inline iterator append_child(NodeT&& node)
233 {
234 ++m_depth;
235 return (m_current = m_graph.append_child(m_current, std::move(node)));
236 }
237
238 inline iterator append_head(NodeT& node)
239 {
240 return m_graph.append_child(m_head, node);
241 }
242
243 inline iterator emplace_child(iterator _itr, const NodeT& node)
244 {
245 return m_graph.append_child(_itr, node);
246 }
247
248 inline iterator emplace_child(iterator _itr, NodeT&& node)
249 {
250 return m_graph.append_child(_itr, std::move(node));
251 }
252
253 TIMEMORY_NODISCARD inverse_insert_t get_inverse_insert() const
254 {
256 for(const auto& itr : m_dummies)
257 ret.push_back({ itr.first, itr.second });
258 std::reverse(ret.begin(), ret.end());
259 return ret;
260 }
261
262private:
263 bool m_has_head = false;
264 int64_t m_depth = 0;
265 int64_t m_sea_level = 0;
266 graph_t m_graph;
267 iterator m_current = nullptr;
268 iterator m_head = nullptr;
269 graph_data* m_master = nullptr;
270 std::multimap<int64_t, iterator> m_dummies = {};
271};
272//
273//--------------------------------------------------------------------------------------//
274//
275} // namespace tim
tim::graph instance + current node + head note + sea-level. Sea-level is defined as the node depth af...
Definition: graph_data.hpp:59
void set_master(graph_data *_master)
Definition: graph_data.hpp:135
typename graph_t::sibling_iterator sibling_iterator
Definition: graph_data.hpp:67
const_iterator end() const
Definition: graph_data.hpp:111
iterator append_child(const NodeT &node)
Definition: graph_data.hpp:226
iterator pop_graph()
Definition: graph_data.hpp:175
tim::graph< NodeT > graph_t
Definition: graph_data.hpp:62
graph_data(this_type &&)=delete
graph_t & graph()
Definition: graph_data.hpp:102
iterator begin()
Definition: graph_data.hpp:108
bool at_sea_level() const
Definition: graph_data.hpp:95
void sync_sea_level()
Definition: graph_data.hpp:113
typename graph_t::iterator iterator
Definition: graph_data.hpp:63
iterator & current()
Definition: graph_data.hpp:106
graph_data(const this_type &)=delete
typename graph_t::const_iterator const_iterator
Definition: graph_data.hpp:64
std::vector< std::pair< int64_t, iterator > > inverse_insert_t
Definition: graph_data.hpp:65
int64_t get_rolling_hash(iterator itr) const
Definition: graph_data.hpp:209
graph_data & operator=(this_type &&)=delete
iterator append_child(NodeT &&node)
Definition: graph_data.hpp:232
auto dummy_count() const
Definition: graph_data.hpp:94
iterator append_head(NodeT &node)
Definition: graph_data.hpp:238
iterator emplace_child(iterator _itr, const NodeT &node)
Definition: graph_data.hpp:243
int64_t & depth()
Definition: graph_data.hpp:97
int64_t sea_level() const
Definition: graph_data.hpp:100
inverse_insert_t get_inverse_insert() const
Definition: graph_data.hpp:253
iterator find(iterator itr) const
Definition: graph_data.hpp:189
typename graph_t::pre_order_iterator pre_order_iterator
Definition: graph_data.hpp:66
iterator & head()
Definition: graph_data.hpp:105
bool has_head() const
Definition: graph_data.hpp:93
const_iterator begin() const
Definition: graph_data.hpp:110
iterator emplace_child(iterator _itr, NodeT &&node)
Definition: graph_data.hpp:248
iterator end()
Definition: graph_data.hpp:109
graph_data & operator=(const this_type &)=delete
int64_t depth() const
Definition: graph_data.hpp:98
int64_t & sea_level()
Definition: graph_data.hpp:99
graph_data(const NodeT &rhs, int64_t _depth, graph_data *_master=nullptr)
Definition: graph_data.hpp:72
const graph_t & graph() const
Definition: graph_data.hpp:103
void clear()
Erase all nodes of the graph.
Definition: graph.hpp:631
void erase_children(const iterator_base &)
Erase all children of the node pointed to by iterator.
Definition: graph.hpp:644
IterT append_child(IterT position)
Insert empty node as last/first child of node pointed to by position.
Definition: graph.hpp:789
static bool is_head(const iterator_base &)
Determine whether the iterator is one of the 'head' nodes at the top level, i.e. has no parent.
Definition: graph.hpp:2328
IterT insert_after(IterT position, const T &x)
Insert node as next sibling of node pointed to by position.
Definition: graph.hpp:1180
pre_order_iterator end() const
Return iterator to the end of the graph.
Definition: graph.hpp:717
pre_order_iterator iterator
The default iterator types throughout the graph class.
Definition: graph.hpp:218
pre_order_iterator set_head(const T &x)
Short-hand to insert topmost node in otherwise empty graph.
Definition: graph.hpp:1057
static IterT parent(IterT)
Return iterator to the parent of a node.
Definition: graph.hpp:752
const iterator const_iterator
Definition: graph.hpp:219
pre_order_iterator begin() const
Return iterator to the beginning of the graph.
Definition: graph.hpp:708
data::entry entry
Definition: stream.hpp:980
Definition: kokkosp.cpp:39
Declare the storage types.
#define DEBUG_PRINT_HERE(...)
Definition: macros.hpp:168