Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-06-13 03:23:57

0001 // -*- C++ -*-
0002 //
0003 // Package:     PerfTools/AllocMonitor
0004 // Class  :     AllocMonitorRegistry
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author:  Christopher Jones
0010 //         Created:  Mon, 21 Aug 2023 15:42:48 GMT
0011 //
0012 
0013 // system include files
0014 #include <dlfcn.h>  // dlsym
0015 
0016 // user include files
0017 #include "PerfTools/AllocMonitor/interface/AllocMonitorRegistry.h"
0018 #include "FWCore/Utilities/interface/Exception.h"
0019 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0020 
0021 //
0022 // constants, enums and typedefs
0023 //
0024 extern "C" {
0025 void alloc_monitor_start();
0026 void alloc_monitor_stop();
0027 bool alloc_monitor_stop_thread_reporting();
0028 void alloc_monitor_start_thread_reporting();
0029 }
0030 
0031 namespace {
0032   bool& dummyThreadReportingFcn() {
0033     static thread_local bool s_running = true;
0034     return s_running;
0035   }
0036 
0037   bool dummyStopThreadReportingFcn() {
0038     auto& t = dummyThreadReportingFcn();
0039     auto last = t;
0040     t = false;
0041     return last;
0042   }
0043 
0044   void dummyStartThreadReportingFcn() { dummyThreadReportingFcn() = true; }
0045 
0046   bool stopThreadReporting() {
0047     static decltype(&::alloc_monitor_stop_thread_reporting) s_fcn = []() {
0048       void* fcn = dlsym(RTLD_DEFAULT, "alloc_monitor_stop_thread_reporting");
0049       if (fcn != nullptr) {
0050         return reinterpret_cast<decltype(&::alloc_monitor_stop_thread_reporting)>(fcn);
0051       }
0052       //this should only be called for testing;
0053       return &::dummyStopThreadReportingFcn;
0054     }();
0055     return s_fcn();
0056   }
0057 
0058   void startThreadReporting() {
0059     static decltype(&::alloc_monitor_start_thread_reporting) s_fcn = []() {
0060       void* fcn = dlsym(RTLD_DEFAULT, "alloc_monitor_start_thread_reporting");
0061       if (fcn != nullptr) {
0062         return reinterpret_cast<decltype(&::alloc_monitor_start_thread_reporting)>(fcn);
0063       }
0064       //this should only be called for testing;
0065       return &::dummyStartThreadReportingFcn;
0066     }();
0067     s_fcn();
0068   }
0069 }  // namespace
0070 
0071 using namespace cms::perftools;
0072 
0073 //
0074 // static data member definitions
0075 //
0076 
0077 //
0078 // constructors and destructor
0079 //
0080 AllocMonitorRegistry::AllocMonitorRegistry() {
0081   //Cannot start here because statics can cause memory to be allocated in the atexit registration
0082   // done behind the scenes. If the allocation happens, AllocMonitorRegistry::instance will be called
0083   // recursively before the static has finished and we well deadlock
0084   startReporting();
0085 }
0086 
0087 AllocMonitorRegistry::~AllocMonitorRegistry() {
0088   void* stop = dlsym(RTLD_DEFAULT, "alloc_monitor_stop");
0089   if (stop != nullptr) {
0090     auto s = reinterpret_cast<decltype(&::alloc_monitor_stop)>(stop);
0091     s();
0092   }
0093   stopReporting();
0094   monitors_.clear();
0095 }
0096 
0097 //
0098 // member functions
0099 //
0100 bool AllocMonitorRegistry::necessaryLibraryWasPreloaded() {
0101   return dlsym(RTLD_DEFAULT, "alloc_monitor_start") != nullptr;
0102 }
0103 
0104 void AllocMonitorRegistry::start() {
0105   if (monitors_.empty()) {
0106     void* start = dlsym(RTLD_DEFAULT, "alloc_monitor_start");
0107     if (start == nullptr) {
0108       throw cms::Exception("NoAllocMonitorPreload")
0109           << "The libPerfToolsAllocMonitorPreload.so was not LD_PRELOADed into the job";
0110     }
0111     auto s = reinterpret_cast<decltype(&::alloc_monitor_start)>(start);
0112     s();
0113   }
0114 }
0115 
0116 bool AllocMonitorRegistry::stopReporting() { return stopThreadReporting(); }
0117 void AllocMonitorRegistry::startReporting() { startThreadReporting(); }
0118 
0119 void AllocMonitorRegistry::deregisterMonitor(AllocMonitorBase* iMonitor) {
0120   for (auto it = monitors_.begin(); monitors_.end() != it; ++it) {
0121     if (it->get() == iMonitor) {
0122       [[maybe_unused]] Guard g = makeGuard();
0123       monitors_.erase(it);
0124       break;
0125     }
0126   }
0127 }
0128 
0129 //
0130 // const member functions
0131 //
0132 void AllocMonitorRegistry::allocCalled_(size_t iRequested, size_t iActual) {
0133   for (auto& m : monitors_) {
0134     m->allocCalled(iRequested, iActual);
0135   }
0136 }
0137 void AllocMonitorRegistry::deallocCalled_(size_t iActual) {
0138   for (auto& m : monitors_) {
0139     m->deallocCalled(iActual);
0140   }
0141 }
0142 
0143 //
0144 // static member functions
0145 //
0146 AllocMonitorRegistry& AllocMonitorRegistry::instance() {
0147   //The thread unsafe methods are marked as unsafe
0148   CMS_SA_ALLOW static AllocMonitorRegistry s_registry;
0149   return s_registry;
0150 }