File indexing completed on 2025-09-15 08:17:54
0001
0002
0003
0004 #pragma once
0005
0006 #include <JANA/JEventProcessor.h>
0007
0008 #include <map>
0009 #include <string>
0010
0011 class JEventProcessorJANATOP : public JEventProcessor {
0012 private:
0013 enum node_type { kDefault, kProcessor, kFactory, kCache, kSource };
0014
0015 class CallLink {
0016 public:
0017 std::string caller_name;
0018 std::string caller_tag;
0019 std::string callee_name;
0020 std::string callee_tag;
0021
0022 bool operator<(const CallLink& link) const {
0023 if (this->caller_name != link.caller_name)
0024 return this->caller_name < link.caller_name;
0025 if (this->callee_name != link.callee_name)
0026 return this->callee_name < link.callee_name;
0027 if (this->caller_tag != link.caller_tag)
0028 return this->caller_tag < link.caller_tag;
0029 return this->callee_tag < link.callee_tag;
0030 }
0031 };
0032
0033 class CallStats {
0034 public:
0035 CallStats(void) {
0036 from_cache_ms = 0;
0037 from_source_ms = 0;
0038 from_factory_ms = 0;
0039 data_not_available_ms = 0;
0040 Nfrom_cache = 0;
0041 Nfrom_source = 0;
0042 Nfrom_factory = 0;
0043 Ndata_not_available = 0;
0044 }
0045 double from_cache_ms;
0046 double from_source_ms;
0047 double from_factory_ms;
0048 double data_not_available_ms;
0049 unsigned int Nfrom_cache;
0050 unsigned int Nfrom_source;
0051 unsigned int Nfrom_factory;
0052 unsigned int Ndata_not_available;
0053 };
0054
0055 class FactoryCallStats {
0056 public:
0057 FactoryCallStats(void) {
0058 type = kDefault;
0059 time_waited_on = 0.0;
0060 time_waiting = 0.0;
0061 Nfrom_factory = 0;
0062 Nfrom_source = 0;
0063 Nfrom_cache = 0;
0064 }
0065 node_type type;
0066 double time_waited_on;
0067 double time_waiting;
0068 unsigned int Nfrom_factory;
0069 unsigned int Nfrom_source;
0070 unsigned int Nfrom_cache;
0071 };
0072
0073 public:
0074 JEventProcessorJANATOP() : JEventProcessor() { SetTypeName("JEventProcessorJANATOP"); };
0075
0076 void Init() override {};
0077
0078 void BeginRun(const std::shared_ptr<const JEvent>& ) override {};
0079
0080 void Process(const std::shared_ptr<const JEvent>& event) override {
0081
0082 auto stack = event->GetJCallGraphRecorder()->GetCallGraph();
0083
0084
0085 std::lock_guard<std::mutex> lck(mutex);
0086
0087
0088 for (unsigned int i = 0; i < stack.size(); i++) {
0089
0090
0091 std::string nametag1 = MakeNametag(stack[i].caller_name, stack[i].caller_tag);
0092 std::string nametag2 = MakeNametag(stack[i].callee_name, stack[i].callee_tag);
0093
0094 FactoryCallStats& fcallstats1 = factory_stats[nametag1];
0095 FactoryCallStats& fcallstats2 = factory_stats[nametag2];
0096
0097 auto delta_t_ms = std::chrono::duration_cast<std::chrono::milliseconds>(stack[i].end_time -
0098 stack[i].start_time)
0099 .count();
0100 fcallstats1.time_waiting += delta_t_ms;
0101 fcallstats2.time_waited_on += delta_t_ms;
0102
0103
0104 CallLink link;
0105 link.caller_name = stack[i].caller_name;
0106 link.caller_tag = stack[i].caller_tag;
0107 link.callee_name = stack[i].callee_name;
0108 link.callee_tag = stack[i].callee_tag;
0109 CallStats& stats =
0110 call_links[link];
0111
0112 switch (stack[i].data_source) {
0113 case JCallGraphRecorder::DATA_NOT_AVAILABLE:
0114 stats.Ndata_not_available++;
0115 stats.data_not_available_ms += delta_t_ms;
0116 break;
0117 case JCallGraphRecorder::DATA_FROM_CACHE:
0118 fcallstats2.Nfrom_cache++;
0119 stats.Nfrom_cache++;
0120 stats.from_cache_ms += delta_t_ms;
0121 break;
0122 case JCallGraphRecorder::DATA_FROM_SOURCE:
0123 fcallstats2.Nfrom_source++;
0124 stats.Nfrom_source++;
0125 stats.from_source_ms += delta_t_ms;
0126 break;
0127 case JCallGraphRecorder::DATA_FROM_FACTORY:
0128 fcallstats2.Nfrom_factory++;
0129 stats.Nfrom_factory++;
0130 stats.from_factory_ms += delta_t_ms;
0131 break;
0132 }
0133 }
0134 };
0135
0136 void EndRun() override {};
0137
0138 void Finish() override {
0139
0140
0141
0142 std::set<std::string> callers;
0143 std::set<std::string> callees;
0144 for (auto iter = call_links.begin(); iter != call_links.end(); iter++) {
0145 const CallLink& link = iter->first;
0146 std::string caller = MakeNametag(link.caller_name, link.caller_tag);
0147 std::string callee = MakeNametag(link.callee_name, link.callee_tag);
0148 callers.insert(caller);
0149 callees.insert(callee);
0150 }
0151
0152
0153
0154 double total_ms = 0.0;
0155 for (auto iter = call_links.begin(); iter != call_links.end(); iter++) {
0156 const CallLink& link = iter->first;
0157 const CallStats& stats = iter->second;
0158 std::string caller = MakeNametag(link.caller_name, link.caller_tag);
0159 std::string callee = MakeNametag(link.callee_name, link.callee_tag);
0160 if (callees.find(caller) == callees.end()) {
0161 total_ms += stats.from_factory_ms + stats.from_source_ms + stats.from_cache_ms +
0162 stats.data_not_available_ms;
0163 }
0164 }
0165 if (total_ms == 0.0)
0166 total_ms = 1.0;
0167
0168
0169 std::cout << "Links:" << std::endl;
0170 std::vector<std::pair<CallLink, CallStats>> call_links_vector{
0171 std::make_move_iterator(std::begin(call_links)),
0172 std::make_move_iterator(std::end(call_links))};
0173 [[maybe_unused]] auto call_links_compare_time = [](const auto& a, const auto& b) {
0174 return ((a.second.from_factory_ms + a.second.from_source_ms + a.second.from_cache_ms) <
0175 (b.second.from_factory_ms + b.second.from_source_ms + b.second.from_cache_ms));
0176 };
0177 [[maybe_unused]] auto call_links_compare_N = [](const auto& a, const auto& b) {
0178 return ((a.second.Nfrom_factory + a.second.Nfrom_source + a.second.Nfrom_cache) <
0179 (b.second.Nfrom_factory + b.second.Nfrom_source + b.second.Nfrom_cache));
0180 };
0181 std::sort(call_links_vector.begin(), call_links_vector.end(), call_links_compare_time);
0182 for (auto iter = call_links_vector.end() - std::min(call_links_vector.size(), 10ul);
0183 iter != call_links_vector.end(); iter++) {
0184 const CallLink& link = iter->first;
0185 const CallStats& stats = iter->second;
0186
0187 unsigned int Ntotal = stats.Nfrom_cache + stats.Nfrom_source + stats.Nfrom_factory;
0188
0189 std::string nametag1 = MakeNametag(link.caller_name, link.caller_tag);
0190 std::string nametag2 = MakeNametag(link.callee_name, link.callee_tag);
0191
0192 double this_ms = stats.from_factory_ms + stats.from_source_ms + stats.from_cache_ms;
0193 std::string timestr = MakeTimeString(stats.from_factory_ms);
0194 double percent = 100.0 * this_ms / total_ms;
0195 char percentstr[32];
0196 snprintf(percentstr, 32, "%5.1f%%", percent);
0197
0198 std::cout << Ntotal << " calls, " << timestr << " (" << percentstr << ") ";
0199 std::cout << nametag1 << " -> " << nametag2;
0200 std::cout << std::endl;
0201 }
0202
0203
0204 std::cout << "Factories:" << std::endl;
0205 std::vector<std::pair<std::string, FactoryCallStats>> factory_stats_vector{
0206 std::make_move_iterator(std::begin(factory_stats)),
0207 std::make_move_iterator(std::end(factory_stats))};
0208 auto factory_stats_compare = [](const auto& a, const auto& b) {
0209 return ((a.second.time_waited_on - a.second.time_waiting) <
0210 (b.second.time_waited_on - b.second.time_waiting));
0211 };
0212 std::sort(factory_stats_vector.begin(), factory_stats_vector.end(), factory_stats_compare);
0213 for (auto iter = factory_stats_vector.end() - std::min(factory_stats_vector.size(), 10ul);
0214 iter != factory_stats_vector.end(); iter++) {
0215 FactoryCallStats& fcall_stats = iter->second;
0216 std::string nodename = iter->first;
0217
0218
0219 double time_spent_in_factory = fcall_stats.time_waited_on - fcall_stats.time_waiting;
0220 std::string timestr = MakeTimeString(time_spent_in_factory);
0221 double percent = 100.0 * time_spent_in_factory / total_ms;
0222 char percentstr[32];
0223 snprintf(percentstr, 32, "%5.1f%%", percent);
0224
0225 std::cout << timestr << " (" << percentstr << ") ";
0226 std::cout << nodename;
0227 std::cout << std::endl;
0228 }
0229 };
0230
0231 private:
0232 std::mutex mutex;
0233
0234 std::map<CallLink, CallStats> call_links;
0235 std::map<std::string, FactoryCallStats> factory_stats;
0236
0237 std::string MakeTimeString(double time_in_ms) {
0238 double order = log10(time_in_ms);
0239 std::stringstream ss;
0240 ss << std::fixed << std::setprecision(2);
0241 if (order < 0) {
0242 ss << time_in_ms * 1000.0 << " us";
0243 } else if (order <= 2.0) {
0244 ss << time_in_ms << " ms";
0245 } else {
0246 ss << time_in_ms / 1000.0 << " s";
0247 }
0248 return ss.str();
0249 }
0250
0251 std::string MakeNametag(const std::string& name, const std::string& tag) {
0252 std::string nametag = name;
0253 if (tag.size() > 0)
0254 nametag += ":" + tag;
0255 return nametag;
0256 }
0257 };