CMS 3D CMS Logo

AllocMonitorRegistry.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: PerfTools/AllocMonitor
4 // Class : AllocMonitorRegistry
5 //
6 // Implementation:
7 // [Notes on implementation]
8 //
9 // Original Author: Christopher Jones
10 // Created: Mon, 21 Aug 2023 15:42:48 GMT
11 //
12 
13 // system include files
14 #include <dlfcn.h> // dlsym
15 
16 // user include files
20 
21 //
22 // constants, enums and typedefs
23 //
24 extern "C" {
25 void alloc_monitor_start();
26 void alloc_monitor_stop();
29 }
30 
31 namespace {
32  bool& dummyThreadReportingFcn() {
33  static thread_local bool s_running = true;
34  return s_running;
35  }
36 
37  bool dummyStopThreadReportingFcn() {
38  auto& t = dummyThreadReportingFcn();
39  auto last = t;
40  t = false;
41  return last;
42  }
43 
44  void dummyStartThreadReportingFcn() { dummyThreadReportingFcn() = true; }
45 
46  bool stopThreadReporting() {
47  static decltype(&::alloc_monitor_stop_thread_reporting) s_fcn = []() {
48  void* fcn = dlsym(RTLD_DEFAULT, "alloc_monitor_stop_thread_reporting");
49  if (fcn != nullptr) {
50  return reinterpret_cast<decltype(&::alloc_monitor_stop_thread_reporting)>(fcn);
51  }
52  //this should only be called for testing;
53  return &::dummyStopThreadReportingFcn;
54  }();
55  return s_fcn();
56  }
57 
58  void startThreadReporting() {
59  static decltype(&::alloc_monitor_start_thread_reporting) s_fcn = []() {
60  void* fcn = dlsym(RTLD_DEFAULT, "alloc_monitor_start_thread_reporting");
61  if (fcn != nullptr) {
62  return reinterpret_cast<decltype(&::alloc_monitor_start_thread_reporting)>(fcn);
63  }
64  //this should only be called for testing;
65  return &::dummyStartThreadReportingFcn;
66  }();
67  s_fcn();
68  }
69 } // namespace
70 
71 using namespace cms::perftools;
72 
73 //
74 // static data member definitions
75 //
76 
77 //
78 // constructors and destructor
79 //
81  //Cannot start here because statics can cause memory to be allocated in the atexit registration
82  // done behind the scenes. If the allocation happens, AllocMonitorRegistry::instance will be called
83  // recursively before the static has finished and we well deadlock
85 }
86 
88  void* stop = dlsym(RTLD_DEFAULT, "alloc_monitor_stop");
89  if (stop != nullptr) {
90  auto s = reinterpret_cast<decltype(&::alloc_monitor_stop)>(stop);
91  s();
92  }
93  stopReporting();
94  monitors_.clear();
95 }
96 
97 //
98 // member functions
99 //
101  return dlsym(RTLD_DEFAULT, "alloc_monitor_start") != nullptr;
102 }
103 
105  if (monitors_.empty()) {
106  void* start = dlsym(RTLD_DEFAULT, "alloc_monitor_start");
107  if (start == nullptr) {
108  throw cms::Exception("NoAllocMonitorPreload")
109  << "The libPerfToolsAllocMonitorPreload.so was not LD_PRELOADed into the job";
110  }
111  auto s = reinterpret_cast<decltype(&::alloc_monitor_start)>(start);
112  s();
113  }
114 }
115 
116 bool AllocMonitorRegistry::stopReporting() { return stopThreadReporting(); }
117 void AllocMonitorRegistry::startReporting() { startThreadReporting(); }
118 
120  for (auto it = monitors_.begin(); monitors_.end() != it; ++it) {
121  if (it->get() == iMonitor) {
122  [[maybe_unused]] Guard g = makeGuard();
123  monitors_.erase(it);
124  break;
125  }
126  }
127 }
128 
129 //
130 // const member functions
131 //
132 void AllocMonitorRegistry::allocCalled_(size_t iRequested, size_t iActual, void const* iPtr) {
133  for (auto& m : monitors_) {
134  m->allocCalled(iRequested, iActual, iPtr);
135  }
136 }
137 void AllocMonitorRegistry::deallocCalled_(size_t iActual, void const* iPtr) {
138  for (auto& m : monitors_) {
139  m->deallocCalled(iActual, iPtr);
140  }
141 }
142 
143 //
144 // static member functions
145 //
147  //The thread unsafe methods are marked as unsafe
148  CMS_SA_ALLOW static AllocMonitorRegistry s_registry;
149  return s_registry;
150 }
Definition: start.py:1
void allocCalled_(size_t, size_t, void const *)
#define CMS_SA_ALLOW
void deallocCalled_(size_t, void const *)
bool alloc_monitor_stop_thread_reporting()
void alloc_monitor_stop()
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
static AllocMonitorRegistry & instance()
void alloc_monitor_start_thread_reporting()
std::vector< std::unique_ptr< AllocMonitorBase > > monitors_
void fcn(int &, double *, double &, double *, int)
void alloc_monitor_start()