~ubuntu-branches/ubuntu/jaunty/google-perftools/jaunty

« back to all changes in this revision

Viewing changes to src/profiler.cc

  • Committer: Bazaar Package Importer
  • Author(s): Daigo Moriwaki
  • Date: 2008-06-15 23:41:36 UTC
  • mfrom: (3.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20080615234136-al5gawvdvt5vhdtz
Tags: 0.98-1
* New upstream release. (Closes: #425147)
* Compiled with GCC 4.3. (Closes: #454841)
* debian/watch: can now report upstream's version (Closes: #450294)
* Because of a file conflict between tau and libgoogle-perftools the
  binary pprof is renamed as google-pprof. (Closes: #404001)
  Great thanks to Michael Mende.
* debian/rules: autoconf files are now generated at the build time.
* Bumped up Standards-Version to 3.7.3, no changes are required.
* Split a new package, libtcmallc_minimal0. The upstream supports
  this module for wider platforms. So I leave its architecture to be
  `any'.
* libgoogle-perftools0's architecture is now i386. The upstream
  supports this module for x86 and x86_64. However, x86_64 requires
  libunwind's development head, which Debian does not have yet.
* Removed an unnecessary patch, debian/patches/02_profiler.cc_alpha.diff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
// ---
31
31
// Author: Sanjay Ghemawat
 
32
//         Chris Demetriou (refactoring)
32
33
//
33
34
// Profile current program by sampling stack-trace every so often
34
 
//
35
 
// TODO: Detect whether or not setitimer() applies to all threads in
36
 
// the process.  If so, instead of starting and stopping by changing
37
 
// the signal handler, start and stop by calling setitimer() and
38
 
// do nothing in the per-thread registration code.
39
35
 
40
36
#include "config.h"
 
37
#include "getpc.h"      // should be first to get the _GNU_SOURCE dfn
 
38
#include <signal.h>
41
39
#include <assert.h>
42
40
#include <stdio.h>
43
 
#include <stdlib.h>
44
 
#include <unistd.h>                 // for getuid() and geteuid()
45
 
#if defined HAVE_STDINT_H
46
 
#include <stdint.h>
47
 
#elif defined HAVE_INTTYPES_H
48
 
#include <inttypes.h>
49
 
#else
50
 
#include <sys/types.h>
51
 
#endif
52
41
#include <errno.h>
53
 
#include <signal.h>
54
 
#include <unistd.h>
 
42
#include <ucontext.h>
 
43
#include <string.h>
55
44
#include <sys/time.h>
56
 
#include <string.h>
57
 
#include <fcntl.h>
58
 
#include "google/profiler.h"
59
 
#include "google/stacktrace.h"
 
45
#include <string>
 
46
#include <google/profiler.h>
 
47
#include <google/stacktrace.h>
60
48
#include "base/commandlineflags.h"
 
49
#include "base/logging.h"
61
50
#include "base/googleinit.h"
 
51
#include "base/spinlock.h"
 
52
#include "base/sysinfo.h"             /* for GetUniquePathFromEnv, etc */
 
53
#include "profiledata.h"
62
54
#ifdef HAVE_CONFLICT_SIGNAL_H
63
55
#include "conflict-signal.h"          /* used on msvc machines */
64
56
#endif
65
 
#include "base/logging.h"
66
 
 
67
 
#ifndef PATH_MAX
68
 
#ifdef MAXPATHLEN
69
 
#define PATH_MAX        MAXPATHLEN
70
 
#else
71
 
#define PATH_MAX        4096         // seems conservative for max filename len!
72
 
#endif
73
 
#endif
74
 
 
75
 
#if HAVE_PTHREAD
76
 
#  include <pthread.h>
77
 
#  define LOCK(m) pthread_mutex_lock(m)
78
 
#  define UNLOCK(m) pthread_mutex_unlock(m)
79
 
// Macro for easily checking return values from pthread routines
80
 
#  define PCALL(f) do { int __r = f;  if (__r != 0) { fprintf(stderr, "%s: %s\n", #f, strerror(__r)); abort(); } } while (0)
81
 
#else
82
 
#  define LOCK(m)
83
 
#  define UNLOCK(m)
84
 
#  define PCALL(f)
85
 
#endif
86
 
 
87
 
// For now, keep logging as a noop.  TODO: do something better?
88
 
#undef LOG
89
 
#define LOG(msg)
 
57
 
 
58
using std::string;
90
59
 
91
60
DEFINE_string(cpu_profile, "",
92
61
              "Profile file name (used if CPUPROFILE env var not specified)");
93
62
 
94
 
// Figure out how to get the PC for our architecture
95
 
#if defined HAVE_STRUCT_SIGINFO_SI_FADDR
96
 
typedef struct siginfo SigStructure;
97
 
inline void* GetPC(const SigStructure& sig_structure ) {
98
 
  return (void*)sig_structure.si_faddr; // maybe not correct
99
 
}
100
 
 
101
 
#elif defined HAVE_STRUCT_SIGCONTEXT_SC_EIP
102
 
typedef struct sigcontext SigStructure;
103
 
inline void* GetPC(const SigStructure& sig_structure ) {
104
 
  return (void*)sig_structure.sc_eip;
105
 
}
106
 
 
107
 
#elif defined HAVE_STRUCT_SIGCONTEXT_EIP
108
 
typedef struct sigcontext SigStructure;
109
 
inline void* GetPC(const SigStructure& sig_structure ) {
110
 
  return (void*)sig_structure.eip;
111
 
}
112
 
 
113
 
#elif defined HAVE_STRUCT_SIGCONTEXT_RIP
114
 
typedef struct sigcontext SigStructure;
115
 
inline void* GetPC(const SigStructure& sig_structure ) {
116
 
  return (void*)sig_structure.rip;
117
 
}
118
 
 
119
 
#elif defined HAVE_STRUCT_SIGCONTEXT_SC_IP
120
 
typedef struct sigcontext SigStructure;
121
 
inline void* GetPC(const SigStructure& sig_structure ) {
122
 
  return (void*)sig_structure.sc_ip;
123
 
}
124
 
 
125
 
#elif defined HAVE_STRUCT_UCONTEXT_UC_MCONTEXT
126
 
typedef struct ucontext SigStructure;
127
 
inline void* GetPC(const SigStructure& sig_structure ) {
128
 
  return (void*)sig_structure.uc_mcontext.gregs[REG_RIP];
129
 
}
130
 
 
131
 
#elif defined HAVE_STRUCT_SIGCONTEXT_REGS__NIP
132
 
typedef struct sigcontext SigStructure;
133
 
inline void* GetPC(const SigStructure& sig_structure ) {
134
 
  return (void*)sig_structure.regs->nip;
135
 
}
136
 
 
137
 
#else
138
 
#error I dont know what your PC is
139
 
 
140
 
#endif
141
 
 
142
 
 
143
 
// Collects up all profile data
144
 
class ProfileData {
 
63
// Collects up all profile data.  This is a singleton, which is
 
64
// initialized by a constructor at startup.
 
65
class CpuProfiler {
145
66
 public:
146
 
  ProfileData();
147
 
  ~ProfileData();
148
 
 
149
 
  // Is profiling turned on at all
150
 
  inline bool enabled() { return out_ >= 0; }
151
 
 
152
 
  // What is the frequency of interrupts (ticks per second)
153
 
  inline int frequency() { return frequency_; }
154
 
 
155
 
  // Record an interrupt at "pc"
156
 
  void Add(unsigned long pc);
157
 
 
158
 
  void FlushTable();
 
67
  CpuProfiler();
 
68
  ~CpuProfiler();
159
69
 
160
70
  // Start profiler to write profile info into fname
161
 
  bool Start(const char* fname);
162
 
  // Stop profiling and flush the data
 
71
  bool Start(const char* fname, const ProfilerOptions* options);
 
72
 
 
73
  // Stop profiling and write the data to disk.
163
74
  void Stop();
164
75
 
 
76
  // Write the data to disk (and continue profiling).
 
77
  void FlushTable();
 
78
 
 
79
  bool Enabled();
 
80
 
165
81
  void GetCurrentState(ProfilerState* state);
166
82
 
 
83
  // Register the current thread with the profiler.  This should be
 
84
  // called only once per thread.
 
85
  //
 
86
  // The profiler attempts to determine whether or not timers are
 
87
  // shared by all threads in the process.  (With LinuxThreads, and
 
88
  // with NPTL on some Linux kernel versions, each thread has separate
 
89
  // timers.)
 
90
  //
 
91
  // On systems which have a separate interval timer for each thread,
 
92
  // this function starts the timer for the current thread.  Profiling
 
93
  // is disabled by ignoring the resulting signals, and enabled by
 
94
  // setting their handler to be prof_handler.
 
95
  //
 
96
  // Prior to determining whether timers are shared, this function
 
97
  // will unconditionally start the timer.  However, if this function
 
98
  // determines that timers are shared, then it will stop the timer if
 
99
  // profiling is not currently enabled.
 
100
  void RegisterThread();
 
101
 
 
102
  static CpuProfiler instance_;
 
103
 
167
104
 private:
168
 
  static const int kMaxStackDepth = 64;         // Max stack depth profiled
169
105
  static const int kMaxFrequency = 4000;        // Largest allowed frequency
170
106
  static const int kDefaultFrequency = 100;     // Default frequency
171
 
  static const int kAssociativity = 4;          // For hashtable
172
 
  static const int kBuckets = 1 << 10;          // For hashtable
173
 
  static const int kBufferLength = 1 << 18;     // For eviction buffer
174
 
 
175
 
  // Type of slots: each slot can be either a count, or a PC value
176
 
  typedef uintptr_t Slot;
177
 
 
178
 
  // Hash-table/eviction-buffer entry
179
 
  struct Entry {
180
 
    Slot count;                 // Number of hits
181
 
    Slot depth;                 // Stack depth
182
 
    Slot stack[kMaxStackDepth]; // Stack contents
183
 
  };
184
 
 
185
 
  // Hash table bucket
186
 
  struct Bucket {
187
 
    Entry entry[kAssociativity];
188
 
  };
189
 
 
190
 
#ifdef HAVE_PTHREAD
191
 
  // Invariant: table_lock_ is only grabbed by handler, or by other code
192
 
  // when the signal is being ignored (via SIG_IGN).
193
 
  //
194
 
  // Locking order is "state_lock_" first, and then "table_lock_"
195
 
  pthread_mutex_t state_lock_;  // Protects filename, etc.(not used in handler)
196
 
  pthread_mutex_t table_lock_;  // Cannot use "Mutex" in signal handlers
197
 
#endif
198
 
  Bucket*       hash_;          // hash table
199
 
 
200
 
  Slot*         evict_;         // evicted entries
201
 
  int           num_evicted_;   // how many evicted entries?
202
 
  int           out_;           // fd for output file
203
 
  int           count_;         // How many interrupts recorded
204
 
  int           evictions_;     // How many evictions
205
 
  size_t        total_bytes_;   // How much output
206
 
  char*         fname_;         // Profile file name
207
 
  int           frequency_;     // Interrupts per second
208
 
  time_t        start_time_;    // Start time, or 0
209
 
 
210
 
  // Add "pc -> count" to eviction buffer
211
 
  void Evict(const Entry& entry);
212
 
 
213
 
  // Write contents of eviction buffer to disk
214
 
  void FlushEvicted();
215
 
 
216
 
  // Handler that records the interrupted pc in the profile data
217
 
  static void prof_handler(int sig, SigStructure sig_structure );
218
 
 
219
 
  // Sets the timer interrupt signal handler to the specified routine
220
 
  static void SetHandler(void (*handler)(int));
 
107
 
 
108
  // Sample frequency, read-only after construction.
 
109
  int           frequency_;
 
110
 
 
111
  // These locks implement the locking requirements described in the
 
112
  // ProfileData documentation, specifically:
 
113
  //
 
114
  // control_lock_ is held all over all collector_ method calls except for
 
115
  // the 'Add' call made from the signal handler, to protect against
 
116
  // concurrent use of collector_'s control routines.
 
117
  //
 
118
  // signal_lock_ is held over calls to 'Start', 'Stop', 'Flush', and
 
119
  // 'Add', to protect against concurrent use of data collection and
 
120
  // writing routines.  Code other than the signal handler must disable
 
121
  // the timer signal while holding signal_lock, to prevent deadlock.
 
122
  //
 
123
  // Locking order is control_lock_ first, and then signal_lock_.
 
124
  // signal_lock_ is acquired by the prof_handler without first
 
125
  // acquiring control_lock_.
 
126
  SpinLock      control_lock_;
 
127
  SpinLock      signal_lock_;
 
128
  ProfileData   collector_;
 
129
 
 
130
  // Filter function and its argument, if any.  (NULL means include
 
131
  // all samples).  Set at start, read-only while running.  Written
 
132
  // while holding both control_lock_ and signal_lock_, read and
 
133
  // executed under signal_lock_.
 
134
  int           (*filter_)(void*);
 
135
  void*         filter_arg_;
 
136
 
 
137
  // Whether or not the threading system provides interval timers
 
138
  // that are shared by all threads in a process.
 
139
  enum {
 
140
    TIMERS_UNTOUCHED,  // No timer initialization attempted yet.
 
141
    TIMERS_ONE_SET,    // First thread has registered and set timer.
 
142
    TIMERS_SHARED,     // Timers are shared by all threads.
 
143
    TIMERS_SEPARATE    // Timers are separate in each thread.
 
144
  }             timer_sharing_;
 
145
 
 
146
  // Start the interval timer used for profiling.  If the thread
 
147
  // library shares timers between threads, this is used to enable and
 
148
  // disable the timer when starting and stopping profiling.  If
 
149
  // timers are not shared, this is used to enable the timer in each
 
150
  // thread.
 
151
  void StartTimer();
 
152
 
 
153
  // Stop the interval timer used for profiling.  Used only if the
 
154
  // thread library shares timers between threads.
 
155
  void StopTimer();
 
156
 
 
157
  // Returns true if the profiling interval timer enabled in the
 
158
  // current thread.  This actually checks the kernel's interval timer
 
159
  // setting.  (It is used to detect whether timers are shared or
 
160
  // separate.)
 
161
  bool IsTimerRunning();
 
162
 
 
163
  // Sets the timer interrupt signal handler to one that stores the pc.
 
164
  static void EnableHandler();
 
165
 
 
166
  // Disables (ignores) the timer interrupt signal.
 
167
  static void DisableHandler();
 
168
 
 
169
  // Signale handler that records the interrupted pc in the profile data
 
170
  static void prof_handler(int sig, siginfo_t*, void* signal_ucontext);
221
171
};
222
172
 
223
 
// Evict the specified entry to the evicted-entry buffer
224
 
inline void ProfileData::Evict(const Entry& entry) {
225
 
  const int d = entry.depth;
226
 
  const int nslots = d + 2;     // Number of slots needed in eviction buffer
227
 
  if (num_evicted_ + nslots > kBufferLength) {
228
 
    FlushEvicted();
229
 
    assert(num_evicted_ == 0);
230
 
    assert(nslots <= kBufferLength);
231
 
  }
232
 
  evict_[num_evicted_++] = entry.count;
233
 
  evict_[num_evicted_++] = d;
234
 
  memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot));
235
 
  num_evicted_ += d;
236
 
}
 
173
// Profile data structure singleton: Constructor will check to see if
 
174
// profiling should be enabled.  Destructor will write profile data
 
175
// out to disk.
 
176
CpuProfiler CpuProfiler::instance_;
237
177
 
238
178
// Initialize profiling: activated if getenv("CPUPROFILE") exists.
239
 
ProfileData::ProfileData() :
240
 
  hash_(0),
241
 
  evict_(0),
242
 
  num_evicted_(0),
243
 
  out_(-1),
244
 
  count_(0),
245
 
  evictions_(0),
246
 
  total_bytes_(0),
247
 
  fname_(0),
248
 
  frequency_(0),
249
 
  start_time_(0) {
250
 
 
251
 
  PCALL(pthread_mutex_init(&state_lock_, NULL));
252
 
  PCALL(pthread_mutex_init(&table_lock_, NULL));
253
 
 
 
179
CpuProfiler::CpuProfiler()
 
180
    : timer_sharing_(TIMERS_UNTOUCHED) {
254
181
  // Get frequency of interrupts (if specified)
255
182
  char junk;
256
 
  const char* fr = getenv("PROFILEFREQUENCY");
 
183
  const char* fr = getenv("CPUPROFILE_FREQUENCY");
257
184
  if (fr != NULL && (sscanf(fr, "%d%c", &frequency_, &junk) == 1) &&
258
185
      (frequency_ > 0)) {
259
186
    // Limit to kMaxFrequency
262
189
    frequency_ = kDefaultFrequency;
263
190
  }
264
191
 
265
 
  // Ignore signals until we decide to turn profiling on
266
 
  SetHandler(SIG_IGN);
 
192
  // Ignore signals until we decide to turn profiling on.  (Paranoia;
 
193
  // should already be ignored.)
 
194
  DisableHandler();
267
195
 
268
 
  ProfilerRegisterThread();
 
196
  RegisterThread();
269
197
 
270
198
  // Should profiling be enabled automatically at start?
271
 
  char* cpuprofile = getenv("CPUPROFILE");
272
 
  if (!cpuprofile || cpuprofile[0] == '\0') {
 
199
  char fname[PATH_MAX];
 
200
  if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
273
201
    return;
274
202
  }
275
203
  // We don't enable profiling if setuid -- it's a security risk
 
204
#ifdef HAVE_GETEUID
276
205
  if (getuid() != geteuid())
277
206
    return;
278
 
 
279
 
  // If we're a child process of the 'main' process, we can't just use
280
 
  // the name CPUPROFILE -- the parent process will be using that.
281
 
  // Instead we append our pid to the name.  How do we tell if we're a
282
 
  // child process?  Ideally we'd set an environment variable that all
283
 
  // our children would inherit.  But -- and perhaps this is a bug in
284
 
  // gcc -- if you do a setenv() in a shared libarary in a global
285
 
  // constructor, the environment setting is lost by the time main()
286
 
  // is called.  The only safe thing we can do in such a situation is
287
 
  // to modify the existing envvar.  So we do a hack: in the parent,
288
 
  // we set the high bit of the 1st char of CPUPROFILE.  In the child,
289
 
  // we notice the high bit is set and append the pid().  This works
290
 
  // assuming cpuprofile filenames don't normally have the high bit
291
 
  // set in their first character!  If that assumption is violated,
292
 
  // we'll still get a profile, but one with an unexpected name.
293
 
  // TODO(csilvers): set an envvar instead when we can do it reliably.
294
 
  char fname[PATH_MAX];
295
 
  if (cpuprofile[0] & 128) {                    // high bit is set
296
 
    snprintf(fname, sizeof(fname), "%c%s_%u",   // add pid and clear high bit
297
 
             cpuprofile[0] & 127, cpuprofile+1, (unsigned int)(getpid()));
298
 
  } else {
299
 
    snprintf(fname, sizeof(fname), "%s", cpuprofile);
300
 
    cpuprofile[0] |= 128;                       // set high bit for kids to see
301
 
  }
302
 
 
303
 
  // process being profiled.  CPU profiles are messed up in that case.
304
 
 
305
 
  if (!Start(fname)) {
306
 
    fprintf(stderr, "Can't turn on cpu profiling: ");
307
 
    perror(fname);
308
 
    exit(1);
 
207
#endif
 
208
 
 
209
  if (!Start(fname, NULL)) {
 
210
    RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
 
211
            fname, strerror(errno));
309
212
  }
310
213
}
311
214
 
312
 
bool ProfileData::Start(const char* fname) {
313
 
  LOCK(&state_lock_);
314
 
  if (enabled()) {
315
 
    // profiling is already enabled
316
 
    UNLOCK(&state_lock_);
317
 
    return false;
318
 
  }
319
 
 
320
 
  // Open output file and initialize various data structures
321
 
  int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
322
 
  if (fd < 0) {
323
 
    // Can't open outfile for write
324
 
    UNLOCK(&state_lock_);
325
 
    return false;
326
 
  }
327
 
 
328
 
  start_time_ = time(NULL);
329
 
  fname_ = strdup(fname);
330
 
 
331
 
  LOCK(&table_lock_);
332
 
 
333
 
  // Reset counters
334
 
  num_evicted_ = 0;
335
 
  count_       = 0;
336
 
  evictions_   = 0;
337
 
  total_bytes_ = 0;
338
 
  // But leave frequency_ alone (i.e., ProfilerStart() doesn't affect
339
 
  // their values originally set in the constructor)
340
 
 
341
 
  out_  = fd;
342
 
 
343
 
  hash_ = new Bucket[kBuckets];
344
 
  evict_ = new Slot[kBufferLength];
345
 
  memset(hash_, 0, sizeof(hash_[0]) * kBuckets);
346
 
 
347
 
  // Record special entries
348
 
  evict_[num_evicted_++] = 0;                     // count for header
349
 
  evict_[num_evicted_++] = 3;                     // depth for header
350
 
  evict_[num_evicted_++] = 0;                     // Version number
351
 
  evict_[num_evicted_++] = 1000000 / frequency_;  // Period (microseconds)
352
 
  evict_[num_evicted_++] = 0;                     // Padding
353
 
 
354
 
  UNLOCK(&table_lock_);
 
215
bool CpuProfiler::Start(const char* fname,
 
216
                        const ProfilerOptions* options) {
 
217
  SpinLockHolder cl(&control_lock_);
 
218
 
 
219
  if (collector_.enabled()) {
 
220
    return false;
 
221
  }
 
222
 
 
223
  {
 
224
    // spin lock really is needed to protect init here, since it's
 
225
    // conceivable that prof_handler may still be running from a
 
226
    // previous profiler run.  (For instance, if prof_handler just
 
227
    // started, had not grabbed the spinlock, then was switched out,
 
228
    // it might start again right now.)  Any such late sample will be
 
229
    // recorded against the new profile, but there's no harm in that.
 
230
    SpinLockHolder sl(&signal_lock_);
 
231
 
 
232
    if (!collector_.Start(fname, frequency_)) {
 
233
      return false;
 
234
    }
 
235
 
 
236
    filter_ = NULL;
 
237
    if (options != NULL && options->filter_in_thread != NULL) {
 
238
      filter_ = options->filter_in_thread;
 
239
      filter_arg_ = options->filter_in_thread_arg;
 
240
    }
 
241
 
 
242
    // Must unlock before setting prof_handler to avoid deadlock
 
243
    // with signal delivered to this thread.
 
244
  }
 
245
 
 
246
  if (timer_sharing_ == TIMERS_SHARED) {
 
247
    StartTimer();
 
248
  }
355
249
 
356
250
  // Setup handler for SIGPROF interrupts
357
 
  SetHandler((void (*)(int)) prof_handler);
 
251
  EnableHandler();
358
252
 
359
 
  UNLOCK(&state_lock_);
360
253
  return true;
361
254
}
362
255
 
363
 
// Write out any collected profile data
364
 
ProfileData::~ProfileData() {
 
256
CpuProfiler::~CpuProfiler() {
365
257
  Stop();
366
258
}
367
259
 
368
260
// Stop profiling and write out any collected profile data
369
 
void ProfileData::Stop() {
370
 
  LOCK(&state_lock_);
371
 
 
372
 
  // Prevent handler from running anymore
373
 
  SetHandler(SIG_IGN);
374
 
 
375
 
  // This lock prevents interference with signal handlers in other threads
376
 
  LOCK(&table_lock_);
377
 
 
378
 
  if (out_ < 0) {
379
 
    // Profiling is not enabled
380
 
    UNLOCK(&table_lock_);
381
 
    UNLOCK(&state_lock_);
382
 
    return;
383
 
  }
384
 
 
385
 
  // Move data from hash table to eviction buffer
386
 
  for (int b = 0; b < kBuckets; b++) {
387
 
    Bucket* bucket = &hash_[b];
388
 
    for (int a = 0; a < kAssociativity; a++) {
389
 
      if (bucket->entry[a].count > 0) {
390
 
        Evict(bucket->entry[a]);
391
 
      }
392
 
    }
393
 
  }
394
 
 
395
 
  if (num_evicted_ + 3 > kBufferLength) {
396
 
    // Ensure there is enough room for end of data marker
397
 
    FlushEvicted();
398
 
  }
399
 
 
400
 
  // Write end of data marker
401
 
  evict_[num_evicted_++] = 0;         // count
402
 
  evict_[num_evicted_++] = 1;         // depth
403
 
  evict_[num_evicted_++] = 0;         // end of data marker
404
 
  FlushEvicted();
405
 
 
406
 
  // Dump "/proc/self/maps" so we get list of mapped shared libraries
407
 
  int maps = open("/proc/self/maps", O_RDONLY);
408
 
  if (maps >= 0) {
409
 
    char buf[100];
410
 
    ssize_t r;
411
 
    while ((r = read(maps, buf, sizeof(buf))) > 0) {
412
 
      write(out_, buf, r);
413
 
    }
414
 
    close(maps);
415
 
  }
416
 
 
417
 
  close(out_);
418
 
  fprintf(stderr, "PROFILE: interrupts/evictions/bytes = %d/%d/%" PRIuS "\n",
419
 
          count_, evictions_, total_bytes_);
420
 
  delete[] hash_;
421
 
  hash_ = 0;
422
 
  delete[] evict_;
423
 
  evict_ = 0;
424
 
  free(fname_);
425
 
  fname_ = 0;
426
 
  start_time_ = 0;
427
 
 
428
 
  out_ = -1;
429
 
  UNLOCK(&table_lock_);
430
 
  UNLOCK(&state_lock_);
431
 
}
432
 
 
433
 
void ProfileData::GetCurrentState(ProfilerState* state) {
434
 
  LOCK(&state_lock_);
435
 
  if (enabled()) {
436
 
    state->enabled = true;
437
 
    state->start_time = start_time_;
438
 
    state->samples_gathered = count_;
439
 
    int buf_size = sizeof(state->profile_name);
440
 
    strncpy(state->profile_name, fname_, buf_size);
441
 
    state->profile_name[buf_size-1] = '\0';
442
 
  } else {
443
 
    state->enabled = false;
444
 
    state->start_time = 0;
445
 
    state->samples_gathered = 0;
446
 
    state->profile_name[0] = '\0';
447
 
  }
448
 
  UNLOCK(&state_lock_);
449
 
}
450
 
 
451
 
void ProfileData::SetHandler(void (*handler)(int)) {
452
 
  struct sigaction sa;
453
 
  sa.sa_handler = handler;
454
 
  sa.sa_flags   = SA_RESTART;
455
 
  sigemptyset(&sa.sa_mask);
456
 
  if (sigaction(SIGPROF, &sa, NULL) != 0) {
457
 
    perror("sigaction(SIGPROF)");
458
 
    exit(1);
459
 
  }
460
 
}
461
 
 
462
 
void ProfileData::FlushTable() {
463
 
  LOCK(&state_lock_); {
464
 
    if (out_ < 0) {
465
 
      // Profiling is not enabled
466
 
      UNLOCK(&state_lock_);
467
 
      return;
468
 
    }
469
 
    SetHandler(SIG_IGN);       // Disable timer interrupts while we're flushing
470
 
    LOCK(&table_lock_); {
471
 
      // Move data from hash table to eviction buffer
472
 
      for (int b = 0; b < kBuckets; b++) {
473
 
        Bucket* bucket = &hash_[b];
474
 
        for (int a = 0; a < kAssociativity; a++) {
475
 
          if (bucket->entry[a].count > 0) {
476
 
            Evict(bucket->entry[a]);
477
 
            bucket->entry[a].depth = 0;
478
 
            bucket->entry[a].count = 0;
479
 
          }
480
 
        }
481
 
      }
482
 
 
483
 
      // Write out all pending data
484
 
      FlushEvicted();
485
 
    } UNLOCK(&table_lock_);
486
 
    SetHandler((void (*)(int)) prof_handler);
487
 
  } UNLOCK(&state_lock_);
488
 
}
489
 
 
490
 
// Record the specified "pc" in the profile data
491
 
void ProfileData::Add(unsigned long pc) {
492
 
  void* stack[kMaxStackDepth];
493
 
  stack[0] = (void*)pc;
494
 
  int depth = GetStackTrace(stack+1, kMaxStackDepth-1,
495
 
                            4/*Removes Add,prof_handler,sighandlers*/);
496
 
  depth++;              // To account for pc value
497
 
 
498
 
  // Make hash-value
499
 
  Slot h = 0;
500
 
  for (int i = 0; i < depth; i++) {
501
 
    Slot slot = reinterpret_cast<Slot>(stack[i]);
502
 
    h = (h << 8) | (h >> (8*(sizeof(h)-1)));
503
 
    h += (slot * 31) + (slot * 7) + (slot * 3);
504
 
  }
505
 
 
506
 
  LOCK(&table_lock_);
507
 
  count_++;
508
 
 
509
 
  // See if table already has an entry for this stack trace
510
 
  bool done = false;
511
 
  Bucket* bucket = &hash_[h % kBuckets];
512
 
  for (int a = 0; a < kAssociativity; a++) {
513
 
    Entry* e = &bucket->entry[a];
514
 
    if (e->depth == depth) {
515
 
      bool match = true;
516
 
      for (int i = 0; i < depth; i++) {
517
 
        if (e->stack[i] != reinterpret_cast<Slot>(stack[i])) {
518
 
          match = false;
519
 
          break;
520
 
        }
521
 
      }
522
 
      if (match) {
523
 
        e->count++;
524
 
        done = true;
525
 
        break;
526
 
      }
527
 
    }
528
 
  }
529
 
 
530
 
  if (!done) {
531
 
    // Evict entry with smallest count
532
 
    Entry* e = &bucket->entry[0];
533
 
    for (int a = 1; a < kAssociativity; a++) {
534
 
      if (bucket->entry[a].count < e->count) {
535
 
        e = &bucket->entry[a];
536
 
      }
537
 
    }
538
 
    if (e->count > 0) {
539
 
      evictions_++;
540
 
      Evict(*e);
541
 
    }
542
 
 
543
 
    // Use the newly evicted entry
544
 
    e->depth = depth;
545
 
    e->count = 1;
546
 
    for (int i = 0; i < depth; i++) {
547
 
      e->stack[i] = reinterpret_cast<Slot>(stack[i]);
548
 
    }
549
 
  }
550
 
  UNLOCK(&table_lock_);
551
 
}
552
 
 
553
 
// Write all evicted data to the profile file
554
 
void ProfileData::FlushEvicted() {
555
 
  if (num_evicted_ > 0) {
556
 
    const char* buf = reinterpret_cast<char*>(evict_);
557
 
    size_t bytes = sizeof(evict_[0]) * num_evicted_;
558
 
    total_bytes_ += bytes;
559
 
    while (bytes > 0) {
560
 
      ssize_t r = write(out_, buf, bytes);
561
 
      if (r < 0) {
562
 
        perror("write");
563
 
        exit(1);
564
 
      }
565
 
      buf += r;
566
 
      bytes -= r;
567
 
    }
568
 
  }
569
 
  num_evicted_ = 0;
570
 
}
571
 
 
572
 
// Profile data structure: Constructor will check to see if profiling
573
 
// should be enabled.  Destructor will write profile data out to disk.
574
 
static ProfileData pdata;
575
 
 
576
 
// Signal handler that records the pc in the profile-data structure
577
 
void ProfileData::prof_handler(int sig, SigStructure sig_structure) {
578
 
  int saved_errno = errno;
579
 
  pdata.Add( (unsigned long int)GetPC( sig_structure ) );
580
 
  errno = saved_errno;
581
 
}
582
 
 
583
 
// Start interval timer for the current thread.  We do this for
584
 
// every known thread.  If profiling is off, the generated signals
585
 
// are ignored, otherwise they are captured by prof_handler().
586
 
void ProfilerRegisterThread() {
 
261
void CpuProfiler::Stop() {
 
262
  SpinLockHolder cl(&control_lock_);
 
263
 
 
264
  if (!collector_.enabled()) {
 
265
    return;
 
266
  }
 
267
 
 
268
  // Ignore timer signals.  Note that the handler may have just
 
269
  // started and might not have taken signal_lock_ yet.  Holding
 
270
  // signal_lock_ below along with the semantics of collector_.Add()
 
271
  // (which does nothing if collection is not enabled) prevents that
 
272
  // late sample from causing a problem.
 
273
  DisableHandler();
 
274
 
 
275
  if (timer_sharing_ == TIMERS_SHARED) {
 
276
    StopTimer();
 
277
  }
 
278
 
 
279
  {
 
280
    SpinLockHolder sl(&signal_lock_);
 
281
    collector_.Stop();
 
282
  }
 
283
}
 
284
 
 
285
void CpuProfiler::FlushTable() {
 
286
  SpinLockHolder cl(&control_lock_);
 
287
 
 
288
  if (!collector_.enabled()) {
 
289
    return;
 
290
  }
 
291
 
 
292
  // Disable timer signal while holding signal_lock_, to prevent deadlock
 
293
  // if we take a timer signal while flushing.
 
294
  DisableHandler();
 
295
  {
 
296
    SpinLockHolder sl(&signal_lock_);
 
297
    collector_.FlushTable();
 
298
  }
 
299
  EnableHandler();
 
300
}
 
301
 
 
302
bool CpuProfiler::Enabled() {
 
303
  SpinLockHolder cl(&control_lock_);
 
304
  return collector_.enabled();
 
305
}
 
306
 
 
307
void CpuProfiler::GetCurrentState(ProfilerState* state) {
 
308
  ProfileData::State collector_state;
 
309
  {
 
310
    SpinLockHolder cl(&control_lock_);
 
311
    collector_.GetCurrentState(&collector_state);
 
312
  }
 
313
 
 
314
  state->enabled = collector_state.enabled;
 
315
  state->start_time = static_cast<time_t>(collector_state.start_time);
 
316
  state->samples_gathered = collector_state.samples_gathered;
 
317
  int buf_size = sizeof(state->profile_name);
 
318
  strncpy(state->profile_name, collector_state.profile_name, buf_size);
 
319
  state->profile_name[buf_size-1] = '\0';
 
320
}
 
321
 
 
322
void CpuProfiler::RegisterThread() {
 
323
  SpinLockHolder cl(&control_lock_);
 
324
 
 
325
  // We try to detect whether timers are being shared by setting a
 
326
  // timer in the first call to this function, then checking whether
 
327
  // it's set in the second call.
 
328
  //
 
329
  // Note that this detection method requires that the first two calls
 
330
  // to RegisterThread must be made from different threads.  (Subsequent
 
331
  // calls will see timer_sharing_ set to either TIMERS_SEPARATE or
 
332
  // TIMERS_SHARED, and won't try to detect the timer sharing type.)
 
333
  //
 
334
  // Also note that if timer settings were inherited across new thread
 
335
  // creation but *not* shared, this approach wouldn't work.  That's
 
336
  // not an issue for any Linux threading implementation, and should
 
337
  // not be a problem for a POSIX-compliant threads implementation.
 
338
  switch (timer_sharing_) {
 
339
    case TIMERS_UNTOUCHED:
 
340
      StartTimer();
 
341
      timer_sharing_ = TIMERS_ONE_SET;
 
342
      break;
 
343
    case TIMERS_ONE_SET:
 
344
      // If the timer is running, that means that the main thread's
 
345
      // timer setup is seen in this (second) thread -- and therefore
 
346
      // that timers are shared.
 
347
      if (IsTimerRunning()) {
 
348
        timer_sharing_ = TIMERS_SHARED;
 
349
        // If profiling has already been enabled, we have to keep the
 
350
        // timer running.  If not, we disable the timer here and
 
351
        // re-enable it in start.
 
352
        if (!collector_.enabled()) {
 
353
          StopTimer();
 
354
        }
 
355
      } else {
 
356
        timer_sharing_ = TIMERS_SEPARATE;
 
357
        StartTimer();
 
358
      }
 
359
      break;
 
360
    case TIMERS_SHARED:
 
361
      // Nothing needed.
 
362
      break;
 
363
    case TIMERS_SEPARATE:
 
364
      StartTimer();
 
365
      break;
 
366
  }
 
367
}
 
368
 
 
369
void CpuProfiler::StartTimer() {
587
370
  // TODO: Randomize the initial interrupt value?
588
371
  // TODO: Randomize the inter-interrupt period on every interrupt?
589
372
  struct itimerval timer;
590
373
  timer.it_interval.tv_sec = 0;
591
 
  timer.it_interval.tv_usec = 1000000 / pdata.frequency();
 
374
  timer.it_interval.tv_usec = 1000000 / frequency_;
592
375
  timer.it_value = timer.it_interval;
593
376
  setitimer(ITIMER_PROF, &timer, 0);
594
377
}
595
378
 
 
379
void CpuProfiler::StopTimer() {
 
380
  struct itimerval timer;
 
381
  memset(&timer, 0, sizeof timer);
 
382
  setitimer(ITIMER_PROF, &timer, 0);
 
383
}
 
384
 
 
385
bool CpuProfiler::IsTimerRunning() {
 
386
  itimerval current_timer;
 
387
  RAW_CHECK(getitimer(ITIMER_PROF, &current_timer) == 0, "getitimer failed");
 
388
  return (current_timer.it_value.tv_sec != 0 ||
 
389
          current_timer.it_value.tv_usec != 0);
 
390
}
 
391
 
 
392
void CpuProfiler::EnableHandler() {
 
393
  struct sigaction sa;
 
394
  sa.sa_sigaction = prof_handler;
 
395
  sa.sa_flags = SA_RESTART | SA_SIGINFO;
 
396
  sigemptyset(&sa.sa_mask);
 
397
  RAW_CHECK(sigaction(SIGPROF, &sa, NULL) == 0, "sigaction failed");
 
398
}
 
399
 
 
400
void CpuProfiler::DisableHandler() {
 
401
  struct sigaction sa;
 
402
  sa.sa_handler = SIG_IGN;
 
403
  sa.sa_flags = SA_RESTART;
 
404
  sigemptyset(&sa.sa_mask);
 
405
  RAW_CHECK(sigaction(SIGPROF, &sa, NULL) == 0, "sigaction failed");
 
406
}
 
407
 
 
408
// Signal handler that records the pc in the profile-data structure
 
409
//
 
410
// NOTE: it is possible for profiling to be disabled just as this
 
411
// signal handler starts, before signal_lock_ is acquired.  Therefore,
 
412
// collector_.Add must check whether profiling is enabled before
 
413
// trying to record any data.  (See also comments in Start and Stop.)
 
414
void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext) {
 
415
  int saved_errno = errno;
 
416
 
 
417
  // Hold the spin lock while we're gathering the trace because there's
 
418
  // no real harm in holding it and there's little point in releasing
 
419
  // and re-acquiring it.  (We'll only be blocking Start, Stop, and
 
420
  // Flush.)  We make sure to release it before restoring errno.
 
421
  {
 
422
    SpinLockHolder sl(&instance_.signal_lock_);
 
423
 
 
424
    if (instance_.filter_ == NULL ||
 
425
        (*instance_.filter_)(instance_.filter_arg_)) {
 
426
      void* stack[ProfileData::kMaxStackDepth];
 
427
 
 
428
      // The top-most active routine doesn't show up as a normal
 
429
      // frame, but as the "pc" value in the signal handler context.
 
430
      stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
 
431
 
 
432
      // We skip the top two stack trace entries (this function and one
 
433
      // signal handler frame) since they are artifacts of profiling and
 
434
      // should not be measured.  Other profiling related frames may be
 
435
      // removed by "pprof" at analysis time.  Instead of skipping the top
 
436
      // frames, we could skip nothing, but that would increase the
 
437
      // profile size unnecessarily.
 
438
      int depth = GetStackTrace(stack + 1, arraysize(stack) - 1, 2);
 
439
      depth++;              // To account for pc value in stack[0];
 
440
 
 
441
      instance_.collector_.Add(depth, stack);
 
442
    }
 
443
  }
 
444
 
 
445
  errno = saved_errno;
 
446
}
 
447
 
 
448
extern "C" void ProfilerRegisterThread() {
 
449
  CpuProfiler::instance_.RegisterThread();
 
450
}
 
451
 
596
452
// DEPRECATED routines
597
 
void ProfilerEnable() { }
598
 
void ProfilerDisable() { }
599
 
 
600
 
void ProfilerFlush() {
601
 
  pdata.FlushTable();
602
 
}
603
 
 
604
 
bool ProfilingIsEnabledForAllThreads() {
605
 
  return pdata.enabled();
606
 
}
607
 
 
608
 
bool ProfilerStart(const char* fname) {
609
 
  return pdata.Start(fname);
610
 
}
611
 
 
612
 
void ProfilerStop() {
613
 
  pdata.Stop();
614
 
}
615
 
 
616
 
void ProfilerGetCurrentState(ProfilerState* state) {
617
 
  pdata.GetCurrentState(state);
 
453
extern "C" void ProfilerEnable() { }
 
454
extern "C" void ProfilerDisable() { }
 
455
 
 
456
extern "C" void ProfilerFlush() {
 
457
  CpuProfiler::instance_.FlushTable();
 
458
}
 
459
 
 
460
extern "C" int ProfilingIsEnabledForAllThreads() {
 
461
  return CpuProfiler::instance_.Enabled();
 
462
}
 
463
 
 
464
extern "C" int ProfilerStart(const char* fname) {
 
465
  return CpuProfiler::instance_.Start(fname, NULL);
 
466
}
 
467
 
 
468
extern "C" int ProfilerStartWithOptions(const char *fname,
 
469
                                         const ProfilerOptions *options) {
 
470
  return CpuProfiler::instance_.Start(fname, options);
 
471
}
 
472
 
 
473
extern "C" void ProfilerStop() {
 
474
  CpuProfiler::instance_.Stop();
 
475
}
 
476
 
 
477
extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
 
478
  CpuProfiler::instance_.GetCurrentState(state);
618
479
}
619
480
 
620
481