31
31
// Author: Sanjay Ghemawat
32
// Chris Demetriou (refactoring)
33
34
// Profile current program by sampling stack-trace every so often
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.
40
36
#include "config.h"
37
#include "getpc.h" // should be first to get the _GNU_SOURCE dfn
41
39
#include <assert.h>
44
#include <unistd.h> // for getuid() and geteuid()
45
#if defined HAVE_STDINT_H
47
#elif defined HAVE_INTTYPES_H
50
#include <sys/types.h>
55
44
#include <sys/time.h>
58
#include "google/profiler.h"
59
#include "google/stacktrace.h"
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 */
65
#include "base/logging.h"
69
#define PATH_MAX MAXPATHLEN
71
#define PATH_MAX 4096 // seems conservative for max filename len!
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)
87
// For now, keep logging as a noop. TODO: do something better?
91
60
DEFINE_string(cpu_profile, "",
92
61
"Profile file name (used if CPUPROFILE env var not specified)");
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
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;
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;
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;
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;
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];
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;
138
#error I dont know what your PC is
143
// Collects up all profile data
63
// Collects up all profile data. This is a singleton, which is
64
// initialized by a constructor at startup.
149
// Is profiling turned on at all
150
inline bool enabled() { return out_ >= 0; }
152
// What is the frequency of interrupts (ticks per second)
153
inline int frequency() { return frequency_; }
155
// Record an interrupt at "pc"
156
void Add(unsigned long pc);
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);
73
// Stop profiling and write the data to disk.
76
// Write the data to disk (and continue profiling).
165
81
void GetCurrentState(ProfilerState* state);
83
// Register the current thread with the profiler. This should be
84
// called only once per thread.
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
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.
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();
102
static CpuProfiler instance_;
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
175
// Type of slots: each slot can be either a count, or a PC value
176
typedef uintptr_t Slot;
178
// Hash-table/eviction-buffer entry
180
Slot count; // Number of hits
181
Slot depth; // Stack depth
182
Slot stack[kMaxStackDepth]; // Stack contents
187
Entry entry[kAssociativity];
191
// Invariant: table_lock_ is only grabbed by handler, or by other code
192
// when the signal is being ignored (via SIG_IGN).
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
198
Bucket* hash_; // hash table
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
210
// Add "pc -> count" to eviction buffer
211
void Evict(const Entry& entry);
213
// Write contents of eviction buffer to disk
216
// Handler that records the interrupted pc in the profile data
217
static void prof_handler(int sig, SigStructure sig_structure );
219
// Sets the timer interrupt signal handler to the specified routine
220
static void SetHandler(void (*handler)(int));
108
// Sample frequency, read-only after construction.
111
// These locks implement the locking requirements described in the
112
// ProfileData documentation, specifically:
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.
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.
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_;
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*);
137
// Whether or not the threading system provides interval timers
138
// that are shared by all threads in a process.
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.
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
153
// Stop the interval timer used for profiling. Used only if the
154
// thread library shares timers between threads.
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
161
bool IsTimerRunning();
163
// Sets the timer interrupt signal handler to one that stores the pc.
164
static void EnableHandler();
166
// Disables (ignores) the timer interrupt signal.
167
static void DisableHandler();
169
// Signale handler that records the interrupted pc in the profile data
170
static void prof_handler(int sig, siginfo_t*, void* signal_ucontext);
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) {
229
assert(num_evicted_ == 0);
230
assert(nslots <= kBufferLength);
232
evict_[num_evicted_++] = entry.count;
233
evict_[num_evicted_++] = d;
234
memcpy(&evict_[num_evicted_], entry.stack, d * sizeof(Slot));
173
// Profile data structure singleton: Constructor will check to see if
174
// profiling should be enabled. Destructor will write profile data
176
CpuProfiler CpuProfiler::instance_;
238
178
// Initialize profiling: activated if getenv("CPUPROFILE") exists.
239
ProfileData::ProfileData() :
251
PCALL(pthread_mutex_init(&state_lock_, NULL));
252
PCALL(pthread_mutex_init(&table_lock_, NULL));
179
CpuProfiler::CpuProfiler()
180
: timer_sharing_(TIMERS_UNTOUCHED) {
254
181
// Get frequency of interrupts (if specified)
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;
265
// Ignore signals until we decide to turn profiling on
192
// Ignore signals until we decide to turn profiling on. (Paranoia;
193
// should already be ignored.)
268
ProfilerRegisterThread();
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)) {
275
203
// We don't enable profiling if setuid -- it's a security risk
276
205
if (getuid() != geteuid())
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()));
299
snprintf(fname, sizeof(fname), "%s", cpuprofile);
300
cpuprofile[0] |= 128; // set high bit for kids to see
303
// process being profiled. CPU profiles are messed up in that case.
306
fprintf(stderr, "Can't turn on cpu profiling: ");
209
if (!Start(fname, NULL)) {
210
RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
211
fname, strerror(errno));
312
bool ProfileData::Start(const char* fname) {
315
// profiling is already enabled
316
UNLOCK(&state_lock_);
320
// Open output file and initialize various data structures
321
int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0666);
323
// Can't open outfile for write
324
UNLOCK(&state_lock_);
328
start_time_ = time(NULL);
329
fname_ = strdup(fname);
338
// But leave frequency_ alone (i.e., ProfilerStart() doesn't affect
339
// their values originally set in the constructor)
343
hash_ = new Bucket[kBuckets];
344
evict_ = new Slot[kBufferLength];
345
memset(hash_, 0, sizeof(hash_[0]) * kBuckets);
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
354
UNLOCK(&table_lock_);
215
bool CpuProfiler::Start(const char* fname,
216
const ProfilerOptions* options) {
217
SpinLockHolder cl(&control_lock_);
219
if (collector_.enabled()) {
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_);
232
if (!collector_.Start(fname, frequency_)) {
237
if (options != NULL && options->filter_in_thread != NULL) {
238
filter_ = options->filter_in_thread;
239
filter_arg_ = options->filter_in_thread_arg;
242
// Must unlock before setting prof_handler to avoid deadlock
243
// with signal delivered to this thread.
246
if (timer_sharing_ == TIMERS_SHARED) {
356
250
// Setup handler for SIGPROF interrupts
357
SetHandler((void (*)(int)) prof_handler);
359
UNLOCK(&state_lock_);
363
// Write out any collected profile data
364
ProfileData::~ProfileData() {
256
CpuProfiler::~CpuProfiler() {
368
260
// Stop profiling and write out any collected profile data
369
void ProfileData::Stop() {
372
// Prevent handler from running anymore
375
// This lock prevents interference with signal handlers in other threads
379
// Profiling is not enabled
380
UNLOCK(&table_lock_);
381
UNLOCK(&state_lock_);
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]);
395
if (num_evicted_ + 3 > kBufferLength) {
396
// Ensure there is enough room for end of data marker
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
406
// Dump "/proc/self/maps" so we get list of mapped shared libraries
407
int maps = open("/proc/self/maps", O_RDONLY);
411
while ((r = read(maps, buf, sizeof(buf))) > 0) {
418
fprintf(stderr, "PROFILE: interrupts/evictions/bytes = %d/%d/%" PRIuS "\n",
419
count_, evictions_, total_bytes_);
429
UNLOCK(&table_lock_);
430
UNLOCK(&state_lock_);
433
void ProfileData::GetCurrentState(ProfilerState* state) {
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';
443
state->enabled = false;
444
state->start_time = 0;
445
state->samples_gathered = 0;
446
state->profile_name[0] = '\0';
448
UNLOCK(&state_lock_);
451
void ProfileData::SetHandler(void (*handler)(int)) {
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)");
462
void ProfileData::FlushTable() {
463
LOCK(&state_lock_); {
465
// Profiling is not enabled
466
UNLOCK(&state_lock_);
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;
483
// Write out all pending data
485
} UNLOCK(&table_lock_);
486
SetHandler((void (*)(int)) prof_handler);
487
} UNLOCK(&state_lock_);
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
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);
509
// See if table already has an entry for this stack trace
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) {
516
for (int i = 0; i < depth; i++) {
517
if (e->stack[i] != reinterpret_cast<Slot>(stack[i])) {
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];
543
// Use the newly evicted entry
546
for (int i = 0; i < depth; i++) {
547
e->stack[i] = reinterpret_cast<Slot>(stack[i]);
550
UNLOCK(&table_lock_);
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;
560
ssize_t r = write(out_, buf, bytes);
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;
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 ) );
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_);
264
if (!collector_.enabled()) {
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.
275
if (timer_sharing_ == TIMERS_SHARED) {
280
SpinLockHolder sl(&signal_lock_);
285
void CpuProfiler::FlushTable() {
286
SpinLockHolder cl(&control_lock_);
288
if (!collector_.enabled()) {
292
// Disable timer signal while holding signal_lock_, to prevent deadlock
293
// if we take a timer signal while flushing.
296
SpinLockHolder sl(&signal_lock_);
297
collector_.FlushTable();
302
bool CpuProfiler::Enabled() {
303
SpinLockHolder cl(&control_lock_);
304
return collector_.enabled();
307
void CpuProfiler::GetCurrentState(ProfilerState* state) {
308
ProfileData::State collector_state;
310
SpinLockHolder cl(&control_lock_);
311
collector_.GetCurrentState(&collector_state);
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';
322
void CpuProfiler::RegisterThread() {
323
SpinLockHolder cl(&control_lock_);
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.
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.)
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:
341
timer_sharing_ = 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()) {
356
timer_sharing_ = TIMERS_SEPARATE;
363
case TIMERS_SEPARATE:
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);
379
void CpuProfiler::StopTimer() {
380
struct itimerval timer;
381
memset(&timer, 0, sizeof timer);
382
setitimer(ITIMER_PROF, &timer, 0);
385
bool CpuProfiler::IsTimerRunning() {
386
itimerval current_timer;
387
RAW_CHECK(getitimer(ITIMER_PROF, ¤t_timer) == 0, "getitimer failed");
388
return (current_timer.it_value.tv_sec != 0 ||
389
current_timer.it_value.tv_usec != 0);
392
void CpuProfiler::EnableHandler() {
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");
400
void CpuProfiler::DisableHandler() {
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");
408
// Signal handler that records the pc in the profile-data structure
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;
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.
422
SpinLockHolder sl(&instance_.signal_lock_);
424
if (instance_.filter_ == NULL ||
425
(*instance_.filter_)(instance_.filter_arg_)) {
426
void* stack[ProfileData::kMaxStackDepth];
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));
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];
441
instance_.collector_.Add(depth, stack);
448
extern "C" void ProfilerRegisterThread() {
449
CpuProfiler::instance_.RegisterThread();
596
452
// DEPRECATED routines
597
void ProfilerEnable() { }
598
void ProfilerDisable() { }
600
void ProfilerFlush() {
604
bool ProfilingIsEnabledForAllThreads() {
605
return pdata.enabled();
608
bool ProfilerStart(const char* fname) {
609
return pdata.Start(fname);
612
void ProfilerStop() {
616
void ProfilerGetCurrentState(ProfilerState* state) {
617
pdata.GetCurrentState(state);
453
extern "C" void ProfilerEnable() { }
454
extern "C" void ProfilerDisable() { }
456
extern "C" void ProfilerFlush() {
457
CpuProfiler::instance_.FlushTable();
460
extern "C" int ProfilingIsEnabledForAllThreads() {
461
return CpuProfiler::instance_.Enabled();
464
extern "C" int ProfilerStart(const char* fname) {
465
return CpuProfiler::instance_.Start(fname, NULL);
468
extern "C" int ProfilerStartWithOptions(const char *fname,
469
const ProfilerOptions *options) {
470
return CpuProfiler::instance_.Start(fname, options);
473
extern "C" void ProfilerStop() {
474
CpuProfiler::instance_.Stop();
477
extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
478
CpuProfiler::instance_.GetCurrentState(state);