ATLAS Offline Software
MemStatsHooks.cxx
Go to the documentation of this file.
1 
3 /*
4  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
5 */
6 
7 // MemStatsHooks.cxx
8 // Implementation file for PerfMon memory snooping
9 // Author: S.Binet<binet@cern.ch>
11 
12 // PerfMonEvent includes
15 
16 #include "CxxUtils/features.h"
17 
18 // std includes
19 #include <pthread.h>
20 #include <stdexcept>
21 
22 // mutex for the hooks
23 static pthread_mutex_t pmon_mem_lock ATLAS_THREAD_SAFE = PTHREAD_MUTEX_INITIALIZER;
24 
25 #if HAVE_MALLOC_HOOKS
26 // holders for original hooks (locked by above mutex)
27 static void* (*orig_malloc ATLAS_THREAD_SAFE) (size_t size, const void* caller);
28 static void* (*orig_realloc ATLAS_THREAD_SAFE)(void* ptr, size_t size, const void* caller);
29 static void (*orig_free ATLAS_THREAD_SAFE) (void* ptr, const void* caller);
30 
31 // perfmon memory monitoring hooks
32 static void* pmon_mem_malloc (size_t size, const void* caller);
33 static void* pmon_mem_realloc(void* ptr, size_t size, const void* caller);
34 static void pmon_mem_free (void* ptr, const void* caller);
35 #endif
36 
38 std::atomic<bool> PerfMon::MemStats::m_enabled = false;
39 unsigned long long PerfMon::MemStats::m_nbytes = 0;
40 unsigned long long PerfMon::MemStats::m_nmallocs = 0;
41 unsigned long long PerfMon::MemStats::m_nfrees = 0;
42 
43 #include <limits>
44 #include <iostream>
45 
46 #ifdef __APPLE__
47 
48 // Dummy code for time being
54 static void* pmon_mem_malloc(size_t size, const void* /*caller*/)
55 { return malloc(size); }
56 static void* pmon_mem_realloc(void* ptr, size_t size, const void* /*caller*/)
57 { return realloc(ptr, size); }
58 static void pmon_mem_free( void* ptr, const void* /*caller*/ )
59 { free(ptr); }
60 
61 #else /* __linux__ */
62 
63 
64 #ifdef __GNUC__
65 # pragma GCC diagnostic push
66 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
67 #endif
68 
69 
71 {
72  if (0 != pthread_mutex_init(&pmon_mem_lock, NULL)) {
73  throw std::runtime_error("perfmon: could not initialize pthread mutex");
74  }
75  pthread_mutex_lock(&pmon_mem_lock);
76  saveHooks();
78  installHooks();
79  } else {
80  // installHooks unlocks the mutex...
81  pthread_mutex_unlock(&pmon_mem_lock);
82  }
83 }
84 
86 {
87  // we actually don't want to ever un-install the hooks as
88  // this might break daisy chains of hooks: if our hooks were installed first
89  // uninstalling them will put the NULL ones back in, and won't give a chance
90  // for later-registered hooks to do their properly afterwards.
91 
92  // if (PerfMon::MemStats::m_enabled) {
93  // uninstallHooks();
94  // }
95  if (0 != pthread_mutex_destroy(&pmon_mem_lock)) {
96  throw std::runtime_error("perfmon: could not destroy pthread mutex");
97  }
98 }
99 
101 {
102 #if HAVE_MALLOC_HOOKS
103  __free_hook = pmon_mem_free;
104  __realloc_hook = pmon_mem_realloc;
105  __malloc_hook = pmon_mem_malloc;
106 #endif
107  pthread_mutex_unlock(&pmon_mem_lock);
108 }
109 
111 {
112  pthread_mutex_lock(&pmon_mem_lock);
113 #if HAVE_MALLOC_HOOKS
114  __free_hook = orig_free;
115  __realloc_hook = orig_realloc;
116  __malloc_hook = orig_malloc;
117 #endif
118 }
119 
121 {
122 #if HAVE_MALLOC_HOOKS
123  // store old hooks in buffer for reset later
124  // prevent storing ourselves in case of a double-call by user
125  if ( __malloc_hook != pmon_mem_malloc ) {
126  orig_malloc = __malloc_hook;
127  }
128 
129  if ( __realloc_hook != pmon_mem_realloc ) {
130  orig_realloc = __realloc_hook;
131  }
132 
133  if ( __free_hook != pmon_mem_free ) {
134  orig_free = __free_hook;
135  }
136 #endif
137 
138  return;
139 }
140 
141 
142 #if HAVE_MALLOC_HOOKS
143 static void* pmon_mem_malloc(size_t size, const void* /*caller*/)
144 {
145  void *result;
146 
147  // reset (system/NULL) hook to prevent recursion
149 
150  // let malloc do its thing
151  result = malloc( size );
152 
153  // update MemStats state
154  PerfMon::MemStats::m_nbytes += size;
155  PerfMon::MemStats::m_nmallocs += 1;
156 
157  // store current hooks
159 
160  // reset hooks to our ones
162 
163  return result;
164 }
165 
166 static void* pmon_mem_realloc(void* ptr, size_t size, const void* /*caller*/)
167 {
168  void *result;
169 
170  // reset (system/NULL) hook to prevent recursion
172 
173  // let realloc do its thing
174  result = realloc( ptr, size );
175 
176  // update MemStats state
177  PerfMon::MemStats::m_nbytes += size;
178  PerfMon::MemStats::m_nmallocs += 1;
179 
180  // store current hooks
182 
183  // reset our hooks
185 
186  return result;
187 }
188 
189 static void pmon_mem_free( void* ptr, const void* /*caller*/ )
190 {
191  // reset (system/NULL) hook to prevent recursion
193 
194  // let free do its thing
195  free( ptr );
196 
197  // update counter
198  PerfMon::MemStats::m_nfrees += 1;
199 
200  // store current hooks
202 
203  // reset our hooks
205 
206  return;
207 }
208 #endif
209 
210 #endif /* __linux__ */
211 
features.h
Some additional feature test macros.
get_generator_info.result
result
Definition: get_generator_info.py:21
PerfMon::MemStats::uninstallHooks
static void uninstallHooks()
uninstall our hooks
Definition: MemStatsHooks.cxx:110
PerfMon::MemStats::saveHooks
static void saveHooks()
save current hooks
Definition: MemStatsHooks.cxx:120
python.setupRTTAlg.size
int size
Definition: setupRTTAlg.py:39
TrigInDetValidation_Base.malloc
malloc
Definition: TrigInDetValidation_Base.py:131
PerfMon::MemStats::start
static void start()
initialize library
Definition: MemStatsHooks.cxx:70
PerfMon::MemStats::stop
static void stop()
finalize library
Definition: MemStatsHooks.cxx:85
PerfMon::MemStats::m_enabled
static std::atomic< bool > m_enabled
flag disabling or enabling the global malloc hooks
Definition: MemStatsHooks.h:35
MemStatsHooks.h
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
checker_macros.h
Define macros for attributes used to control the static checker.
PerfMon::MemStats::installHooks
static void installHooks()
install our hooks
Definition: MemStatsHooks.cxx:100