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