ATLAS Offline Software
PerfMonMTUtils.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 /*
6  * @authors: Alaettin Serhan Mete, Hasan Ozturk - alaettin.serhan.mete@cern.ch, haozturk@cern.ch
7  */
8 
9 #ifndef PERFMONCOMPS_PERFMONMTUTILS_H
10 #define PERFMONCOMPS_PERFMONMTUTILS_H
11 
12 // Thread-safety-checker
14 
15 // PerfMon includes
16 #include "SemiDetMisc.h" // borrow from existing code
17 #include "PerfMonEvent/mallinfo.h"
18 
19 // STL includes
20 #include <fcntl.h> // for open function
21 #include <malloc.h> // for mallinfo function
22 #include <sys/stat.h> // to check whether /proc/* exists in the machine
23 
24 #include <chrono>
25 #include <cstdint>
26 #include <ctime>
27 #include <fstream>
28 #include <map>
29 #include <string>
30 
31 typedef std::map<std::string, int64_t> MemoryMap_t; // Component : Memory Measurement(kB)
32 
33 /*
34  * Inline function prototypes
35  */
36 inline MemoryMap_t operator-(const MemoryMap_t& map1, const MemoryMap_t& map2);
37 
38 /*
39  * Necessary tools
40  */
41 namespace PMonMT {
42 
43  // Base methods for collecting data
44  double get_thread_cpu_time();
45  double get_process_cpu_time();
46  double get_wall_time();
47 
48  // Non-efficient memory measurement
50 
51  // Efficient memory measurements
52  double get_vmem();
53 
54  // Simple check if directory exists
55  bool doesDirectoryExist(const std::string& dir);
56 
57  // Step name and Component name pairs. Ex: Initialize - StoreGateSvc
58  struct StepComp {
59  std::string stepName;
60  std::string compName;
61 
62  // Overload < operator, because we are using a custom key(StepComp) for std::map
63  bool operator<(const StepComp& sc) const {
64  return std::make_pair(this->stepName, this->compName) < std::make_pair(sc.stepName, sc.compName);
65  }
66  };
67 
68  // ComponentMeasurement
70 
71  // Variables to store measurements
72  double cpu_time{}, wall_time{}; // Timing
73  double vmem{}, malloc{}; // Memory: Vmem, Malloc
74 
75  // Capture component-level measurements
76  void capture() {
77 
78  // Timing
81  }
82 
83  // Capture component-level memory measurements
84  bool capture_memory ATLAS_NOT_THREAD_SAFE() {
85 
86  // Memory
87  malloc = PMonSD::get_malloc_kb();
88  vmem = get_vmem();
89  return true; // dummy return value for use with thread-checker macros
90  }
91 
92  // Constructor
93  ComponentMeasurement() : cpu_time{0.}, wall_time{0.}, vmem{0.}, malloc{0.} { }
94 
95  }; // End ComponentMeasurement
96 
97  // Component Data
98  struct ComponentData {
99 
100  // These variables are used to calculate and store the component level measurements
102  double m_tmp_cpu{}, m_delta_cpu{};
106 
107  // [Component Level Monitoring] : Start
108  void addPointStart(const ComponentMeasurement& meas, const bool doMem = false) {
109 
110  // Timing
111  m_tmp_cpu = meas.cpu_time;
112  m_tmp_wall = meas.wall_time;
113 
114  // Memory if only necessary
115  if (!doMem) return;
116 
117  // Memory
118  m_tmp_malloc = meas.malloc;
119  m_tmp_vmem = meas.vmem;
120 
121  }
122 
123  // [Component Level Monitoring] : Stop
124  void addPointStop(const ComponentMeasurement& meas, const bool doMem = false) {
125 
126  // Call count
127  m_call_count++;
128 
129  // Timing
130  m_delta_cpu += meas.cpu_time - m_tmp_cpu;
132 
133  // Memory if only necessary
134  if (!doMem) return;
135 
136  // Memory
138  m_delta_vmem += meas.vmem - m_tmp_vmem;
139 
140  }
141 
142  // Convenience methods
143  uint64_t getCallCount() const { return m_call_count; }
145 
146  double getDeltaCPU() const { return m_delta_cpu; }
147  void add2DeltaCPU(double val) { m_delta_cpu += val; }
148 
149  double getDeltaWall() const { return m_delta_wall; }
150  void add2DeltaWall(double val) { m_delta_wall += val; }
151 
152  double getDeltaVmem() const { return m_delta_vmem; }
153  void add2DeltaVmem(double val) { m_delta_vmem += val; }
154 
155  double getDeltaMalloc() const { return m_delta_malloc; }
156  void add2DeltaMalloc(double val) { m_delta_malloc += val; }
157 
158  // Constructor
160  m_tmp_vmem{0.}, m_delta_vmem{0.}, m_tmp_malloc{0.}, m_delta_malloc{0.} { }
161 
162  }; // End ComponentData
163 
164  // Snapshot Measurement
166 
167  // Variables to store measurements
168  double cpu_time{}, wall_time{}; // Timing
169  MemoryMap_t mem_stats; // Memory: Vmem, Rss, Pss, Swap
170 
171  // Capture snapshot measurements
172  void capture() {
173 
174  // Timing
177 
178  // Memory
180 
181  }
182 
183  // Constructor
185  mem_stats["vmem"] = 0; mem_stats["pss"] = 0; mem_stats["rss"] = 0; mem_stats["swap"] = 0;
186  }
187 
188  }; // End SnapshotMeasurement
189 
190  // Event Level Data
191  struct EventLevelData {
192 
193  // This map is used to store the event level measurements
194  typedef std::map<uint64_t, SnapshotMeasurement> EventMeasMap_t; // Event number: Measurement
196 
197  // [Event Level Monitoring] : Record the measurement for the current checkpoint
198  void recordEvent(const SnapshotMeasurement& meas, const int eventCount) {
199 
200  // Timing
201  m_eventLevelDeltaMap[eventCount].cpu_time = meas.cpu_time;
202  m_eventLevelDeltaMap[eventCount].wall_time = meas.wall_time - m_offset_wall;
203 
204  // Memory
205  m_eventLevelDeltaMap[eventCount].mem_stats = meas.mem_stats;
206 
207  }
208 
209  // Wall time offset for event level monitoring
210  double m_offset_wall{};
211 
212  // Convenience methods
213  void set_wall_time_offset(const double wall_time_offset) { m_offset_wall = wall_time_offset; }
214 
216  return m_eventLevelDeltaMap;
217  }
218 
220  return m_eventLevelDeltaMap.size();
221  }
222 
223  double getEventLevelCpuTime(const uint64_t event_count) const {
224  return m_eventLevelDeltaMap.at(event_count).cpu_time;
225  }
226 
227  double getEventLevelWallTime(const uint64_t event_count) const {
228  return m_eventLevelDeltaMap.at(event_count).wall_time;
229  }
230 
231  int64_t getEventLevelMemory(const uint64_t event_count,
232  const std::string& stat) const {
233  return m_eventLevelDeltaMap.at(event_count).mem_stats.at(stat);
234  }
235 
236  int64_t getEventLevelMemoryMax(const std::string& stat) const {
237  int64_t result = 0;
238  for (const auto& it : getEventLevelData()) {
239  if (it.second.mem_stats.at(stat) > result) {
240  result = it.second.mem_stats.at(stat);
241  }
242  }
243  return result;
244  }
245 
246  }; // Add EventLevelData
247 
248  // Snapshot Data
249  struct SnapshotData {
250 
251  // These variables are used to calculate and store the serial component level measurements
252  double m_tmp_cpu{}, m_delta_cpu{};
255 
256  // [Snapshot Level Monitoring] : Start
257  void addPointStart(const SnapshotMeasurement& meas) {
258 
259  // Timing
260  m_tmp_cpu = meas.cpu_time;
261  m_tmp_wall = meas.wall_time;
262 
263  // Non-efficient memory measurements
264  m_memMonTmpMap = meas.mem_stats;
265 
266  }
267 
268  // [Snapshot Level Monitoring] : Stop
269  void addPointStop(const SnapshotMeasurement& meas) {
270 
271  // Timing
272  m_delta_cpu = meas.cpu_time - m_tmp_cpu;
274 
275  // Non-efficient memory measurements
277 
278  }
279 
280  // Convenience methods
281  double getDeltaCPU() const { return m_delta_cpu; }
282  void add2DeltaCPU(double val) { m_delta_cpu += val; }
283 
284  double getDeltaWall() const { return m_delta_wall; }
285  void add2DeltaWall(double val) { m_delta_wall += val; }
286 
287  int64_t getMemMonDeltaMap(const std::string& mem_stat) const {
288  return m_memMonDeltaMap.at(mem_stat);
289  }
290 
291  // Constructor
293  m_memMonTmpMap["vmem"] = 0; m_memMonTmpMap["pss"] = 0; m_memMonTmpMap["rss"] = 0; m_memMonTmpMap["swap"] = 0;
294  m_memMonDeltaMap["vmem"] = 0; m_memMonDeltaMap["pss"] = 0; m_memMonDeltaMap["rss"] = 0; m_memMonDeltaMap["swap"] = 0;
295  }
296 
297  }; // End SnapshotData
298 
299 } // namespace PMonMT
300 
302 // Inline methods:
304 
305 /*
306  * Thread specific CPU time measurement in ms
307  */
309  // Get the thread specific CPU time
310  struct timespec ctime;
311  clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ctime);
312 
313  // Return the measurement in ms
314  return static_cast<double>(ctime.tv_sec * 1.e3 + ctime.tv_nsec * 1.e-6);
315 }
316 
317 /*
318  * Process specific CPU time measurement in ms
319  */
320 inline double PMonMT::get_process_cpu_time() { return static_cast<double>(std::clock() * (1.e3 / CLOCKS_PER_SEC)); }
321 
322 /*
323  * Wall-time measurement since epoch in ms
324  */
325 inline double PMonMT::get_wall_time() {
326  return static_cast<double>(std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1));
327 }
328 
329 /*
330  * Memory statistics
331  */
332 
333 // Read from proc's smaps file. It is costly to do this operation too often.
334 // In a realistic reconstruction job, the smaps for the the whole application can get large.
335 // Therefore, this operation might take about 100 ms per call, which is fairly substantial.
336 // However, this is one of the most reliable way to get PSS.
337 // Therefore, keep it as is but don't call it too often!
339  // Result object
341 
342  // Zero initialize
343  result["vmem"] = result["rss"] = result["pss"] = result["swap"] = 0;
344 
345  // This is the input where we read the stats from
346  static const std::string fileName = "/proc/self/smaps";
347  std::ifstream smaps_file{fileName};
348 
349  std::string line{}, key{}, value{};
350 
351  // Loop over the file
352  while (smaps_file) {
353  // Read interesting key value pairs
354  smaps_file >> key >> value;
355  smaps_file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
356 
357  if(smaps_file) {
358  if (key == "Size:") {
359  result["vmem"] += std::stol(value);
360  }
361  if (key == "Rss:") {
362  result["rss"] += std::stol(value);
363  }
364  if (key == "Pss:") {
365  result["pss"] += std::stol(value);
366  }
367  if (key == "Swap:") {
368  result["swap"] += std::stol(value);
369  }
370  }
371  }
372 
373  return result;
374 }
375 
376 // This operation is less costly than the previous one. Since statm is a much smaller file compared to smaps.
377 inline double PMonMT::get_vmem() {
378  // Result
379  double result = 0.;
380 
381  // This is where we read the stats from
382  static const std::string fileName = "/proc/self/statm";
383  std::ifstream statm_file{fileName};
384 
385  std::string vmem_in_pages{}, line{}; // vmem measured in pages
386 
387  // We simply get the first line
388  if (getline(statm_file, line)) {
389  std::stringstream ss{line};
390  ss >> vmem_in_pages; // The first number in this file is the vmem measured in pages
391  }
392 
393  static const double page_size = sysconf(_SC_PAGESIZE) / 1024.0; // page size in KB
394  result = std::stod(vmem_in_pages) * page_size;
395 
396  return result;
397 }
398 
399 inline MemoryMap_t operator-(const MemoryMap_t& map1, const MemoryMap_t& map2) {
400  MemoryMap_t result_map;
401  for (auto it : map1) {
402  result_map[it.first] = map1.at(it.first) - map2.at(it.first);
403  }
404  return result_map;
405 }
406 
407 /*
408  * Simple check if a given directory exists
409  */
410 inline bool PMonMT::doesDirectoryExist(const std::string& dir) {
411  struct stat buffer;
412  return (stat(dir.c_str(), &buffer) == 0);
413 }
414 
415 #endif // PERFMONCOMPS_PERFMONMTUTILS_H
PMonMT::ComponentMeasurement::ComponentMeasurement
ComponentMeasurement()
Definition: PerfMonMTUtils.h:93
PMonMT::ComponentData::m_delta_wall
double m_delta_wall
Definition: PerfMonMTUtils.h:103
PMonMT::ComponentData::m_tmp_wall
double m_tmp_wall
Definition: PerfMonMTUtils.h:103
checkFileSG.line
line
Definition: checkFileSG.py:75
get_generator_info.result
result
Definition: get_generator_info.py:21
max
#define max(a, b)
Definition: cfImp.cxx:41
PowhegControl_ttHplus_NLO.ss
ss
Definition: PowhegControl_ttHplus_NLO.py:83
PMonMT::ComponentData::ComponentData
ComponentData()
Definition: PerfMonMTUtils.h:159
PMonMT::ComponentData::addPointStart
void addPointStart(const ComponentMeasurement &meas, const bool doMem=false)
Definition: PerfMonMTUtils.h:108
PMonMT::SnapshotData::getMemMonDeltaMap
int64_t getMemMonDeltaMap(const std::string &mem_stat) const
Definition: PerfMonMTUtils.h:287
PMonMT::EventLevelData
Definition: PerfMonMTUtils.h:191
PMonMT::ComponentData::m_tmp_malloc
double m_tmp_malloc
Definition: PerfMonMTUtils.h:105
PMonMT::get_vmem
double get_vmem()
Definition: PerfMonMTUtils.h:377
PMonMT::SnapshotData::add2DeltaWall
void add2DeltaWall(double val)
Definition: PerfMonMTUtils.h:285
PMonMT::ComponentData::getCallCount
uint64_t getCallCount() const
Definition: PerfMonMTUtils.h:143
PMonMT::StepComp::operator<
bool operator<(const StepComp &sc) const
Definition: PerfMonMTUtils.h:63
PMonMT::ComponentData::add2DeltaWall
void add2DeltaWall(double val)
Definition: PerfMonMTUtils.h:150
PMonMT::SnapshotMeasurement
Definition: PerfMonMTUtils.h:165
skel.it
it
Definition: skel.GENtoEVGEN.py:423
PMonMT::StepComp
Definition: PerfMonMTUtils.h:58
PMonMT::ComponentData::m_tmp_cpu
double m_tmp_cpu
Definition: PerfMonMTUtils.h:102
PMonMT::ComponentData::m_delta_vmem
double m_delta_vmem
Definition: PerfMonMTUtils.h:104
athena.value
value
Definition: athena.py:122
PMonMT::EventLevelData::getEventLevelData
EventMeasMap_t getEventLevelData() const
Definition: PerfMonMTUtils.h:215
PMonMT::SnapshotData::m_tmp_cpu
double m_tmp_cpu
Definition: PerfMonMTUtils.h:252
PMonMT::ComponentData::getDeltaCPU
double getDeltaCPU() const
Definition: PerfMonMTUtils.h:146
PMonMT::get_process_cpu_time
double get_process_cpu_time()
Definition: PerfMonMTUtils.h:320
SemiDetMisc.h
PMonMT::ComponentMeasurement::ATLAS_NOT_THREAD_SAFE
bool capture_memory ATLAS_NOT_THREAD_SAFE()
Definition: PerfMonMTUtils.h:84
PMonMT::ComponentMeasurement::cpu_time
double cpu_time
Definition: PerfMonMTUtils.h:72
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
PMonMT::ComponentMeasurement
Definition: PerfMonMTUtils.h:69
operator-
MemoryMap_t operator-(const MemoryMap_t &map1, const MemoryMap_t &map2)
Definition: PerfMonMTUtils.h:399
PMonMT::ComponentData::add2DeltaMalloc
void add2DeltaMalloc(double val)
Definition: PerfMonMTUtils.h:156
PMonMT::get_wall_time
double get_wall_time()
Definition: PerfMonMTUtils.h:325
python.handimod.now
now
Definition: handimod.py:675
createCoolChannelIdFile.buffer
buffer
Definition: createCoolChannelIdFile.py:12
FortranAlgorithmOptions.fileName
fileName
Definition: FortranAlgorithmOptions.py:13
PMonMT::ComponentMeasurement::wall_time
double wall_time
Definition: PerfMonMTUtils.h:72
PMonMT::SnapshotData::add2DeltaCPU
void add2DeltaCPU(double val)
Definition: PerfMonMTUtils.h:282
PMonMT::EventLevelData::getEventLevelMemoryMax
int64_t getEventLevelMemoryMax(const std::string &stat) const
Definition: PerfMonMTUtils.h:236
PMonMT::SnapshotData::m_delta_cpu
double m_delta_cpu
Definition: PerfMonMTUtils.h:252
PMonMT::SnapshotMeasurement::wall_time
double wall_time
Definition: PerfMonMTUtils.h:168
PMonMT::ComponentData::add2DeltaVmem
void add2DeltaVmem(double val)
Definition: PerfMonMTUtils.h:153
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
PMonMT::SnapshotMeasurement::SnapshotMeasurement
SnapshotMeasurement()
Definition: PerfMonMTUtils.h:184
PMonMT::ComponentData::getDeltaWall
double getDeltaWall() const
Definition: PerfMonMTUtils.h:149
PMonMT::ComponentData::m_call_count
uint64_t m_call_count
Definition: PerfMonMTUtils.h:101
PMonMT::SnapshotMeasurement::capture
void capture()
Definition: PerfMonMTUtils.h:172
PMonMT::ComponentData
Definition: PerfMonMTUtils.h:98
PerfMon::clock_gettime
struct timespec clock_gettime()
Definition: PerfMonEventDict.h:21
PMonMT::ComponentData::m_delta_cpu
double m_delta_cpu
Definition: PerfMonMTUtils.h:102
beamspotman.stat
stat
Definition: beamspotman.py:266
mallinfo.h
Wrappers for mallinfo.
PMonMT::EventLevelData::m_eventLevelDeltaMap
EventMeasMap_t m_eventLevelDeltaMap
Definition: PerfMonMTUtils.h:195
beamspotman.dir
string dir
Definition: beamspotman.py:623
PMonMT::EventLevelData::m_offset_wall
double m_offset_wall
Definition: PerfMonMTUtils.h:210
PMonMT::SnapshotData
Definition: PerfMonMTUtils.h:249
PMonMT::SnapshotData::SnapshotData
SnapshotData()
Definition: PerfMonMTUtils.h:292
PMonMT::SnapshotData::m_memMonDeltaMap
MemoryMap_t m_memMonDeltaMap
Definition: PerfMonMTUtils.h:254
PMonMT::StepComp::stepName
std::string stepName
Definition: PerfMonMTUtils.h:59
PMonMT::EventLevelData::getEventLevelMemory
int64_t getEventLevelMemory(const uint64_t event_count, const std::string &stat) const
Definition: PerfMonMTUtils.h:231
PMonMT::get_mem_stats
MemoryMap_t get_mem_stats()
Definition: PerfMonMTUtils.h:338
PMonMT::ComponentMeasurement::vmem
double vmem
Definition: PerfMonMTUtils.h:73
PMonMT::ComponentData::m_tmp_vmem
double m_tmp_vmem
Definition: PerfMonMTUtils.h:104
PMonMT::SnapshotMeasurement::mem_stats
MemoryMap_t mem_stats
Definition: PerfMonMTUtils.h:169
PMonMT::EventLevelData::set_wall_time_offset
void set_wall_time_offset(const double wall_time_offset)
Definition: PerfMonMTUtils.h:213
PMonMT::ComponentData::getDeltaVmem
double getDeltaVmem() const
Definition: PerfMonMTUtils.h:152
PMonMT::EventLevelData::getNMeasurements
uint64_t getNMeasurements() const
Definition: PerfMonMTUtils.h:219
PMonMT::SnapshotData::m_delta_wall
double m_delta_wall
Definition: PerfMonMTUtils.h:253
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
PMonMT::ComponentMeasurement::malloc
double malloc
Definition: PerfMonMTUtils.h:73
PMonMT::ComponentData::add2DeltaCPU
void add2DeltaCPU(double val)
Definition: PerfMonMTUtils.h:147
PMonMT::ComponentData::getDeltaMalloc
double getDeltaMalloc() const
Definition: PerfMonMTUtils.h:155
MemoryMap_t
std::map< std::string, int64_t > MemoryMap_t
Definition: PerfMonMTUtils.h:31
PMonMT::SnapshotData::addPointStart
void addPointStart(const SnapshotMeasurement &meas)
Definition: PerfMonMTUtils.h:257
PMonMT::ComponentData::add2CallCount
void add2CallCount(uint64_t val)
Definition: PerfMonMTUtils.h:144
PMonMT::StepComp::compName
std::string compName
Definition: PerfMonMTUtils.h:60
PMonMT::SnapshotData::addPointStop
void addPointStop(const SnapshotMeasurement &meas)
Definition: PerfMonMTUtils.h:269
PMonMT::ComponentData::addPointStop
void addPointStop(const ComponentMeasurement &meas, const bool doMem=false)
Definition: PerfMonMTUtils.h:124
PMonMT::SnapshotData::m_tmp_wall
double m_tmp_wall
Definition: PerfMonMTUtils.h:253
PMonMT::SnapshotData::getDeltaWall
double getDeltaWall() const
Definition: PerfMonMTUtils.h:284
PMonMT::get_thread_cpu_time
double get_thread_cpu_time()
Definition: PerfMonMTUtils.h:308
checker_macros.h
Define macros for attributes used to control the static checker.
PMonMT::SnapshotMeasurement::cpu_time
double cpu_time
Definition: PerfMonMTUtils.h:168
PMonMT::EventLevelData::EventMeasMap_t
std::map< uint64_t, SnapshotMeasurement > EventMeasMap_t
Definition: PerfMonMTUtils.h:194
PMonMT::doesDirectoryExist
bool doesDirectoryExist(const std::string &dir)
Definition: PerfMonMTUtils.h:410
PMonMT::ComponentMeasurement::capture
void capture()
Definition: PerfMonMTUtils.h:76
PMonMT::SnapshotData::getDeltaCPU
double getDeltaCPU() const
Definition: PerfMonMTUtils.h:281
PMonMT::EventLevelData::getEventLevelWallTime
double getEventLevelWallTime(const uint64_t event_count) const
Definition: PerfMonMTUtils.h:227
PMonMT::SnapshotData::m_memMonTmpMap
MemoryMap_t m_memMonTmpMap
Definition: PerfMonMTUtils.h:254
PMonMT::EventLevelData::recordEvent
void recordEvent(const SnapshotMeasurement &meas, const int eventCount)
Definition: PerfMonMTUtils.h:198
PMonMT
Definition: PerfMonMTUtils.h:41
PMonMT::ComponentData::m_delta_malloc
double m_delta_malloc
Definition: PerfMonMTUtils.h:105
PMonMT::EventLevelData::getEventLevelCpuTime
double getEventLevelCpuTime(const uint64_t event_count) const
Definition: PerfMonMTUtils.h:223
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37