9 #include <framework/core/ProcessStatistics.h>
11 #include <framework/logging/Logger.h>
12 #include <framework/pcore/ProcHandler.h>
13 #include <framework/gearbox/Unit.h>
14 #include <framework/utilities/Utils.h>
16 #include <boost/algorithm/string/replace.hpp>
18 #include <boost/format.hpp>
26 int ProcessStatistics::getIndex(
const Module* module)
28 auto indexIt = m_modulesToStatsIndex.find(module);
29 if (indexIt == m_modulesToStatsIndex.end()) {
30 int index = m_stats.size();
31 m_modulesToStatsIndex[module] = index;
32 m_stats.emplace_back();
36 return indexIt->second;
39 void ProcessStatistics::initModule(
const Module* module)
41 int index = getIndex(module);
43 if (module and stats.getName().empty()) {
44 const string& type = module->getType();
45 if (type ==
"Tx" or type ==
"Rx")
48 stats.setName(module->getName());
50 stats.setIndex(index);
54 const std::vector<ModuleStatistics>* modules,
bool html)
const
57 if (!modules) modules = &(getAll());
58 int moduleNameLength = 21;
59 const int lengthOfRest = 80 - moduleNameLength;
61 int len = stats.getName().length();
62 if (len > moduleNameLength)
63 moduleNameLength = len;
65 const std::string numTabsModule = (boost::format(
"%d") % (moduleNameLength + 1)).str();
66 const std::string numWidth = (boost::format(
"%d") % (moduleNameLength + 1 + lengthOfRest)).str();
67 boost::format outputheader(
"%s %|" + numTabsModule +
"t|| %10s | %10s | %10s | %17s\n");
68 boost::format output(
"%s %|" + numTabsModule +
"t|| %10.0f | %10.0f | %10.2f | %7.2f +-%7.2f\n");
70 outputheader = boost::format(
"<thead><tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr></thead>");
71 output = boost::format(
"<tr><td>%s</td><td>%.0f</td><td>%.0f</td><td>%.2f</td><td>%.2f ± %.2f</td></tr>");
76 out << boost::format(
"%|" + numWidth +
"T=|\n");
77 out << outputheader %
"Name" %
"Calls" %
"Memory(MB)" %
"Time(s)" %
"Time(ms)/Call";
78 out << boost::format(
"%|" + numWidth +
"T=|\n");
80 out <<
"<table border=0>";
81 out << outputheader %
"Name" %
"Calls" %
"Memory(MB)" %
"Time(s)" %
"Time(ms)/Call";
85 std::vector<ModuleStatistics> modulesSortedByIndex(*modules);
86 sort(modulesSortedByIndex.begin(), modulesSortedByIndex.end(), [](
const ModuleStatistics & a,
const ModuleStatistics & b) { return a.getIndex() < b.getIndex(); });
91 % stats.getCalls(mode)
92 % (stats.getMemorySum(mode) / 1024)
93 % (stats.getTimeSum(mode) / Unit::s)
94 % (stats.getTimeMean(mode) / Unit::ms)
95 % (stats.getTimeStddev(mode) / Unit::ms);
99 out << boost::format(
"%|" + numWidth +
"T=|\n");
101 out <<
"</tbody><tfoot>";
104 % (ProcHandler::isOutputProcess() ?
"Total (output proc.)" :
"Total")
111 out << boost::format(
"%|" + numWidth +
"T=|\n");
113 out <<
"</tfoot></table>";
120 unsigned int minIndexUnmerged = 0;
122 B2WARNING(
"ProcessStatistics::appendUnmergedModules(): Module -> index list is empty? This might produce wrong results");
126 if (pair.second < (
int)minIndexUnmerged)
127 minIndexUnmerged = pair.second;
130 if (minIndexUnmerged > m_stats.size())
131 B2FATAL(
"(minIndexUnmerged > m_stats.size()) :( ");
132 if (minIndexUnmerged > otherObject->
m_stats.size())
133 B2FATAL(
"(minIndexUnmerged > otherObject->m_stats.size()) :( ");
137 for (
unsigned int i = 0; i < minIndexUnmerged; i++) {
141 myStats.
update(otherStats);
143 B2ERROR(
"mismatch in module names in statistics (" << myStats.
getName() <<
" vs. " << otherStats.
getName() <<
144 "). ProcessStatistics::merge() can only merge statistics that contain exactly the same modules.");
149 for (
unsigned int i = minIndexUnmerged; i < otherObject->
m_stats.size(); i++) {
151 m_stats.emplace_back(otherStats);
152 m_stats.back().setIndex(m_stats.size() - 1);
156 const int shift = m_stats.size() - otherObject->
m_stats.size();
158 B2FATAL(
"shift negative:" <<
LogVar(
"shift", shift));
161 m_modulesToStatsIndex[pair.first] = pair.second + shift;
170 if (m_stats == otherObject->m_stats) {
172 for (
unsigned int i = 0; i < otherObject->m_stats.size(); i++)
173 m_stats[i].update(otherObject->m_stats[i]);
177 m_global.update(otherObject->m_global);
179 appendUnmergedModules(otherObject);
183 if (!otherObject->m_modulesToStatsIndex.empty())
184 setTransientCounters(otherObject);
197 void ProcessStatistics::clear()
200 for (
auto& stats : m_stats) { stats.clear(); }
203 void ProcessStatistics::setCounters(
double& time,
double& memory,
204 double startTime,
double startMemory)
206 time = Utils::getClock() - startTime;
207 memory = Utils::getRssMemoryKB() - startMemory;
210 TObject* ProcessStatistics::Clone(
const char*)
const
216 std::string ProcessStatistics::getInfoHTML()
const
218 std::string s = getStatisticsString();
219 return "Event Statistics:<br />" + s;
Abstract base class for objects that can be merged.
Keep track of time and memory consumption during processing.
value_type getTimeStddev(EStatisticCounters type=c_Total) const
return the stddev of the execution times for a given counter
value_type getCalls(EStatisticCounters type=c_Total) const
return the number of calls for a given counter type
const std::string & getName() const
Return the previously set name.
EStatisticCounters
Enum to define all counter types.
value_type getMemorySum(EStatisticCounters type=c_Total) const
return the total used memory for a given counter
value_type getTimeSum(EStatisticCounters type=c_Total) const
return the sum of all execution times for a given counter
value_type getTimeMean(EStatisticCounters type=c_Total) const
return the mean execution time for a given counter
void update(const ModuleStatistics &other)
Add statistics for each category.
Class to collect call statistics for all modules.
double m_globalTime
store clock counter for global time consumption
double m_suspendedMemory
(transient)
std::map< const Module *, int > m_modulesToStatsIndex
transient, maps Module* to m_stats index.
std::vector< Belle2::ModuleStatistics > m_stats
module statistics
double m_suspendedTime
(transient)
double m_moduleTime
(transient)
double m_globalMemory
(transient)
double m_moduleMemory
(transient)
Class to store variables with their name which were sent to the logging service.
std::vector< std::vector< double > > merge(std::vector< std::vector< std::vector< double >>> toMerge)
merge { vector<double> a, vector<double> b} into {a, b}
Abstract base class for different kinds of events.