Belle II Software  release-06-00-14
ProfileModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <framework/modules/profile/ProfileModule.h>
10 #include <framework/dataobjects/ProfileInfo.h>
11 #include <framework/datastore/StoreObjPtr.h>
12 #include <framework/utilities/Utils.h>
13 #include <framework/gearbox/Unit.h>
14 
15 #include <TROOT.h>
16 #include <TCanvas.h>
17 #include <TGraph.h>
18 #include <TH1.h>
19 
20 
21 using namespace Belle2;
22 
23 //-----------------------------------------------------------------
24 // Register the Module
25 //-----------------------------------------------------------------
26 REG_MODULE(Profile)
27 
28 //-----------------------------------------------------------------
29 // Implementation
30 //-----------------------------------------------------------------
31 
32 ProfileModule::ProfileModule() : Module(), m_outputFileName(""), m_rssOutputFileName(""), m_timeOffset(Utils::getClock() / Unit::s),
33  m_nEvents(0), m_step(1),
34  m_eventInfo(k_maxPoints)
35 {
36  // Set module properties
37  setDescription("Records execution time and memory usage in ProfileInfo objects for each event. Can also graph memory usage.");
38  addParam("outputFileName", m_outputFileName, "File name of virtual memory usage plot.", std::string(""));
39  addParam("rssOutputFileName", m_rssOutputFileName, "File name of rss memory usage plot.", std::string(""));
40 }
41 
43 {
45  m_nEvents = 0;
46  m_step = 1;
47 
48  StoreObjPtr<ProfileInfo> profileInfoPtr;
49  StoreObjPtr<ProfileInfo> profileInfoStartPtr("ProfileInfo_Start", DataStore::c_Persistent);
50  StoreObjPtr<ProfileInfo> profileInfoEndPtr("ProfileInfo_End", DataStore::c_Persistent);
51  StoreObjPtr<TH1D> virtprofileHistogram("VirtualMemoryProfile", DataStore::c_Persistent);
52  StoreObjPtr<TH1D> rssProfileHistogram("RssMemoryProfile", DataStore::c_Persistent);
53  // Register the profile info objects in the data store
54  profileInfoPtr.registerInDataStore();
55  profileInfoStartPtr.registerInDataStore();
56  profileInfoEndPtr.registerInDataStore();
57  virtprofileHistogram.registerInDataStore();
58  rssProfileHistogram.registerInDataStore();
59 
60  // Store and print profile info at initialization
61  profileInfoStartPtr.create(true);
62  profileInfoStartPtr->set(m_timeOffset);
63  m_initializeInfo = MemTime(profileInfoStartPtr->getVirtualMemory(),
64  profileInfoStartPtr->getRssMemory(),
65  profileInfoStartPtr->getTimeInSec());
66  B2INFO("Virtual Memory usage at initialization [MB]: " << m_initializeInfo.virtualMem / 1024);
67 }
68 
70 {
71  // Store and print profile info at this event
72  StoreObjPtr<ProfileInfo> profileInfoPtr;
73  profileInfoPtr.create(true);
74  profileInfoPtr->set(m_timeOffset);
75  B2DEBUG(100, "Virtual Memory usage [MB]: " << profileInfoPtr->getVirtualMemory() / 1024);
76 
77  // Remember profile info at first (+burn in) and last event
78  if (m_nEvents == k_burnIn) {
79  m_startInfo = MemTime(profileInfoPtr->getVirtualMemory(),
80  profileInfoPtr->getRssMemory(),
81  profileInfoPtr->getTimeInSec());
82  }
83  m_endInfo = MemTime(profileInfoPtr->getVirtualMemory(),
84  profileInfoPtr->getRssMemory(),
85  profileInfoPtr->getTimeInSec());
86 
87  // Add profile info to the vector after each step of events
88  if (m_nEvents % m_step == 0) {
89  int index = m_nEvents / m_step;
90 
91  // Shrink the vector if the maximal number of points is reached
92  if (index >= k_maxPoints) {
93  for (int i = 1; i < k_maxPoints / 2; i++) {
94  m_eventInfo[i] = m_eventInfo[2 * i];
95  }
96  m_step *= 2;
97  index /= 2;
98  }
99 
100  m_eventInfo[index] = MemTime(profileInfoPtr->getVirtualMemory(),
101  profileInfoPtr->getRssMemory(),
102  profileInfoPtr->getTimeInSec());
103  }
104 
105  m_nEvents++;
106 }
107 
108 void ProfileModule::storeMemoryGraph(const std::string& name, const std::string& title, const std::string& yAxisName,
109  const std::string& imgOutput, const MemoryExtractLambda& lmdMemoryExtract)
110 {
111  // Create and save a plot of the memory usage vs. time
112  int nPoints = m_nEvents / m_step;
113  double factorMB = 1. / 1024;
114  if (!imgOutput.empty()) {
115  TDirectory* saveDir = gDirectory;
116  gROOT->cd();
117  auto* can = new TCanvas();
118  auto* graph = new TGraph(nPoints);
119  for (int i = 0; i < nPoints; i++) {
120  graph->SetPoint(i, m_eventInfo[i].time, lmdMemoryExtract(m_eventInfo[i]) * factorMB);
121  }
122  graph->SetMarkerStyle(kMultiply);
123  graph->Draw("ALP");
124  TH1* histo = graph->GetHistogram();
125  histo->SetTitle("");
126  histo->GetYaxis()->SetTitle(yAxisName.c_str());
127  histo->GetXaxis()->SetTitle("Time [s]");
128  can->Print(imgOutput.c_str());
129  saveDir->cd();
130  delete can;
131  delete graph;
132  }
133 
134  // Create a histogram of the memory usage vs. number of events and add it to the DataStore
135  StoreObjPtr<TH1D> profileHistogram(name, DataStore::c_Persistent);
136  profileHistogram.assign(new TH1D(name.c_str(), title.c_str(), nPoints + 1, 0 - 0.5 * m_step, m_nEvents + 0.5 * m_step), true);
137  profileHistogram->SetDirectory(nullptr);
138  profileHistogram->SetStats(false);
139  profileHistogram->GetYaxis()->SetTitle(yAxisName.c_str());
140  profileHistogram->GetXaxis()->SetTitle("Event");
141  profileHistogram->SetBinContent(1, lmdMemoryExtract(m_initializeInfo) * factorMB);
142  for (int i = 0; i < nPoints; i++) {
143  profileHistogram->SetBinContent(i + 2, lmdMemoryExtract(m_eventInfo[i]) * factorMB);
144  }
145 }
146 
148 {
149  // Store and print profile info at termination
150  StoreObjPtr<ProfileInfo> profileInfoEndPtr("ProfileInfo_End", DataStore::c_Persistent);
151  profileInfoEndPtr.create(true);
152  profileInfoEndPtr->set(m_timeOffset);
153  m_terminateInfo = MemTime(profileInfoEndPtr->getVirtualMemory(),
154  profileInfoEndPtr->getRssMemory(),
155  profileInfoEndPtr->getTimeInSec());
156  B2INFO("Virtual Memory usage at termination [MB]: " << m_terminateInfo.virtualMem / 1024);
157  B2INFO("Rss Memory usage at termination [MB] : " << m_terminateInfo.rssMem / 1024);
158 
159  if (m_nEvents > k_burnIn) {
160  B2INFO("Virtual Memory increase per event [kB] : " << ((long)m_endInfo.virtualMem - (long)m_startInfo.virtualMem) /
161  (m_nEvents - k_burnIn));
162  B2INFO("Rss Memory increase per event [kB] : " << ((long)m_endInfo.rssMem - (long)m_startInfo.rssMem) /
163  (m_nEvents - k_burnIn));
164  B2INFO("Execution time per event [ms] : " << 1000 * (m_endInfo.time - m_startInfo.time) / (m_nEvents - k_burnIn));
165  }
166 
167  // store the plots of ther memory consumption for virtual and rss memory
168  storeMemoryGraph("VirtualMemoryProfile", "Virtual Memory usage", "Virtual Memory Usage [MB]",
170  storeMemoryGraph("RssMemoryProfile", "Rss Memory usage", "Rss Memory Usage [MB]",
172 }
@ c_Persistent
Object is available during entire execution time.
Definition: DataStore.h:60
Base class for Modules.
Definition: Module.h:72
A module that measures the execution time and memory usage per event.
Definition: ProfileModule.h:41
const MemoryExtractLambda m_extractVirtualMem
Lambda expression to return the virtual memory from a MemTime data structure.
MemTime m_startInfo
memory usage and time at start of event loop + burn in
static const int k_maxPoints
maximal number of profile points
Definition: ProfileModule.h:84
static const int k_burnIn
number of events before the average time measurement is started
Definition: ProfileModule.h:83
virtual void initialize() override
Initializes the Module.
MemTime m_endInfo
memory usage and time at end of event loop
virtual void event() override
Event profiling.
std::function< unsigned long(MemTime const &) > MemoryExtractLambda
Signature of the lambda functions, which are used to extract the memory usage from teh MemTime struct...
virtual void terminate() override
Terminate the Module.
int m_step
number of events between profile points
std::vector< MemTime > m_eventInfo
memory usage and time at individual events
const MemoryExtractLambda m_extractRssMem
Lambda expression to return the Rss memory from a MemTime data structure.
MemTime m_terminateInfo
memory usage and time at termination
void storeMemoryGraph(const std::string &name, const std::string &title, const std::string &xAxisName, const std::string &imgOutput, const MemoryExtractLambda &lmdMemoryExtract)
Stores the memory usage of the application over time in plots.
std::string m_rssOutputFileName
Name for rss image output file.
Definition: ProfileModule.h:81
double m_timeOffset
time at module creation
MemTime m_initializeInfo
memory usage and time at initialization
std::string m_outputFileName
Name for image output file.
Definition: ProfileModule.h:75
int m_nEvents
event counter
bool assign(TObject *object, bool replace=false)
Assign 'object' to this accessor.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool create(bool replace=false)
Create a default object in the data store.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
The Unit class.
Definition: Unit.h:40
static const double s
[second]
Definition: Unit.h:95
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double getClock()
Return current value of the real-time clock.
Definition: Utils.cc:65
Abstract base class for different kinds of events.
An internal struct to store pairs of memory usage and time.
Definition: ProfileModule.h:89
unsigned long virtualMem
virtual memory usage
Definition: ProfileModule.h:93
double time
execution time
Definition: ProfileModule.h:96
unsigned long rssMem
rss memory usage
Definition: ProfileModule.h:95