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