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