The Gaudi Framework  master (37c0b60a)
IgHook_IgHookTrace.cpp
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2019 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 //<<<<<< INCLUDES >>>>>>
12 
13 #include "IgHook_IgHookTrace.h"
14 #include <cstdio>
15 #include <cstdlib>
16 #include <dlfcn.h>
17 #include <sys/mman.h>
18 #include <unistd.h>
19 #if __linux
20 # include <execinfo.h>
21 # include <sys/syscall.h>
22 # include <ucontext.h>
23 # if __x86_64__
24 # define UNW_LOCAL_ONLY
25 # include <libunwind.h>
26 # endif
27 #endif
28 #if __APPLE__
29 extern "C" void _sigtramp( void );
30 #endif
31 
32 //<<<<<< PRIVATE DEFINES >>>>>>
33 
34 #if !defined MAP_ANONYMOUS && defined MAP_ANON
35 # define MAP_ANONYMOUS MAP_ANON
36 #endif
37 
38 //<<<<<< PRIVATE CONSTANTS >>>>>>
39 //<<<<<< PRIVATE TYPES >>>>>>
40 //<<<<<< PRIVATE VARIABLE DEFINITIONS >>>>>>
41 //<<<<<< PUBLIC VARIABLE DEFINITIONS >>>>>>
42 //<<<<<< CLASS STRUCTURE INITIALIZATION >>>>>>
43 //<<<<<< PRIVATE FUNCTION DEFINITIONS >>>>>>
44 
45 #if 0 && __x86_64__ && __linux
46 // Linux x86-64 does not use regular call frames, like IA-32 does for
47 // example, and it would be a very difficult job to decipher the call
48 // stack. In order to walk the call stack correctly, we have to use
49 // the DWARF-2 unwind data. This alone is incredibly, uselessly slow
50 // for our purposes.
51 //
52 // We avoid using the unwind data by caching frame structures for
53 // recently seen functions. This is slow to start with, but very
54 // quickly gets fast enough for our purposes. Fortunately the x86-64
55 // unwind library appears to be robust enough to be called in signal
56 // handlers (unlike at least some IA-32 versions).
57 //
58 // The cache consists of two arrays arranged as an open-addressed
59 // unprobed hash table. Hash collisions overwrite the entry with the
60 // latest data. We try to avoid making this a problem by using a
61 // high-quality hash function and pure brute force in the form of a
62 // large hash table. A couple of megabytes goes a long way to help!
63 //
64 // The first of the cache arrays, of "void *", tracks program counter
65 // addresses. A parallel array of "int" tracks the size of the call
66 // frame at that address. Given a program counter and the canonical
67 // frame address (CFA) of the previous (= above) call frame, the new
68 // frame address is the previous plus the delta. We find the address
69 // of the caller just above this new frame address.
70 //
71 // We use the cache as long as we can find the addresses there. When
72 // we fall off the cache, we resort to the language run time unwinder.
73 
74 struct IgHookTraceArgs
75 {
76  struct
77  {
78  void **pc;
79  int **frame;
80  } cache;
81  struct
82  {
83  void **addresses;
84  int top;
85  int size;
86  } stack;
87  void **prevframe;
88 };
89 
90 static _Unwind_Reason_Code
91 GCCBackTrace (_Unwind_Context *context, void *arg)
92 {
93  IgHookTraceArgs *args = (IgHookTraceArgs *) arg;
94  if (args->stack.top < 0 || args->stack.top >= args->stack.size)
95  return _URC_END_OF_STACK;
96 
97  args->stack.addresses [args->stack.top++] = (void *) _Unwind_GetIP (context);
98  args->prevframe = (void **) _Unwind_GetCFA (context);
99  return _URC_NO_REASON;
100 }
101 #endif
102 
103 //<<<<<< PUBLIC FUNCTION DEFINITIONS >>>>>>
104 //<<<<<< MEMBER FUNCTION DEFINITIONS >>>>>>
105 
109 IgHookTraceAlloc::IgHookTraceAlloc( void ) : m_pool( 0 ), m_left( 0 ) {}
110 
111 void* IgHookTraceAlloc::allocate( size_t bytes ) {
112  // The reason for the existence of this class is to allocate
113  // memory directly using mmap() so we don't create calls to
114  // malloc() and friends. This is for two reasons: it must be
115  // possible to use this in asynchronous signal handlers, and
116  // calling malloc() in those is a really bad idea; and this is
117  // meant to be used by profiling code and it's nicer to not
118  // allocate memory in ways tracked by the profiler.
119  if ( m_left < bytes ) {
120  size_t psize = getpagesize();
121  size_t hunk = psize * 20;
122  if ( hunk < bytes ) hunk = ( hunk + psize - 1 ) & ~( psize - 1 );
123  void* addr = mmap( 0, hunk, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 );
124  if ( addr == MAP_FAILED ) return 0;
125 
126  m_pool = addr;
127  m_left = hunk;
128  }
129 
130  void* ptr = m_pool;
131  m_pool = (char*)m_pool + bytes;
132  m_left -= bytes;
133  return ptr;
134 }
135 
139 void* IgHookTrace::CounterValue::operator new( size_t n, IgHookTraceAlloc* alloc /* = 0 */ ) {
140  return alloc ? alloc->allocate( n ) : ::operator new( n );
141 }
142 
144  unsigned long long value /* = 0 */ )
145  : m_counter( counter ), m_next( next ), m_value( value ), m_count( 0 ) {}
146 
148 
150 
151 unsigned long long IgHookTrace::CounterValue::value( void ) { return m_value; }
152 
153 unsigned long long IgHookTrace::CounterValue::count( void ) { return m_count; }
154 
155 unsigned long long IgHookTrace::CounterValue::tick( void ) {
156  ++m_count;
157  return ++m_value;
158 }
159 
160 unsigned long long IgHookTrace::CounterValue::untick( void ) {
161  --m_count;
162  return --m_value;
163 }
164 
165 unsigned long long IgHookTrace::CounterValue::add( unsigned long long value ) {
166  ++m_count;
167  return m_value += value;
168 }
169 
170 unsigned long long IgHookTrace::CounterValue::sub( unsigned long long value ) {
171  --m_count;
172  return m_value -= value;
173 }
174 
175 unsigned long long IgHookTrace::CounterValue::max( unsigned long long value ) {
176  ++m_count;
177  if ( m_value < value ) m_value = value;
178  return m_value;
179 }
180 
182  m_count += x.m_count;
183  m_value += x.m_value;
184  return m_value;
185 }
186 
188  m_count -= x.m_count;
189  m_value -= x.m_value;
190  return m_value;
191 }
192 
194  m_count += x.m_count;
195  if ( m_value < x.m_value ) m_value = x.m_value;
196  return m_value;
197 }
198 
202 void* IgHookTrace::operator new( size_t n, IgHookTraceAlloc* alloc /* = 0 */ ) {
203  return alloc ? alloc->allocate( n ) : ::operator new( n );
204 }
205 
206 IgHookTrace::IgHookTrace( IgHookTrace* parent /* = 0 */, void* address /* = 0 */ )
208  , m_parent( parent )
209  , m_next( parent ? parent->m_children : 0 )
210  , m_children( 0 )
211  , m_address( address )
212  , m_counters( 0 ) {
213  if ( m_parent ) m_parent->m_children = this;
214 }
215 
217 
219 
220 void* IgHookTrace::address( void ) { return m_address; }
221 
222 bool IgHookTrace::symbol( void* address, const char*& sym, const char*& lib, int& offset, int& liboffset ) {
223  sym = lib = 0;
224  offset = 0;
225  liboffset = (unsigned long)address;
226 
227  Dl_info info;
228  if ( dladdr( address, &info ) ) {
229  if ( info.dli_fname && info.dli_fname[0] ) lib = info.dli_fname;
230 
231  if ( info.dli_fbase ) liboffset = (unsigned long)address - (unsigned long)info.dli_fbase;
232 
233  if ( info.dli_saddr ) offset = (unsigned long)address - (unsigned long)info.dli_saddr;
234 
235  if ( info.dli_sname && info.dli_sname[0] ) sym = info.dli_sname;
236 
237  return true;
238  }
239 
240  return false;
241 }
242 
243 bool IgHookTrace::symbol( const char*& sym, const char*& lib, int& offset, int& liboffset ) {
244  return symbol( m_address, sym, lib, offset, liboffset );
245 }
246 
247 void* IgHookTrace::tosymbol( void* address ) {
248  Dl_info info;
249  return ( dladdr( address, &info ) && info.dli_fname && info.dli_fname[0] && info.dli_saddr ) ? info.dli_saddr
250  : address;
251 }
IgHookTrace::parent
IgHookTrace * parent(void)
Definition: IgHook_IgHookTrace.cpp:216
IgHookTrace::CounterValue::CounterValue
CounterValue(Counter *counter, CounterValue *next=0, unsigned long long value=0)
Definition: IgHook_IgHookTrace.cpp:143
IgHookTraceAlloc::allocate
void * allocate(size_t bytes)
Definition: IgHook_IgHookTrace.cpp:111
IgHookTraceAlloc
Definition: IgHook_IgHookTrace.h:26
Gaudi::Units::pc
constexpr double pc
Definition: SystemOfUnits.h:116
details::size
constexpr auto size(const T &, Args &&...) noexcept
Definition: AnyDataWrapper.h:23
IgHookTrace::CounterValue::counter
Counter * counter(void)
Definition: IgHook_IgHookTrace.cpp:147
IgHookTrace::CounterValue::max
unsigned long long max(unsigned long long value)
Definition: IgHook_IgHookTrace.cpp:175
IgHookTrace
Definition: IgHook_IgHookTrace.h:37
IgHookTraceAlloc::m_pool
void * m_pool
Definition: IgHook_IgHookTrace.h:33
IgHookTrace::m_next
IgHookTrace * m_next
Definition: IgHook_IgHookTrace.h:102
IgHook_IgHookTrace.h
IgHookTrace::CounterValue::count
unsigned long long count(void)
Definition: IgHook_IgHookTrace.cpp:153
IgHookTrace::m_counters
CounterValue * m_counters
Definition: IgHook_IgHookTrace.h:105
IgHookTrace::m_parent
IgHookTrace * m_parent
Definition: IgHook_IgHookTrace.h:101
IgHookTrace::CounterValue::next
CounterValue * next(void)
Definition: IgHook_IgHookTrace.cpp:149
IgHookTrace::m_children
IgHookTrace * m_children
Definition: IgHook_IgHookTrace.h:103
IgHookTrace::CounterValue::value
unsigned long long value(void)
Definition: IgHook_IgHookTrace.cpp:151
IgHookTrace::CounterValue::sub
unsigned long long sub(unsigned long long value)
Definition: IgHook_IgHookTrace.cpp:170
IgHookTrace::CounterValue::tick
unsigned long long tick(void)
Definition: IgHook_IgHookTrace.cpp:155
IgHookTrace::symbol
static bool symbol(void *address, const char *&sym, const char *&lib, int &offset, int &liboffset)
Definition: IgHook_IgHookTrace.cpp:222
IgHookTraceAlloc::m_left
size_t m_left
Definition: IgHook_IgHookTrace.h:34
IgHookTrace::CounterValue::m_count
unsigned long long m_count
Definition: IgHook_IgHookTrace.h:72
IgHookTrace::next
IgHookTrace * next(void)
Definition: IgHook_IgHookTrace.cpp:218
IgHookTrace::address
void * address(void)
Definition: IgHook_IgHookTrace.cpp:220
IgHookTrace::tosymbol
static void * tosymbol(void *address)
Definition: IgHook_IgHookTrace.cpp:247
IgHookTrace::CounterValue
Value for a counter chained from a trace.
Definition: IgHook_IgHookTrace.h:45
IgHookTraceAlloc::IgHookTraceAlloc
IgHookTraceAlloc(void)
Definition: IgHook_IgHookTrace.cpp:109
IgHookTrace::CounterValue::untick
unsigned long long untick(void)
Definition: IgHook_IgHookTrace.cpp:160
IgHookTrace::CounterValue::m_value
unsigned long long m_value
Definition: IgHook_IgHookTrace.h:71
cpluginsvc.n
n
Definition: cpluginsvc.py:234
IgHookTrace::m_address
void * m_address
Definition: IgHook_IgHookTrace.h:104
gaudirun.args
args
Definition: gaudirun.py:336
IgHookTrace::m_alloc
IgHookTraceAlloc * m_alloc
Definition: IgHook_IgHookTrace.h:100
IgHookTrace::Counter
Nearly dummy object type to identify a counter.
Definition: IgHook_IgHookTrace.h:40
IgHookTrace::IgHookTrace
IgHookTrace(IgHookTrace *parent=0, void *address=0)
Definition: IgHook_IgHookTrace.cpp:206
IgHookTrace::CounterValue::add
unsigned long long add(unsigned long long value)
Definition: IgHook_IgHookTrace.cpp:165
plotSpeedupsPyRoot.counter
counter
Definition: plotSpeedupsPyRoot.py:175
AlgSequencer.top
top
Definition: AlgSequencer.py:37