LCOV - code coverage report
Current view: top level - proto - routingReceiver.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 103 0
Test Date: 2025-09-04 00:45:34 Functions: 0.0 % 5 0

            Line data    Source code
       1              : #define TRACE_NAME "RoutingReceiver"
       2              : #include "artdaq/DAQdata/Globals.hh"
       3              : 
       4              : #include <arpa/inet.h>
       5              : #include <netinet/in.h>
       6              : #include <poll.h>
       7              : #include <sys/socket.h>
       8              : #include <sys/types.h>
       9              : #include <chrono>
      10              : #include <csignal>
      11              : #include <thread>
      12              : #include "artdaq/Application/LoadParameterSet.hh"
      13              : #include "artdaq/DAQdata/TCPConnect.hh"
      14              : #include "artdaq/DAQrate/detail/RoutingPacket.hh"
      15              : #include "artdaq/DAQrate/detail/TableReceiver.hh"
      16              : #include "canvas/Utilities/Exception.h"
      17              : #include "fhiclcpp/types/Atom.h"
      18              : #include "fhiclcpp/types/OptionalTable.h"
      19              : #include "fhiclcpp/types/TableFragment.h"
      20              : #include "proto/artdaqapp.hh"
      21              : 
      22              : namespace artdaq {
      23              : /**
      24              :  * \brief Class which receives routing tables and prints updates
      25              :  */
      26              : struct RoutingReceiverConfig
      27              : {
      28              :         /// "collection_time_ms": Time to collect routing table updates between printing summaries
      29              :         fhicl::Atom<size_t> collection_time_ms{fhicl::Name{"collection_time_ms"}, fhicl::Comment{"Time to collect routing table updates between printing summaries"}, 1000};
      30              :         /// "print_verbose_info" (Default: true): Print verbose information about each receiver detected in routing tables
      31              :         fhicl::Atom<bool> print_verbose_info{fhicl::Name{"print_verbose_info"}, fhicl::Comment{"Print verbose information about each receiver detected in routing tables"}, true};
      32              :         /// "graph_width": Width of the summary graph
      33              :         fhicl::Atom<size_t> graph_width{fhicl::Name{"graph_width"}, fhicl::Comment{"Width of the summary graph"}, 40};
      34              :         /// Configuration for the TableReceiver. See artdaq::TableReceiver::Config
      35              :         fhicl::OptionalTable<artdaq::TableReceiver::Config> routingTableConfig{fhicl::Name{"routing_table_config"}, fhicl::Comment{"Configuration for the TableReceiver"}};
      36              :         fhicl::TableFragment<artdaq::artdaqapp::Config> artdaqAppConfig;  ///< Configuration for artdaq Application (BoardReader, etc)
      37              : };
      38              : 
      39              : }  // namespace artdaq
      40              : 
      41              : static bool sighandler_init = false;
      42              : static bool should_stop = false;
      43            0 : static void signal_handler(int signum)
      44              : {
      45              :         // Messagefacility may already be gone at this point, TRACE ONLY!
      46              : #if TRACE_REVNUM < 1459
      47              :         TRACE_STREAMER(TLVL_ERROR, &("routingReceiver")[0], 0, 0, 0)
      48              : #else
      49            0 :         TRACE_STREAMER(TLVL_ERROR, TLOG2("routingReceiver", 0), 0)
      50              : #endif
      51            0 :             << "A signal of type " << signum << " was caught by routingReceiver. Stopping receive loop!";
      52              : 
      53            0 :         should_stop = true;
      54              : 
      55              :         sigset_t set;
      56            0 :         pthread_sigmask(SIG_UNBLOCK, nullptr, &set);
      57            0 :         pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
      58            0 : }
      59              : 
      60            0 : int main(int argc, char* argv[])
      61              : try
      62              : {
      63            0 :         artdaq::configureMessageFacility("RoutingReceiver", false, false);
      64              :         static std::mutex sighandler_mutex;
      65            0 :         std::unique_lock<std::mutex> lk(sighandler_mutex);
      66              : 
      67            0 :         if (!sighandler_init)  //&& manager_id_ == 0) // ELF 3/22/18: Taking out manager_id_==0 requirement as I think kill(getpid()) is enough protection
      68              :         {
      69            0 :                 sighandler_init = true;
      70            0 :                 std::vector<int> signals = {SIGINT, SIGTERM, SIGUSR1, SIGUSR2};  // SIGQUIT is used by art in normal operation
      71            0 :                 for (auto signal : signals)
      72              :                 {
      73              :                         struct sigaction old_action;
      74            0 :                         sigaction(signal, nullptr, &old_action);
      75              : 
      76              :                         // If the old handler wasn't SIG_IGN (it's a handler that just
      77              :                         //  "ignore" the signal)
      78            0 :                         if (old_action.sa_handler != SIG_IGN)  // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
      79              :                         {
      80              :                                 struct sigaction action;
      81            0 :                                 action.sa_handler = signal_handler;
      82            0 :                                 sigemptyset(&action.sa_mask);
      83            0 :                                 for (auto sigblk : signals)
      84              :                                 {
      85            0 :                                         sigaddset(&action.sa_mask, sigblk);
      86              :                                 }
      87            0 :                                 action.sa_flags = 0;
      88              : 
      89              :                                 // Replace the signal handler of SIGINT with the one described by new_action
      90            0 :                                 sigaction(signal, &action, nullptr);
      91              :                         }
      92              :                 }
      93            0 :         }
      94              : 
      95            0 :         fhicl::ParameterSet init_ps = LoadParameterSet<artdaq::RoutingReceiverConfig>(argc, argv, "routingReceiver", "This application receives Routing Tables, and calculates statistics about the usage of the receivers");
      96            0 :         auto config_ps = init_ps.get<fhicl::ParameterSet>("daq", init_ps);
      97            0 :         auto metric_ps = config_ps.get<fhicl::ParameterSet>("metrics", config_ps);
      98            0 :         auto fr_ps = config_ps.get<fhicl::ParameterSet>("fragment_receiver", config_ps);
      99            0 :         auto rmConfig = fr_ps.get<fhicl::ParameterSet>("routing_table_config", fhicl::ParameterSet());
     100            0 :         artdaq::TableReceiver rr(rmConfig);
     101              : 
     102            0 :         auto host_map = artdaq::MakeHostMap(fr_ps);
     103              : 
     104            0 :         auto collection_time_ms = init_ps.get<size_t>("collection_time_ms", 1000);
     105            0 :         auto max_graph_width = init_ps.get<size_t>("max_graph_width", 100);
     106            0 :         bool print_verbose = init_ps.get<bool>("print_verbose_info", true);
     107            0 :         bool verbose_clear_screen = init_ps.get<bool>("clear_screen", true);
     108              : 
     109            0 :         auto blue = "\033[34m";
     110            0 :         auto cyan = "\033[36m";
     111            0 :         auto green = "\033[32m";
     112            0 :         auto yellow = "\033[93m";
     113            0 :         auto red = "\033[31m";
     114              : 
     115            0 :         metricMan->initialize(metric_ps, "RoutingReceiver");
     116            0 :         metricMan->do_start();
     117            0 :         if (print_verbose && verbose_clear_screen)
     118              :         {
     119            0 :                 std::cout << "\033[2J";
     120              :         }
     121              : 
     122            0 :         std::map<int, int> receiver_table = std::map<int, int>();
     123              : 
     124            0 :         while (!should_stop)
     125              :         {
     126            0 :                 auto start_time = std::chrono::steady_clock::now();
     127              : 
     128            0 :                 auto this_table = rr.GetAndClearRoutingTable();
     129              : 
     130            0 :                 if (!this_table.empty())
     131              :                 {
     132            0 :                         auto graph_width = this_table.size();
     133            0 :                         auto n = 1;  // n becomes entries per graph character
     134            0 :                         auto graph_width_orig = graph_width;
     135            0 :                         while (graph_width > max_graph_width)
     136              :                         {
     137            0 :                                 n++;
     138            0 :                                 graph_width = graph_width_orig / n;
     139              :                         }
     140              : 
     141            0 :                         for (auto& entry : this_table)
     142              :                         {
     143            0 :                                 receiver_table[entry.second]++;
     144              :                         }
     145              : 
     146            0 :                         auto average_entries_per_receiver = this_table.size() / receiver_table.size();
     147            0 :                         auto offset = 2 * n;  // Offset is 2 characters, in entries
     148              : 
     149            0 :                         auto cyan_threshold = ((average_entries_per_receiver - offset) / 2) / n;
     150            0 :                         auto green_threshold = (average_entries_per_receiver - offset) / n;
     151            0 :                         auto yellow_threshold = (average_entries_per_receiver + offset) / n;
     152            0 :                         auto red_threshold = (2 * average_entries_per_receiver) / n;
     153              : 
     154            0 :                         TLOG(TLVL_TRACE) << "CT: " << cyan_threshold << ", GT: " << green_threshold << ", YT: " << yellow_threshold << ", RT: " << red_threshold;
     155              : 
     156            0 :                         std::ostringstream report;
     157            0 :                         std::ostringstream verbose_report;
     158              : 
     159            0 :                         if (print_verbose && verbose_clear_screen)
     160              :                         {
     161            0 :                                 std::cout << "\033[;H\033[J";
     162              :                         }
     163              : 
     164            0 :                         report << artdaq::TimeUtils::gettimeofday_us() << ": " << this_table.size() << " Entries, ";
     165            0 :                         for (auto& receiver : receiver_table)
     166              :                         {
     167            0 :                                 auto percent = static_cast<int>(receiver.second * 100 / this_table.size());
     168            0 :                                 report << receiver.first << ": " << receiver.second << " (" << percent << "%), ";
     169            0 :                                 if (print_verbose)
     170              :                                 {
     171            0 :                                         verbose_report << receiver.first << ": " << receiver.second << " (" << percent << "%)\t[";
     172              : 
     173            0 :                                         size_t graph_characters = receiver.second / n;
     174              : 
     175            0 :                                         for (size_t ii = 0; ii < graph_characters; ++ii)
     176              :                                         {
     177            0 :                                                 if (ii < cyan_threshold)
     178              :                                                 {
     179            0 :                                                         verbose_report << blue;
     180              :                                                 }
     181            0 :                                                 else if (ii < green_threshold)
     182              :                                                 {
     183            0 :                                                         verbose_report << cyan;
     184              :                                                 }
     185            0 :                                                 else if (ii < yellow_threshold)
     186              :                                                 {
     187            0 :                                                         verbose_report << green;
     188              :                                                 }
     189            0 :                                                 else if (ii < red_threshold)
     190              :                                                 {
     191            0 :                                                         verbose_report << yellow;
     192              :                                                 }
     193              :                                                 else
     194              :                                                 {
     195            0 :                                                         verbose_report << red;
     196              :                                                 }
     197            0 :                                                 verbose_report << "|";
     198              :                                         }
     199            0 :                                         std::string spaces = std::string(graph_width - graph_characters, ' ');
     200            0 :                                         verbose_report << "\033[0m" << spaces << "]" << std::endl;
     201            0 :                                 }
     202            0 :                                 receiver.second = 0;
     203              :                         }
     204            0 :                         TLOG(TLVL_INFO) << report.str();
     205            0 :                         std::cout << report.str() << std::endl;
     206            0 :                         if (print_verbose)
     207              :                         {
     208            0 :                                 std::cout << verbose_report.str() << std::endl;
     209              :                         }
     210            0 :                 }
     211            0 :                 std::this_thread::sleep_until(start_time + std::chrono::milliseconds(collection_time_ms));
     212            0 :         }
     213              : 
     214            0 :         metricMan->do_stop();
     215            0 :         artdaq::Globals::CleanUpGlobals();
     216              : 
     217            0 :         return 0;
     218            0 : }
     219            0 : catch (...)
     220              : {
     221            0 :         return -1;
     222            0 : }
        

Generated by: LCOV version 2.0-1