FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
memory_usage.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
10#include <kernel/util/string.hpp>
12#include <kernel/util/os_windows.hpp>
13#include <kernel/util/dist.hpp>
14
15#ifdef __unix__
16#include <sys/types.h>
17#include <sys/time.h>
18#include <sys/resource.h>
19#include <stdio.h>
20#endif
21
22#include <fstream>
23#include <vector>
24#include <string>
25#include <array>
26
27namespace FEAT
28{
44 {
45 public:
46 enum memory_type : std::uint8_t
47 {
48 peak_physical = 0,
49 cur_physical = 1,
50 peak_virtual = 2,
51 cur_virtual = 3,
52 cur_swap = 4,
53 size = 5
54 };
55
56 static const char* format(memory_type type)
57 {
58 switch (type) {
59 case peak_physical:
60 return "Peak Physical";
61 case cur_physical:
62 return "Current Physical";
63 case peak_virtual:
64 return "Peak Virtual";
65 case cur_virtual:
66 return "Current Virtual";
67 case cur_swap:
68 return "Current Swap";
69 default:
70 return "Unkown";
71 }
72 }
73
74 private:
75 std::array<std::size_t, memory_type::size> _memory;
76
77 public:
78 MemoryUsage() :
79 _memory()
80 {
81 stamp();
82 }
83
85 void stamp()
86 {
87#if defined(__linux)
88 String line;
89 std::ifstream status_file("/proc/self/status");
90 if (!status_file.is_open())
91 XABORTM("could not open /proc/self/status!");
92
93 /* man 5 proc:
94 * /proc/[pid]/status
95 * Provides much of the information in /proc/[pid]/stat and
96 * /proc/[pid]/statm in a format that's easier for humans to parse.
97 * The fields are as follows:
98 * Name: Command run by this process.
99 * State: Current state of the process. One of "R (running)", "S (sleeping)", "D (disk sleep)", "T (stopped)", "T (trac-
100 * ing stop)", "Z (zombie)", or "X (dead)".
101 * Tgid: Thread group ID (i.e., Process ID).
102 * Pid: Thread ID (see gettid(2)).
103 * PPid: PID of parent process.
104 * TracerPid: PID of process tracing this process (0 if not being traced).
105 * Uid, Gid: Real, effective, saved set, and file system UIDs (GIDs).
106 * FDSize: Number of file descriptor slots currently allocated.
107 * Groups: Supplementary group list.
108 *! VmPeak: Peak virtual memory size.
109 *! VmSize: Virtual memory size.
110 * VmLck: Locked memory size (see mlock(3)).
111 *! VmHWM: Peak resident set size ("high water mark").
112 *! VmRSS: Resident set size.
113 * VmData, VmStk, VmExe: Size of data, stack, and text segments.
114 * VmLib: Shared library code size.
115 * VmPTE: Page table entries size (since Linux 2.6.10).
116 * Threads: Number of threads in process containing this thread.
117 * [...]
118 */
119 while (std::getline(status_file, line))
120 {
121 if (line.starts_with("VmRSS"))
122 {
123 std::size_t& _current_physical = _memory[memory_type::cur_physical];
124 std::deque<String> v = line.split_by_whitespaces();
125 XASSERTM(v.back() == "kB", "get_memory_usage: unit mismatch!");
126 v.at(v.size() - 2).parse(_current_physical);
127 _current_physical *= 1024;
128 continue;
129 }
130
131 if (line.starts_with("VmHWM"))
132 {
133 std::size_t& _peak_physical = _memory[memory_type::peak_physical];
134 std::deque<String> v = line.split_by_whitespaces();
135 XASSERTM(v.back() == "kB", "get_memory_usage: unit mismatch!");
136 v.at(v.size() - 2).parse(_peak_physical);
137 _peak_physical *= 1024;
138 continue;
139 }
140
141 if (line.starts_with("VmSize"))
142 {
143 std::size_t& _current_virtual = _memory[memory_type::cur_virtual];
144 std::deque<String> v = line.split_by_whitespaces();
145 XASSERTM(v.back() == "kB", "get_memory_usage: unit mismatch!");
146 v.at(v.size() - 2).parse(_current_virtual);
147 _current_virtual *= 1024;
148 continue;
149 }
150
151 if (line.starts_with("VmPeak"))
152 {
153 std::size_t& _peak_virtual = _memory[memory_type::peak_virtual];
154 std::deque<String> v = line.split_by_whitespaces();
155 XASSERTM(v.back() == "kB", "get_memory_usage: unit mismatch!");
156 v.at(v.size() - 2).parse(_peak_virtual);
157 _peak_virtual *= 1024;
158 continue;
159 }
160
161 if (line.starts_with("VmSwap"))
162 {
163 std::size_t& _current_swap = _memory[memory_type::cur_swap];
164 std::deque<String> v = line.split_by_whitespaces();
165 XASSERTM(v.back() == "kB", "get_memory_usage: unit mismatch!");
166 v.at(v.size() - 2).parse(_current_swap);
167 _current_swap *= 1024;
168 continue;
169 }
170 }
171 status_file.close();
172
173#elif defined(_WIN32)
174
175 unsigned long long work_set_size(0ull), work_set_size_peak(0ull), page_file_usage(0ull), page_file_usage_peak(0ull);
176
177 Windows::query_memory_usage(work_set_size, work_set_size_peak, page_file_usage, page_file_usage_peak);
178
179 _memory[memory_type::cur_physical] = std::size_t(work_set_size);
180 _memory[memory_type::cur_virtual] = std::size_t(page_file_usage);
181 _memory[memory_type::peak_physical] = std::size_t(work_set_size_peak);
182 _memory[memory_type::peak_virtual] = std::size_t(page_file_usage_peak);
183 _memory[memory_type::cur_swap] = std::size_t(0);
184
185#elif defined(__unix__)
186 // see:
187 // https://linux.die.net/man/2/getrusage
188 // https://www.freebsd.org/cgi/man.cgi?query=getrusage
189 struct rusage r_usage;
190 if (0 != getrusage(RUSAGE_SELF, &r_usage))
191 XABORTM("Error in getrusage call!");
192 // 'ru_maxrss' is given in kilobytes
193 _memory[memory_type::cur_physical] = std::size_t(r_usage.ru_maxrss) * 1024u;
194 _memory[memory_type::cur_virtual] = std::size_t(r_usage.ru_maxrss) * 1024u;
195 _memory[memory_type::peak_physical] = std::size_t(r_usage.ru_maxrss) * 1024u;
196 _memory[memory_type::peak_virtual] = std::size_t(r_usage.ru_maxrss) * 1024u;
197 _memory[memory_type::cur_swap] = std::size_t(0);
198#endif
199 }
200
202 std::size_t get_current_physical() const
203 {
204 return _memory[memory_type::cur_physical];
205 }
206
208 std::size_t get_peak_physical() const
209 {
210 return _memory[memory_type::peak_physical];
211 }
212
214 std::size_t get_current_virtual() const
215 {
216 return _memory[memory_type::cur_virtual];
217 }
218
220 std::size_t get_peak_virtual() const
221 {
222 return _memory[memory_type::peak_virtual];
223 }
224
226 std::size_t get_current_swap() const
227 {
228 return _memory[memory_type::cur_swap];
229 }
230
233 {
234 String r;
235 for(std::size_t k = 0u; k < memory_type::size; ++k)
236 {
237 memory_type type = memory_type(k);
238 r += (String(format(type)) + String(":")).pad_back(20) + stringify(_memory[type] / 1024 / 1024) + " MByte\n";
239 }
240
241 return r;
242 }
243
244 String get_formatted_memory_usage(const Dist::Comm& comm, memory_type mem_type) const
245 {
246 std::uint64_t min_p, max_p, sum_p;
247 min_p = max_p = sum_p = _memory[mem_type];
248 comm.allreduce(&min_p, &min_p, 1u, Dist::op_min);
249 comm.allreduce(&max_p, &max_p, 1u, Dist::op_max);
250 comm.allreduce(&sum_p, &sum_p, 1u, Dist::op_sum);
251 return String(format(mem_type)).pad_back(20u, '.') + ": " + stringify_bytes(sum_p, 3, 0) + " [ Max: " + stringify_bytes(max_p, 3, 0) + " / Min: " + stringify_bytes(min_p, 3, 0) + " ]";
252 }
253
261 {
262 MemoryUsage mu;
263 return mu.get_formatted_memory_usage(comm, memory_type::peak_physical);
264 }
265 }; //class MemoryUsage
266} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Communicator class.
Definition: dist.hpp:1349
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
Definition: dist.cpp:655
Memory usage info object.
std::size_t get_peak_virtual() const
Returns peak virtual memory.
std::size_t get_current_swap() const
Returns current (last stamp call) swap memory.
std::size_t get_current_physical() const
Returns current (last stamp call) physical memory.
std::size_t get_peak_physical() const
Returns peak physical memory.
void stamp()
update the memory usage statistics with current data
static String format_peak_physical_usage(const Dist::Comm &comm)
Returns the formatted peak physical memory usage over an entire communicator.
std::size_t get_current_virtual() const
Returns current (last stamp call) virtual memory.
String get_formatted_memory_usage() const
Retrieve formatted memory usage string.
String class implementation.
Definition: string.hpp:47
std::deque< String > split_by_whitespaces() const
Splits the string by white-spaces.
Definition: string.hpp:519
String pad_back(size_type len, char c=' ') const
Pads the back of the string up to a desired length.
Definition: string.hpp:416
bool starts_with(const String &head) const
Checks whether this string starts with another string.
Definition: string.hpp:732
const Operation op_min(MPI_MIN)
Operation wrapper for MPI_MIN.
Definition: dist.hpp:275
const Operation op_max(MPI_MAX)
Operation wrapper for MPI_MAX.
Definition: dist.hpp:273
const Operation op_sum(MPI_SUM)
Operation wrapper for MPI_SUM.
Definition: dist.hpp:271
void query_memory_usage(unsigned long long &work_set_size, unsigned long long &work_set_size_peak, unsigned long long &page_file_usage, unsigned long long &page_file_usage_peak)
Queries memory usage information.
Definition: os_windows.cpp:41
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:993
String stringify_bytes(std::uint64_t bytes, int precision=3, int width=7)
Prints a byte size to a string using the common units Bytes, KiB, MiB, Gib, TiB or PiB.
Definition: string.hpp:1310