OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
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 
33 #include <boost/filesystem.hpp>
34 
35 #include "Ippl.h"
36 
37 #include <sstream>
38 
39 MemoryProfiler::MemoryProfiler(const std::string& fname, bool restart)
40  : SDDSWriter(fname, restart)
41 {
42  procinfo_m = {
43  {"VmPeak:", VirtualMemory::VMPEAK},
44  {"VmSize:", VirtualMemory::VMSIZE},
45  {"VmHWM:", VirtualMemory::VMHWM},
46  {"VmRSS:", VirtualMemory::VMRSS},
47  {"VmStk:", VirtualMemory::VMSTK},
48  {"VmData:", VirtualMemory::VMDATA},
49  {"VmExe:", VirtualMemory::VMEXE},
50  {"VmLck:", VirtualMemory::VMLCK},
51  {"VmPin:", VirtualMemory::VMPIN},
52  {"VmLib:", VirtualMemory::VMLIB},
53  {"VmPTE:", VirtualMemory::VMPTE},
54  {"VmPMD:", VirtualMemory::VMPMD},
55  {"VmSwap:", VirtualMemory::VMSWAP}
56  };
57 
58  vmem_m.resize(procinfo_m.size());
59  unit_m.resize(procinfo_m.size());
60 }
61 
62 
64 
65  if (this->hasColumns()) {
66  return;
67  }
68 
69  columns_m.addColumn("t", "double", "ns", "Time");
70 
71  columns_m.addColumn("s", "double", "m", "Path length");
72 
73  // peak virtual memory size
74  columns_m.addColumn("VmPeak-Min", "double", unit_m[VirtualMemory::VMPEAK],
75  "Minimum peak virtual memory size");
76 
77  columns_m.addColumn("VmPeak-Max", "double", unit_m[VirtualMemory::VMPEAK],
78  "Maximum peak virtual memory size");
79 
80  columns_m.addColumn("VmPeak-Avg", "double", unit_m[VirtualMemory::VMPEAK],
81  "Average peak virtual memory size");
82 
83  // virtual memory size
84  columns_m.addColumn("VmSize-Min", "double", unit_m[VirtualMemory::VMSIZE],
85  "Minimum virtual memory size");
86 
87  columns_m.addColumn("VmSize-Max", "double", unit_m[VirtualMemory::VMSIZE],
88  "Maximum virtual memory size");
89 
90  columns_m.addColumn("VmSize-Avg", "double", unit_m[VirtualMemory::VMSIZE],
91  "Average virtual memory size");
92 
93  // peak resident set size ("high water mark")
94  columns_m.addColumn("VmHWM-Min", "double", unit_m[VirtualMemory::VMHWM],
95  "Minimum peak resident set size");
96 
97  columns_m.addColumn("VmHWM-Max", "double", unit_m[VirtualMemory::VMHWM],
98  "Maximum peak resident set size");
99 
100  columns_m.addColumn("VmHWM-Avg", "double", unit_m[VirtualMemory::VMHWM],
101  "Average peak resident set size");
102 
103  // resident set size
104  columns_m.addColumn("VmRSS-Min", "double", unit_m[VirtualMemory::VMRSS],
105  "Minimum resident set size");
106 
107  columns_m.addColumn("VmRSS-Max", "double", unit_m[VirtualMemory::VMRSS],
108  "Maximum resident set size");
109 
110  columns_m.addColumn("VmRSS-Avg", "double", unit_m[VirtualMemory::VMRSS],
111  "Average resident set size");
112 
113  // stack size
114  columns_m.addColumn("VmStk-Min", "double", unit_m[VirtualMemory::VMSTK],
115  "Minimum stack size");
116 
117  columns_m.addColumn("VmStk-Max", "double", unit_m[VirtualMemory::VMSTK],
118  "Maximum stack size");
119 
120  columns_m.addColumn("VmStk-Avg", "double", unit_m[VirtualMemory::VMSTK],
121  "Average stack size");
122 
123  if ( mode_m == std::ios::app )
124  return;
125 
126  OPALTimer::Timer simtimer;
127 
128  std::string dateStr(simtimer.date());
129  std::string timeStr(simtimer.time());
130 
131  std::stringstream ss;
132  ss << "Memory statistics '"
133  << OpalData::getInstance()->getInputFn() << "' "
134  << dateStr << "" << timeStr;
135 
136  this->addDescription(ss.str(), "memory info");
137 
138  this->addDefaultParameters();
139 
140  this->addInfo("ascii", 1);
141 }
142 
143 
145 #ifdef __linux__
146  static pid_t pid = getpid();
147  std::string fname = "/proc/" + std::to_string(pid) + "/status";
148 
149  if ( !boost::filesystem::exists(fname) ) {
150  throw OpalException("MemoryProfiler::update()",
151  "File '" + fname + "' doesn't exist.");
152  }
153 
154  std::ifstream ifs(fname.c_str());
155 
156  if ( !ifs.is_open() ) {
157  throw OpalException("MemoryProfiler::update()",
158  "Failed to open '" + fname + "'.");
159  }
160 
161  std::string token = "";
162  while (ifs >> token) {
163  if ( !procinfo_m.count(token) ) {
164  continue;
165  }
166  int idx = procinfo_m[token];
167  ifs >> vmem_m[idx]
168  >> unit_m[idx];
169  }
170 
171  ifs.close();
172 #endif
173 }
174 
175 
177  vm_t& vmMax,
178  vm_t& vmAvg)
179 {
180  if ( Ippl::getNodes() == 1 ) {
181  for (unsigned int i = 0; i < vmem_m.size(); ++i) {
182  vmMin[i] = vmMax[i] = vmAvg[i] = vmem_m[i];
183  }
184  return;
185  }
186 
187  new_reduce(vmem_m.data(), vmAvg.data(), vmem_m.size(), std::plus<double>());
188 
189  double inodes = 1.0 / double(Ippl::getNodes());
190  for (auto& vm : vmAvg) {
191  vm *= inodes;
192  }
193 
194  new_reduce(vmem_m.data(), vmMin.data(), vmem_m.size(), std::less<double>());
195  new_reduce(vmem_m.data(), vmMax.data(), vmem_m.size(), std::greater<double>());
196 }
197 
198 
200 
201  this->update();
202 
203  vm_t vmMin(vmem_m.size());
204  vm_t vmMax(vmem_m.size());
205  vm_t vmAvg(vmem_m.size());
206 
207  this->compute(vmMin, vmMax, vmAvg);
208 
209  if ( Ippl::myNode() != 0 ) {
210  return;
211  }
212 
213  double pathLength = beam->get_sPos();
214 
215  header();
216 
217  this->open();
218 
219  this->writeHeader();
220 
221  columns_m.addColumnValue("t", beam->getT() * 1e9); // 1
222  columns_m.addColumnValue("s", pathLength); // 2
223 
224  // boost::variant can't overload double and long double. By using a
225  // string this shortcoming can be bypassed.
226  columns_m.addColumnValue("VmPeak-Min", toString(vmMin[VMPEAK]));
227  columns_m.addColumnValue("VmPeak-Max", toString(vmMax[VMPEAK]));
228  columns_m.addColumnValue("VmPeak-Avg", toString(vmAvg[VMPEAK]));
229 
230  columns_m.addColumnValue("VmSize-Min", toString(vmMin[VMSIZE]));
231  columns_m.addColumnValue("VmSize-Max", toString(vmMax[VMSIZE]));
232  columns_m.addColumnValue("VmSize-Avg", toString(vmAvg[VMSIZE]));
233 
234  columns_m.addColumnValue("VmHWM-Min", toString(vmMin[VMHWM]));
235  columns_m.addColumnValue("VmHWM-Max", toString(vmMax[VMHWM]));
236  columns_m.addColumnValue("VmHWM-Avg", toString(vmAvg[VMHWM]));
237 
238  columns_m.addColumnValue("VmRSS-Min", toString(vmMin[VMRSS]));
239  columns_m.addColumnValue("VmRSS-Max", toString(vmMax[VMRSS]));
240  columns_m.addColumnValue("VmRSS-Avg", toString(vmAvg[VMRSS]));
241 
242  columns_m.addColumnValue("VmStk-Min", toString(vmMin[VMSTK]));
243  columns_m.addColumnValue("VmStk-Max", toString(vmMax[VMSTK]));
244  columns_m.addColumnValue("VmStk-Avg", toString(vmAvg[VMSTK]));
245 
246  this->writeRow();
247 
248  this->close();
249 }
void new_reduce(const T *input, T *output, int count, Op op, int root=0)
Definition: GlobalComm.hpp:477
double get_sPos() const
double getT() const
std::string getInputFn()
get opals input filename
Definition: OpalData.cpp:654
static OpalData * getInstance()
Definition: OpalData.cpp:195
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