OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
MemoryProfiler.cpp
Go to the documentation of this file.
1//
2// Class MemoryProfiler
3// This class writes a SDDS file with virtual memory usage information (Linux only).
4//
5// Copyright (c) 2019, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
6// All rights reserved
7//
8// Implemented as part of the PhD thesis
9// "Precise Simulations of Multibunches in High Intensity Cyclotrons"
10//
11// This file is part of OPAL.
12//
13// OPAL is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// You should have received a copy of the GNU General Public License
19// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
20//
21#include "MemoryProfiler.h"
22
23#ifdef __linux__
24#include <sys/types.h>
25#include <unistd.h>
26#endif
27
28#include "Utilities/Timer.h"
32#include "Physics/Units.h"
33
34#include <boost/filesystem.hpp>
35
36#include "Ippl.h"
37
38#include <sstream>
39
40MemoryProfiler::MemoryProfiler(const std::string& fname, bool restart)
41 : SDDSWriter(fname, restart)
42{
43 procinfo_m = {
44 {"VmPeak:", VirtualMemory::VMPEAK},
45 {"VmSize:", VirtualMemory::VMSIZE},
46 {"VmHWM:", VirtualMemory::VMHWM},
47 {"VmRSS:", VirtualMemory::VMRSS},
48 {"VmStk:", VirtualMemory::VMSTK},
49 {"VmData:", VirtualMemory::VMDATA},
50 {"VmExe:", VirtualMemory::VMEXE},
51 {"VmLck:", VirtualMemory::VMLCK},
52 {"VmPin:", VirtualMemory::VMPIN},
53 {"VmLib:", VirtualMemory::VMLIB},
54 {"VmPTE:", VirtualMemory::VMPTE},
55 {"VmPMD:", VirtualMemory::VMPMD},
56 {"VmSwap:", VirtualMemory::VMSWAP}
57 };
58
59 vmem_m.resize(procinfo_m.size());
60 unit_m.resize(procinfo_m.size());
61}
62
63
65
66 if (this->hasColumns()) {
67 return;
68 }
69
70 columns_m.addColumn("t", "double", "ns", "Time");
71
72 columns_m.addColumn("s", "double", "m", "Path length");
73
74 // peak virtual memory size
75 columns_m.addColumn("VmPeak-Min", "double", unit_m[VirtualMemory::VMPEAK],
76 "Minimum peak virtual memory size");
77
78 columns_m.addColumn("VmPeak-Max", "double", unit_m[VirtualMemory::VMPEAK],
79 "Maximum peak virtual memory size");
80
81 columns_m.addColumn("VmPeak-Avg", "double", unit_m[VirtualMemory::VMPEAK],
82 "Average peak virtual memory size");
83
84 // virtual memory size
85 columns_m.addColumn("VmSize-Min", "double", unit_m[VirtualMemory::VMSIZE],
86 "Minimum virtual memory size");
87
88 columns_m.addColumn("VmSize-Max", "double", unit_m[VirtualMemory::VMSIZE],
89 "Maximum virtual memory size");
90
91 columns_m.addColumn("VmSize-Avg", "double", unit_m[VirtualMemory::VMSIZE],
92 "Average virtual memory size");
93
94 // peak resident set size ("high water mark")
95 columns_m.addColumn("VmHWM-Min", "double", unit_m[VirtualMemory::VMHWM],
96 "Minimum peak resident set size");
97
98 columns_m.addColumn("VmHWM-Max", "double", unit_m[VirtualMemory::VMHWM],
99 "Maximum peak resident set size");
100
101 columns_m.addColumn("VmHWM-Avg", "double", unit_m[VirtualMemory::VMHWM],
102 "Average peak resident set size");
103
104 // resident set size
105 columns_m.addColumn("VmRSS-Min", "double", unit_m[VirtualMemory::VMRSS],
106 "Minimum resident set size");
107
108 columns_m.addColumn("VmRSS-Max", "double", unit_m[VirtualMemory::VMRSS],
109 "Maximum resident set size");
110
111 columns_m.addColumn("VmRSS-Avg", "double", unit_m[VirtualMemory::VMRSS],
112 "Average resident set size");
113
114 // stack size
115 columns_m.addColumn("VmStk-Min", "double", unit_m[VirtualMemory::VMSTK],
116 "Minimum stack size");
117
118 columns_m.addColumn("VmStk-Max", "double", unit_m[VirtualMemory::VMSTK],
119 "Maximum stack size");
120
121 columns_m.addColumn("VmStk-Avg", "double", unit_m[VirtualMemory::VMSTK],
122 "Average stack size");
123
124 if ( mode_m == std::ios::app )
125 return;
126
127 OPALTimer::Timer simtimer;
128
129 std::string dateStr(simtimer.date());
130 std::string timeStr(simtimer.time());
131
132 std::stringstream ss;
133 ss << "Memory statistics '"
134 << OpalData::getInstance()->getInputFn() << "' "
135 << dateStr << "" << timeStr;
136
137 this->addDescription(ss.str(), "memory info");
138
139 this->addDefaultParameters();
140
141 this->addInfo("ascii", 1);
142}
143
144
146#ifdef __linux__
147 static pid_t pid = getpid();
148 std::string fname = "/proc/" + std::to_string(pid) + "/status";
149
150 if ( !boost::filesystem::exists(fname) ) {
151 throw OpalException("MemoryProfiler::update()",
152 "File '" + fname + "' doesn't exist.");
153 }
154
155 std::ifstream ifs(fname.c_str());
156
157 if ( !ifs.is_open() ) {
158 throw OpalException("MemoryProfiler::update()",
159 "Failed to open '" + fname + "'.");
160 }
161
162 std::string token;
163 while (ifs >> token) {
164 if ( !procinfo_m.count(token) ) {
165 continue;
166 }
167 int idx = procinfo_m[token];
168 ifs >> vmem_m[idx]
169 >> unit_m[idx];
170 }
171
172 ifs.close();
173#endif
174}
175
176
178 vm_t& vmMax,
179 vm_t& vmAvg)
180{
181 if ( Ippl::getNodes() == 1 ) {
182 for (unsigned int i = 0; i < vmem_m.size(); ++i) {
183 vmMin[i] = vmMax[i] = vmAvg[i] = vmem_m[i];
184 }
185 return;
186 }
187
188 new_reduce(vmem_m.data(), vmAvg.data(), vmem_m.size(), std::plus<double>());
189
190 double inodes = 1.0 / double(Ippl::getNodes());
191 for (auto& vm : vmAvg) {
192 vm *= inodes;
193 }
194
195 new_reduce(vmem_m.data(), vmMin.data(), vmem_m.size(), std::less<double>());
196 new_reduce(vmem_m.data(), vmMax.data(), vmem_m.size(), std::greater<double>());
197}
198
199
201
202 this->update();
203
204 vm_t vmMin(vmem_m.size());
205 vm_t vmMax(vmem_m.size());
206 vm_t vmAvg(vmem_m.size());
207
208 this->compute(vmMin, vmMax, vmAvg);
209
210 if ( Ippl::myNode() != 0 ) {
211 return;
212 }
213
214 double pathLength = beam->get_sPos();
215
216 header();
217
218 this->open();
219
220 this->writeHeader();
221
222 columns_m.addColumnValue("t", beam->getT() * Units::s2ns); // 1
223 columns_m.addColumnValue("s", pathLength); // 2
224
225 // boost::variant can't overload double and long double. By using a
226 // string this shortcoming can be bypassed.
227 columns_m.addColumnValue("VmPeak-Min", toString(vmMin[VMPEAK]));
228 columns_m.addColumnValue("VmPeak-Max", toString(vmMax[VMPEAK]));
229 columns_m.addColumnValue("VmPeak-Avg", toString(vmAvg[VMPEAK]));
230
231 columns_m.addColumnValue("VmSize-Min", toString(vmMin[VMSIZE]));
232 columns_m.addColumnValue("VmSize-Max", toString(vmMax[VMSIZE]));
233 columns_m.addColumnValue("VmSize-Avg", toString(vmAvg[VMSIZE]));
234
235 columns_m.addColumnValue("VmHWM-Min", toString(vmMin[VMHWM]));
236 columns_m.addColumnValue("VmHWM-Max", toString(vmMax[VMHWM]));
237 columns_m.addColumnValue("VmHWM-Avg", toString(vmAvg[VMHWM]));
238
239 columns_m.addColumnValue("VmRSS-Min", toString(vmMin[VMRSS]));
240 columns_m.addColumnValue("VmRSS-Max", toString(vmMax[VMRSS]));
241 columns_m.addColumnValue("VmRSS-Avg", toString(vmAvg[VMRSS]));
242
243 columns_m.addColumnValue("VmStk-Min", toString(vmMin[VMSTK]));
244 columns_m.addColumnValue("VmStk-Max", toString(vmMax[VMSTK]));
245 columns_m.addColumnValue("VmStk-Avg", toString(vmAvg[VMSTK]));
246
247 this->writeRow();
248
249 this->close();
250}
void new_reduce(const T *input, T *output, int count, Op op, int root=0)
Definition: GlobalComm.hpp:477
constexpr double s2ns
Definition: Units.h:44
double get_sPos() const
double getT() const
std::string getInputFn()
get opals input filename
Definition: OpalData.cpp:665
static OpalData * getInstance()
Definition: OpalData.cpp:196
void write(const PartBunchBase< double, 3 > *beam) override
void compute(vm_t &vmMin, vm_t &vmMax, vm_t &vmAvg)
std::vector< long double > vm_t
MemoryProfiler(const std::string &fname, bool restart)
std::map< std::string, int > procinfo_m
void addColumn(const std::string &name, const std::string &type, const std::string &unit, const std::string &desc, std::ios_base::fmtflags flags=std::ios_base::scientific, unsigned short precision=15)
void addColumnValue(const std::string &name, const T &val)
Definition: SDDSColumnSet.h:63
std::string toString(const T &val)
Definition: SDDSWriter.h:198
SDDSColumnSet columns_m
Definition: SDDSWriter.h:126
bool hasColumns() const
Definition: SDDSWriter.h:207
void addDefaultParameters()
Definition: SDDSWriter.cpp:211
void addDescription(const std::string &text, const std::string &content)
Definition: SDDSWriter.h:164
void open()
Definition: SDDSWriter.cpp:134
void writeHeader()
Write SDDS header.
Definition: SDDSWriter.cpp:151
std::ios_base::openmode mode_m
First write to the statistics output file.
Definition: SDDSWriter.h:124
void close()
Definition: SDDSWriter.cpp:144
void writeRow()
Definition: SDDSWriter.h:192
void addInfo(const std::string &mode, const size_t &no_row_counts)
Definition: SDDSWriter.h:185
The base class for all OPAL exceptions.
Definition: OpalException.h:28
std::string date() const
Return date.
Definition: Timer.cpp:35
std::string time() const
Return time.
Definition: Timer.cpp:42
static int getNodes()
Definition: IpplInfo.cpp:670
static int myNode()
Definition: IpplInfo.cpp:691