ThroughputServiceClient

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
// C++ headers
#include <string>
#include <cstring>

// boost headers
#include <boost/regex.hpp>

// Root headers
#include <TH1F.h>

// CMSSW headers
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/Run.h"
#include "FWCore/Framework/interface/LuminosityBlock.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/Registry.h"
#include "FWCore/ServiceRegistry/interface/Service.h"
#include "DataFormats/Provenance/interface/ProcessHistory.h"
#include "DQMServices/Core/interface/DQMStore.h"
#include "DQMServices/Core/interface/DQMEDHarvester.h"

class ThroughputServiceClient : public DQMEDHarvester {
public:
  explicit ThroughputServiceClient(edm::ParameterSet const &);
  ~ThroughputServiceClient() override = default;

  static void fillDescriptions(edm::ConfigurationDescriptions &descriptions);

private:
  const std::string m_dqm_path;
  const bool m_dqm_merge;
  const bool m_fillEveryLumiSection;

  void dqmEndLuminosityBlock(DQMStore::IBooker &booker,
                             DQMStore::IGetter &getter,
                             edm::LuminosityBlock const &,
                             edm::EventSetup const &) override;
  void dqmEndJob(DQMStore::IBooker &booker, DQMStore::IGetter &getter) override;

private:
  void fillSummaryPlots(DQMStore::IBooker &booker, DQMStore::IGetter &getter);
};

ThroughputServiceClient::ThroughputServiceClient(edm::ParameterSet const &config)
    : m_dqm_path(config.getUntrackedParameter<std::string>("dqmPath")),
      m_dqm_merge(config.getUntrackedParameter<bool>("createSummary")),
      m_fillEveryLumiSection(config.getParameter<bool>("fillEveryLumiSection")) {}

void ThroughputServiceClient::dqmEndJob(DQMStore::IBooker &booker, DQMStore::IGetter &getter) {
  fillSummaryPlots(booker, getter);
}

void ThroughputServiceClient::dqmEndLuminosityBlock(DQMStore::IBooker &booker,
                                                    DQMStore::IGetter &getter,
                                                    edm::LuminosityBlock const &,
                                                    edm::EventSetup const &) {
  if (m_fillEveryLumiSection) {
    fillSummaryPlots(booker, getter);
  }
}

void ThroughputServiceClient::fillSummaryPlots(DQMStore::IBooker &booker, DQMStore::IGetter &getter) {
  // find whether the plots are in the main folder, or in per-number-of-processess subfolders
  std::vector<std::string> folders;
  if (getter.get(m_dqm_path + "/throughput_sourced")) {
    // the plots are in the main folder
    folders.push_back(m_dqm_path);
  } else {
    static const boost::regex running_n_processes(".*/Running .*");
    booker.setCurrentFolder(m_dqm_path);
    std::vector<std::string> subdirs = getter.getSubdirs();
    for (auto const &subdir : subdirs) {
      if (boost::regex_match(subdir, running_n_processes)) {
        if (getter.get(subdir + "/throughput_sourced")) {
          // the plots are in a per-number-of-processes subfolder
          folders.push_back(subdir);
        }
      }
    }
  }
  // create a summary folder if there are more than one
  if (m_dqm_merge and folders.size() > 1) {
    std::string summary_folder = m_dqm_path + "/Summary";
    booker.setCurrentFolder(summary_folder);
    // clone the first set of histograms
    auto folder = folders.begin();
    TH1F *sourced =
        booker.book1D("throughput_sourced", getter.get(*folder + "/throughput_sourced")->getTH1F())->getTH1F();
    TH1F *retired =
        booker.book1D("throughput_retired", getter.get(*folder + "/throughput_retired")->getTH1F())->getTH1F();
    // add the other sets of histograms
    for (++folder; folder != folders.end(); ++folder) {
      sourced->Add(getter.get(*folder + "/throughput_sourced")->getTH1F());
      retired->Add(getter.get(*folder + "/throughput_retired")->getTH1F());
    }
    // move the summary folder to the list
    folders.push_back(std::move(summary_folder));
  }
  for (auto const &folder : folders) {
    TH1F *sourced = getter.get(folder + "/throughput_sourced")->getTH1F();
    TH1F *retired = getter.get(folder + "/throughput_retired")->getTH1F();
    booker.setCurrentFolder(folder);
    unsigned int nbins = sourced->GetXaxis()->GetNbins();
    double range = sourced->GetXaxis()->GetXmax();

    // (re)book and fill .../concurrent
    TH1F *concurrent = booker.book1D("concurrent", "Concurrent events being processed", nbins, 0., range)->getTH1F();
    double sum = 0;
    // from bin=0 (underflow) to bin=nbins+1 (overflow)
    for (unsigned int i = 0; i <= nbins + 1; ++i) {
      sum += sourced->GetBinContent(i) - retired->GetBinContent(i);
      concurrent->Fill(concurrent->GetXaxis()->GetBinCenter(i), sum);
    }

    TH1F *average = nullptr;
    double avg_min = std::min(sourced->GetMinimum(0.), retired->GetMinimum(0.));
    double avg_max = std::max(sourced->GetMaximum(), retired->GetMaximum());
    double width = avg_max - avg_min;
    avg_min = std::floor(avg_min - width * 0.2);
    if (avg_min < 0.)
      avg_min = 0.;
    avg_max = std::ceil(avg_max + width * 0.2);
    width = avg_max - avg_min;

    // define the range for .../average_sourced
    auto first = sourced->FindFirstBinAbove(0.);
    auto last = sourced->FindLastBinAbove(0.);
    booker.setCurrentFolder(folder);
    // (re)book and fill .../average_sourced
    average = booker.book1D("average_sourced", "Throughput (sourced events)", (int)width, avg_min, avg_max)->getTH1F();
    if (first >= 0)
      for (auto i = first; i <= last; ++i)
        average->Fill(sourced->GetBinContent(i));

    // define the range for .../average_retired
    first = retired->FindFirstBinAbove(0.);
    last = retired->FindLastBinAbove(0.);
    booker.setCurrentFolder(folder);
    // (re)book and fill .../average_retired
    average = booker.book1D("average_retired", "Throughput (retired events)", (int)width, avg_min, avg_max)->getTH1F();
    if (first >= 0)
      for (auto i = first; i <= last; ++i)
        average->Fill(retired->GetBinContent(i));
  }
}

void ThroughputServiceClient::fillDescriptions(edm::ConfigurationDescriptions &descriptions) {
  edm::ParameterSetDescription desc;
  desc.addUntracked<std::string>("dqmPath", "HLT/Throughput");
  desc.addUntracked<bool>("createSummary", true);
  desc.add<bool>("fillEveryLumiSection", true);
  descriptions.add("throughputServiceClient", desc);
}

// declare this class as a framework plugin
#include "FWCore/Framework/interface/MakerMacros.h"
DEFINE_FWK_MODULE(ThroughputServiceClient);