Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-10-25 09:57:43

0001 // -*- C++ -*-
0002 //
0003 // Package:     PerfTools/AllocMonitor
0004 // Class  :     PeriodicAllocMonitor
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author:  Christopher Jones
0010 //         Created:  Fri, 15 Sep 2023 14:44:38 GMT
0011 //
0012 
0013 // system include files
0014 #include <thread>
0015 #include <chrono>
0016 #include <fstream>
0017 
0018 // user include files
0019 #include "PerfTools/AllocMonitor/interface/AllocMonitorBase.h"
0020 #include "PerfTools/AllocMonitor/interface/AllocMonitorRegistry.h"
0021 #include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
0022 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0023 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0024 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0025 #include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
0026 
0027 namespace {
0028   class MonitorAdaptor : public cms::perftools::AllocMonitorBase {
0029   public:
0030     struct Report {
0031       size_t requested_;
0032       size_t presentActual_;
0033       size_t maxActual_;
0034       size_t nAllocations_;
0035       size_t nDeallocations_;
0036       size_t maxSingleRequested_;
0037     };
0038     Report report() const {
0039       Report report;
0040       report.requested_ = requested_.load(std::memory_order_acquire);
0041       report.maxActual_ = maxActual_.load(std::memory_order_acquire);
0042       report.presentActual_ = presentActual_.load(std::memory_order_acquire);
0043       report.nAllocations_ = nAllocations_.load(std::memory_order_acquire);
0044       report.nDeallocations_ = nDeallocations_.load(std::memory_order_acquire);
0045       report.maxSingleRequested_ = maxSingleRequested_.load(std::memory_order_acquire);
0046 
0047       return report;
0048     }
0049 
0050   private:
0051     void allocCalled(size_t iRequested, size_t iActual) final {
0052       nAllocations_.fetch_add(1, std::memory_order_acq_rel);
0053       requested_.fetch_add(iRequested, std::memory_order_acq_rel);
0054 
0055       //returns previous value
0056       auto a = presentActual_.fetch_add(iActual, std::memory_order_acq_rel);
0057       a += iActual;
0058 
0059       auto max = maxActual_.load(std::memory_order_relaxed);
0060       while (a > max) {
0061         if (maxActual_.compare_exchange_strong(max, a, std::memory_order_acq_rel)) {
0062           break;
0063         }
0064       }
0065 
0066       auto single = maxSingleRequested_.load(std::memory_order_relaxed);
0067       while (iRequested > single) {
0068         if (maxSingleRequested_.compare_exchange_strong(single, iRequested, std::memory_order_acq_rel)) {
0069           break;
0070         }
0071       }
0072     }
0073     void deallocCalled(size_t iActual) final {
0074       if (0 == iActual)
0075         return;
0076       nDeallocations_.fetch_add(1, std::memory_order_acq_rel);
0077       auto present = presentActual_.load(std::memory_order_acquire);
0078       if (present >= iActual) {
0079         presentActual_.fetch_sub(iActual, std::memory_order_acq_rel);
0080       }
0081     }
0082 
0083     std::atomic<size_t> requested_ = 0;
0084     std::atomic<size_t> presentActual_ = 0;
0085     std::atomic<size_t> maxActual_ = 0;
0086     std::atomic<size_t> nAllocations_ = 0;
0087     std::atomic<size_t> nDeallocations_ = 0;
0088     std::atomic<size_t> maxSingleRequested_ = 0;
0089   };
0090 
0091 }  // namespace
0092 
0093 class PeriodicAllocMonitor {
0094 public:
0095   PeriodicAllocMonitor(edm::ParameterSet const& iPS, edm::ActivityRegistry& iAR) {
0096     auto adaptor = cms::perftools::AllocMonitorRegistry::instance().createAndRegisterMonitor<MonitorAdaptor>();
0097     auto fileName = iPS.getUntrackedParameter<std::string>("filename");
0098     auto interval = iPS.getUntrackedParameter<unsigned long long>("millisecondsPerMeasurement");
0099 
0100     threadShutDown_ = false;
0101     thread_ = std::thread([this, fileName, interval, adaptor]() {
0102       auto const start = std::chrono::steady_clock::now();
0103       std::ofstream fs(fileName);
0104       fs << "timestamp, runs-started, lumis-started, events-started, events-finished, total-requested, max-actual, "
0105             "present-actual, max-single, nAllocs, nDeallocs\n";
0106       while (continueRunning_.load()) {
0107         auto rStarted = nRunsStarted_.load(std::memory_order_acquire);
0108         auto lStarted = nLumisStarted_.load(std::memory_order_acquire);
0109         auto const now = std::chrono::steady_clock::now();
0110         auto eStarted = nEventsStarted_.load(std::memory_order_acquire);
0111         auto eFinished = nEventsFinished_.load(std::memory_order_acquire);
0112         auto report = adaptor->report();
0113 
0114         fs << std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count() << ", " << rStarted << ", "
0115            << lStarted << ", " << eStarted << ", " << eFinished << ", " << report.requested_ << ", "
0116            << report.maxActual_ << ", " << report.presentActual_ << ", " << report.maxSingleRequested_ << ", "
0117            << report.nAllocations_ << ", " << report.nDeallocations_ << std::endl;
0118         std::this_thread::sleep_for(std::chrono::milliseconds(interval));
0119       }
0120     });
0121 
0122     iAR.watchPreEvent([this](auto const&) { nEventsStarted_.fetch_add(1, std::memory_order_acq_rel); });
0123     iAR.watchPostEvent([this](auto const&) { nEventsFinished_.fetch_add(1, std::memory_order_acq_rel); });
0124     iAR.watchPreGlobalBeginRun([this](auto const&) { nRunsStarted_.fetch_add(1, std::memory_order_acq_rel); });
0125     iAR.watchPreGlobalBeginLumi([this](auto const&) { nLumisStarted_.fetch_add(1, std::memory_order_acq_rel); });
0126     iAR.watchPreEndJob([adaptor, this]() {
0127       continueRunning_ = false;
0128       thread_.join();
0129       threadShutDown_ = true;
0130       cms::perftools::AllocMonitorRegistry::instance().deregisterMonitor(adaptor);
0131     });
0132   }
0133   ~PeriodicAllocMonitor() {
0134     if (not threadShutDown_) {
0135       continueRunning_ = false;
0136       thread_.join();
0137     }
0138   }
0139 
0140   static void fillDescriptions(edm::ConfigurationDescriptions& iDesc) {
0141     edm::ParameterSetDescription ps;
0142     ps.addUntracked<std::string>("filename", "timing.log")->setComment("Name of file to write the reports");
0143     ps.addUntracked<unsigned long long>("millisecondsPerMeasurement", 1000)
0144         ->setComment("The frequency at which to write reports");
0145     iDesc.addDefault(ps);
0146   }
0147 
0148 private:
0149   std::thread thread_;
0150   std::atomic<std::size_t> nRunsStarted_ = 0;
0151   std::atomic<std::size_t> nLumisStarted_ = 0;
0152   std::atomic<std::size_t> nEventsStarted_ = 0;
0153   std::atomic<std::size_t> nEventsFinished_ = 0;
0154   std::atomic<bool> continueRunning_ = true;
0155   bool threadShutDown_ = true;
0156 };
0157 
0158 DEFINE_FWK_SERVICE(PeriodicAllocMonitor);