SDSL 3.0.2
Succinct Data Structure Library
Loading...
Searching...
No Matches
memory_tracking.hpp
Go to the documentation of this file.
1// Copyright (c) 2016, the SDSL Project Authors. All rights reserved.
2// Please see the AUTHORS file for details. Use of this source code is governed
3// by a BSD license that can be found in the LICENSE file.
8#ifndef INCLUDED_SDSL_MEMORY_TRACKING
9#define INCLUDED_SDSL_MEMORY_TRACKING
10
11#include <stdint.h>
12
13#include <sdsl/config.hpp>
14//#include <sdsl/ram_fs.hpp>
15
16#include <algorithm>
17#include <atomic>
18#include <chrono>
19#include <cstdlib>
20#include <fstream>
21#include <limits>
22#include <map>
23#include <memory>
24#include <mutex>
25#include <new>
26#include <stack>
27#include <string>
28#include <utility>
29#include <vector>
30
31#ifdef _WIN32
32# ifndef NOMINMAX
33// windows.h has min/max macro which causes problems when using std::min/max
34# define NOMINMAX 1
35# endif
36# include <io.h>
37# include <windows.h>
38#else
39
40#endif
41
42namespace sdsl
43{
44
45// forward declare
46void memory_monitor_record(int64_t);
47
48// minimal allocator from http://stackoverflow.com/a/21083096
49template <typename T>
51{
52 using value_type = T;
53
54 track_allocator() = default;
55 template <class U>
58
59 T * allocate(std::size_t n)
60 {
61 if (n <= std::numeric_limits<std::size_t>::max() / sizeof(T))
62 {
63 size_t s = n * sizeof(T);
64 if (auto ptr = std::malloc(s))
65 {
67 return static_cast<T *>(ptr);
68 }
69 }
70 throw std::bad_alloc();
71 }
72 void deallocate(T * ptr, std::size_t n)
73 {
74 std::size_t s = n * sizeof(T);
75 memory_monitor_record(-((int64_t)s));
76 std::free(ptr);
77 }
78};
79
80template <typename T, typename U>
82{
83 return true;
84}
85
86template <typename T, typename U>
87inline bool operator!=(track_allocator<T> const & a, track_allocator<U> const & b)
88{
89 return !(a == b);
90}
91
92// spin lock
94{
95private:
96 std::atomic_flag m_slock;
97
98public:
100 {
101 m_slock.clear();
102 }
103 void lock()
104 {
105 while (m_slock.test_and_set(std::memory_order_acquire))
106 { /* spin */
107 }
108 };
109 void unlock()
110 {
111 m_slock.clear(std::memory_order_release);
112 };
113};
114
115namespace ram_fs
116{
117typedef std::vector<char, track_allocator<char>> content_type;
118}
119
121{
122 typedef std::map<std::string, ram_fs::content_type> mss_type;
123 typedef std::map<int, std::string> mis_type;
124 std::recursive_mutex m_rlock;
125
128
130 {
131 m_fd_map[-1] = "";
132 }
133
136};
137
139{
140 using timer = std::chrono::high_resolution_clock;
141 timer::time_point timestamp;
142 int64_t usage;
143 mm_alloc(timer::time_point t, int64_t u) : timestamp(t), usage(u){};
144};
145
147{
148 using timer = std::chrono::high_resolution_clock;
149 std::string name;
150 std::vector<mm_alloc> allocations;
151 mm_event(std::string n, int64_t usage) : name(n)
152 {
153 allocations.emplace_back(timer::now(), usage);
154 };
155 bool operator<(mm_event const & a) const
156 {
157 if (a.allocations.size() && this->allocations.size())
158 {
159 if (this->allocations[0].timestamp == a.allocations[0].timestamp)
160 {
161 return this->allocations.back().timestamp < a.allocations.back().timestamp;
162 }
163 else
164 {
165 return this->allocations[0].timestamp < a.allocations[0].timestamp;
166 }
167 }
168 return true;
169 }
170};
171
173{
174 using timer = std::chrono::high_resolution_clock;
175 std::chrono::milliseconds log_granularity = std::chrono::milliseconds(20ULL);
176 int64_t current_usage = 0;
177 bool track_usage = false;
178 std::vector<mm_event> completed_events;
179 std::stack<mm_event> event_stack;
180 timer::time_point start_log;
181 timer::time_point last_event;
183
186
189};
190
191template <format_type F>
192void write_mem_log(std::ostream & out, tracker_storage const & m);
193
195{
196public:
197 using timer = std::chrono::high_resolution_clock;
198
200 {
201 bool add;
202 timer::time_point created;
203 mm_event_proxy(std::string const & name, int64_t usage, bool a) : add(a)
204 {
205 if (add)
206 {
207 auto & m = *(the_monitor().m_tracker);
208 std::lock_guard<spin_lock> lock(m.spinlock);
209 m.event_stack.emplace(name, usage);
210 }
211 }
213 {
214 if (add)
215 {
216 auto & m = *(the_monitor().m_tracker);
217 std::lock_guard<spin_lock> lock(m.spinlock);
218 auto & cur = m.event_stack.top();
219 auto cur_time = timer::now();
220 cur.allocations.emplace_back(cur_time, m.current_usage);
221 m.completed_events.emplace_back(std::move(cur));
222 m.event_stack.pop();
223 // add a point to the new "top" with the same memory
224 // as before but just ahead in time
225 if (!m.event_stack.empty())
226 {
227 if (m.event_stack.top().allocations.size())
228 {
229 auto last_usage = m.event_stack.top().allocations.back().usage;
230 m.event_stack.top().allocations.emplace_back(cur_time, last_usage);
231 }
232 }
233 }
234 }
235 };
236
237private:
238 tracker_storage * m_tracker;
239 ramfs_storage * m_ram_fs;
240
241 // disable construction of the object
243 {
244 m_tracker = new tracker_storage();
245 m_ram_fs = new ramfs_storage();
246 };
247
248 ~memory_monitor()
249 {
250 if (m_tracker->track_usage)
251 {
252 stop();
253 }
254 delete m_ram_fs;
255 delete m_tracker;
256 }
257 memory_monitor(memory_monitor const &) = delete;
258 memory_monitor & operator=(memory_monitor const &) = delete;
259
260 static memory_monitor & the_monitor()
261 {
262 static memory_monitor m;
263 return m;
264 }
265
266public:
267 static void granularity(std::chrono::milliseconds ms)
268 {
269 auto & m = *(the_monitor().m_tracker);
270 m.log_granularity = ms;
271 }
272 static int64_t peak()
273 {
274 auto & m = *(the_monitor().m_tracker);
275 int64_t max = 0;
276 for (auto events : m.completed_events)
277 {
278 for (auto alloc : events.allocations)
279 {
280 if (max < alloc.usage)
281 {
282 max = alloc.usage;
283 }
284 }
285 }
286 return max;
287 }
288
290 {
291 return *(the_monitor().m_ram_fs);
292 }
293
294 static void start()
295 {
296 auto & m = *(the_monitor().m_tracker);
297 m.track_usage = true;
298 // clear if there is something there
299 if (m.completed_events.size())
300 {
301 m.completed_events.clear();
302 }
303 while (m.event_stack.size())
304 {
305 m.event_stack.pop();
306 }
307 m.start_log = timer::now();
308 m.current_usage = 0;
309 m.last_event = m.start_log;
310 m.event_stack.emplace("unknown", 0);
311 }
312 static void stop()
313 {
314 auto & m = *(the_monitor().m_tracker);
315 while (!m.event_stack.empty())
316 {
317 m.completed_events.emplace_back(std::move(m.event_stack.top()));
318 m.event_stack.pop();
319 }
320 m.track_usage = false;
321 }
322 static void record(int64_t delta)
323 {
324 auto & m = *(the_monitor().m_tracker);
325 if (m.track_usage)
326 {
327 std::lock_guard<spin_lock> lock(m.spinlock);
328 auto cur = timer::now();
329 if (m.last_event + m.log_granularity < cur)
330 {
331 m.event_stack.top().allocations.emplace_back(cur, m.current_usage);
332 m.current_usage = m.current_usage + delta;
333 m.event_stack.top().allocations.emplace_back(cur, m.current_usage);
334 m.last_event = cur;
335 }
336 else
337 {
338 if (m.event_stack.top().allocations.size())
339 {
340 m.current_usage = m.current_usage + delta;
341 m.event_stack.top().allocations.back().usage = m.current_usage;
342 m.event_stack.top().allocations.back().timestamp = cur;
343 }
344 }
345 }
346 }
347
348 static mm_event_proxy event(std::string const & name)
349 {
350 auto & m = *(the_monitor().m_tracker);
351 if (m.track_usage)
352 {
353 return mm_event_proxy(name, m.current_usage, true);
354 }
355 return mm_event_proxy(name, m.current_usage, false);
356 }
357
358 template <format_type F>
359 static void write_memory_log(std::ostream & out)
360 {
361 write_mem_log<F>(out, *(the_monitor().m_tracker));
362 }
363};
364
365inline void memory_monitor_record(int64_t delta)
366{
368}
369
370} // namespace sdsl
371
372#endif
static void granularity(std::chrono::milliseconds ms)
std::chrono::high_resolution_clock timer
static ramfs_storage & ram_fs()
static void record(int64_t delta)
static mm_event_proxy event(std::string const &name)
static void write_memory_log(std::ostream &out)
std::vector< char, track_allocator< char > > content_type
Namespace for the succinct data structure library.
void write_mem_log(std::ostream &out, tracker_storage const &m)
void memory_monitor_record(int64_t)
bool operator==(track_allocator< T > const &, track_allocator< U > const &)
bool operator!=(track_allocator< T > const &a, track_allocator< U > const &b)
mm_event_proxy(std::string const &name, int64_t usage, bool a)
std::chrono::high_resolution_clock timer
mm_alloc(timer::time_point t, int64_t u)
timer::time_point timestamp
std::vector< mm_alloc > allocations
std::chrono::high_resolution_clock timer
bool operator<(mm_event const &a) const
mm_event(std::string n, int64_t usage)
std::recursive_mutex m_rlock
std::map< int, std::string > mis_type
std::map< std::string, ram_fs::content_type > mss_type
track_allocator(track_allocator< U > const &)
T * allocate(std::size_t n)
void deallocate(T *ptr, std::size_t n)
std::vector< mm_event > completed_events
std::stack< mm_event > event_stack
timer::time_point start_log
std::chrono::milliseconds log_granularity
std::chrono::high_resolution_clock timer
timer::time_point last_event