blob: 227deb2a0d34a6482ae84c3c0adbee22a926c99a [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2005, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// ---
32// Author: Sanjay Ghemawat
33// Chris Demetriou (refactoring)
34//
35// Profile current program by sampling stack-trace every so often
36
37#include "config.h"
38#include "getpc.h" // should be first to get the _GNU_SOURCE dfn
39#include <signal.h>
40#include <assert.h>
41#include <stdio.h>
42#include <errno.h>
43#include <string.h>
44#ifdef HAVE_UNISTD_H
45#include <unistd.h> // for getpid()
46#endif
47#if defined(HAVE_SYS_UCONTEXT_H)
48#include <sys/ucontext.h>
49#elif defined(HAVE_UCONTEXT_H)
50#include <ucontext.h>
51#elif defined(HAVE_CYGWIN_SIGNAL_H)
52#include <cygwin/signal.h>
53typedef ucontext ucontext_t;
54#else
55typedef int ucontext_t; // just to quiet the compiler, mostly
56#endif
57#include <sys/time.h>
58#include <string>
59#include <gperftools/profiler.h>
60#include <gperftools/stacktrace.h>
61#include "base/commandlineflags.h"
62#include "base/logging.h"
63#include "base/googleinit.h"
64#include "base/spinlock.h"
65#include "base/sysinfo.h" /* for GetUniquePathFromEnv, etc */
66#include "profiledata.h"
67#include "profile-handler.h"
Austin Schuh745610d2015-09-06 18:19:50 -070068
69using std::string;
70
71DEFINE_bool(cpu_profiler_unittest,
72 EnvToBool("PERFTOOLS_UNITTEST", true),
73 "Determines whether or not we are running under the \
74 control of a unit test. This allows us to include or \
75 exclude certain behaviours.");
76
77// Collects up all profile data. This is a singleton, which is
78// initialized by a constructor at startup. If no cpu profiler
79// signal is specified then the profiler lifecycle is either
80// manaully controlled via the API or attached to the scope of
81// the singleton (program scope). Otherwise the cpu toggle is
82// used to allow for user selectable control via signal generation.
83// This is very useful for profiling a daemon process without
84// having to start and stop the daemon or having to modify the
85// source code to use the cpu profiler API.
86class CpuProfiler {
87 public:
88 CpuProfiler();
89 ~CpuProfiler();
90
91 // Start profiler to write profile info into fname
92 bool Start(const char* fname, const ProfilerOptions* options);
93
94 // Stop profiling and write the data to disk.
95 void Stop();
96
97 // Write the data to disk (and continue profiling).
98 void FlushTable();
99
100 bool Enabled();
101
102 void GetCurrentState(ProfilerState* state);
103
104 static CpuProfiler instance_;
105
106 private:
107 // This lock implements the locking requirements described in the ProfileData
108 // documentation, specifically:
109 //
110 // lock_ is held all over all collector_ method calls except for the 'Add'
111 // call made from the signal handler, to protect against concurrent use of
112 // collector_'s control routines. Code other than signal handler must
113 // unregister the signal handler before calling any collector_ method.
114 // 'Add' method in the collector is protected by a guarantee from
115 // ProfileHandle that only one instance of prof_handler can run at a time.
116 SpinLock lock_;
117 ProfileData collector_;
118
119 // Filter function and its argument, if any. (NULL means include all
120 // samples). Set at start, read-only while running. Written while holding
121 // lock_, read and executed in the context of SIGPROF interrupt.
122 int (*filter_)(void*);
123 void* filter_arg_;
124
125 // Opaque token returned by the profile handler. To be used when calling
126 // ProfileHandlerUnregisterCallback.
127 ProfileHandlerToken* prof_handler_token_;
128
129 // Sets up a callback to receive SIGPROF interrupt.
130 void EnableHandler();
131
132 // Disables receiving SIGPROF interrupt.
133 void DisableHandler();
134
135 // Signal handler that records the interrupted pc in the profile data.
136 static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
137 void* cpu_profiler);
138};
139
140// Signal handler that is registered when a user selectable signal
141// number is defined in the environment variable CPUPROFILESIGNAL.
142static void CpuProfilerSwitch(int signal_number)
143{
Brian Silverman20350ac2021-11-17 18:19:55 -0800144 static unsigned profile_count;
145 static char base_profile_name[PATH_MAX];
146 static bool started = false;
Austin Schuh745610d2015-09-06 18:19:50 -0700147
Brian Silverman20350ac2021-11-17 18:19:55 -0800148 if (base_profile_name[0] == '\0') {
149 if (!GetUniquePathFromEnv("CPUPROFILE", base_profile_name)) {
150 RAW_LOG(FATAL,"Cpu profiler switch is registered but no CPUPROFILE is defined");
151 return;
Austin Schuh745610d2015-09-06 18:19:50 -0700152 }
Brian Silverman20350ac2021-11-17 18:19:55 -0800153 }
154
155 if (!started) {
156 char full_profile_name[PATH_MAX + 16];
157
158 snprintf(full_profile_name, sizeof(full_profile_name), "%s.%u",
159 base_profile_name, profile_count++);
160
161 if(!ProfilerStart(full_profile_name)) {
162 RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
163 full_profile_name, strerror(errno));
Austin Schuh745610d2015-09-06 18:19:50 -0700164 }
Brian Silverman20350ac2021-11-17 18:19:55 -0800165 } else {
166 ProfilerStop();
167 }
168 started = !started;
Austin Schuh745610d2015-09-06 18:19:50 -0700169}
170
171// Profile data structure singleton: Constructor will check to see if
172// profiling should be enabled. Destructor will write profile data
173// out to disk.
174CpuProfiler CpuProfiler::instance_;
175
176// Initialize profiling: activated if getenv("CPUPROFILE") exists.
177CpuProfiler::CpuProfiler()
178 : prof_handler_token_(NULL) {
179 // TODO(cgd) Move this code *out* of the CpuProfile constructor into a
180 // separate object responsible for initialization. With ProfileHandler there
181 // is no need to limit the number of profilers.
182 if (getenv("CPUPROFILE") == NULL) {
183 if (!FLAGS_cpu_profiler_unittest) {
184 RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n");
185 }
186 return;
187 }
188
189 // We don't enable profiling if setuid -- it's a security risk
190#ifdef HAVE_GETEUID
191 if (getuid() != geteuid()) {
192 if (!FLAGS_cpu_profiler_unittest) {
193 RAW_LOG(WARNING, "Cannot perform CPU profiling when running with setuid\n");
194 }
195 return;
196 }
197#endif
198
199 char *signal_number_str = getenv("CPUPROFILESIGNAL");
200 if (signal_number_str != NULL) {
201 long int signal_number = strtol(signal_number_str, NULL, 10);
202 if (signal_number >= 1 && signal_number <= 64) {
203 intptr_t old_signal_handler = reinterpret_cast<intptr_t>(signal(signal_number, CpuProfilerSwitch));
204 if (old_signal_handler == 0) {
205 RAW_LOG(INFO,"Using signal %d as cpu profiling switch", signal_number);
206 } else {
207 RAW_LOG(FATAL, "Signal %d already in use\n", signal_number);
208 }
209 } else {
210 RAW_LOG(FATAL, "Signal number %s is invalid\n", signal_number_str);
211 }
212 } else {
213 char fname[PATH_MAX];
214 if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
215 if (!FLAGS_cpu_profiler_unittest) {
216 RAW_LOG(WARNING, "CPU profiler linked but no valid CPUPROFILE environment variable found\n");
217 }
218 return;
219 }
220
221 if (!Start(fname, NULL)) {
222 RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
223 fname, strerror(errno));
224 }
225 }
226}
227
228bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
229 SpinLockHolder cl(&lock_);
230
231 if (collector_.enabled()) {
232 return false;
233 }
234
235 ProfileHandlerState prof_handler_state;
236 ProfileHandlerGetState(&prof_handler_state);
237
238 ProfileData::Options collector_options;
239 collector_options.set_frequency(prof_handler_state.frequency);
240 if (!collector_.Start(fname, collector_options)) {
241 return false;
242 }
243
244 filter_ = NULL;
245 if (options != NULL && options->filter_in_thread != NULL) {
246 filter_ = options->filter_in_thread;
247 filter_arg_ = options->filter_in_thread_arg;
248 }
249
250 // Setup handler for SIGPROF interrupts
251 EnableHandler();
252
253 return true;
254}
255
256CpuProfiler::~CpuProfiler() {
257 Stop();
258}
259
260// Stop profiling and write out any collected profile data
261void CpuProfiler::Stop() {
262 SpinLockHolder cl(&lock_);
263
264 if (!collector_.enabled()) {
265 return;
266 }
267
268 // Unregister prof_handler to stop receiving SIGPROF interrupts before
269 // stopping the collector.
270 DisableHandler();
271
272 // DisableHandler waits for the currently running callback to complete and
273 // guarantees no future invocations. It is safe to stop the collector.
274 collector_.Stop();
275}
276
277void CpuProfiler::FlushTable() {
278 SpinLockHolder cl(&lock_);
279
280 if (!collector_.enabled()) {
281 return;
282 }
283
284 // Unregister prof_handler to stop receiving SIGPROF interrupts before
285 // flushing the profile data.
286 DisableHandler();
287
288 // DisableHandler waits for the currently running callback to complete and
289 // guarantees no future invocations. It is safe to flush the profile data.
290 collector_.FlushTable();
291
292 EnableHandler();
293}
294
295bool CpuProfiler::Enabled() {
296 SpinLockHolder cl(&lock_);
297 return collector_.enabled();
298}
299
300void CpuProfiler::GetCurrentState(ProfilerState* state) {
301 ProfileData::State collector_state;
302 {
303 SpinLockHolder cl(&lock_);
304 collector_.GetCurrentState(&collector_state);
305 }
306
307 state->enabled = collector_state.enabled;
308 state->start_time = static_cast<time_t>(collector_state.start_time);
309 state->samples_gathered = collector_state.samples_gathered;
310 int buf_size = sizeof(state->profile_name);
311 strncpy(state->profile_name, collector_state.profile_name, buf_size);
312 state->profile_name[buf_size-1] = '\0';
313}
314
315void CpuProfiler::EnableHandler() {
316 RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
317 prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
318 RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
319}
320
321void CpuProfiler::DisableHandler() {
322 RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
323 ProfileHandlerUnregisterCallback(prof_handler_token_);
324 prof_handler_token_ = NULL;
325}
326
327// Signal handler that records the pc in the profile-data structure. We do no
328// synchronization here. profile-handler.cc guarantees that at most one
329// instance of prof_handler() will run at a time. All other routines that
330// access the data touched by prof_handler() disable this signal handler before
331// accessing the data and therefore cannot execute concurrently with
332// prof_handler().
333void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
334 void* cpu_profiler) {
335 CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
336
337 if (instance->filter_ == NULL ||
338 (*instance->filter_)(instance->filter_arg_)) {
339 void* stack[ProfileData::kMaxStackDepth];
340
341 // Under frame-pointer-based unwinding at least on x86, the
342 // top-most active routine doesn't show up as a normal frame, but
343 // as the "pc" value in the signal handler context.
344 stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
345
346 // We skip the top three stack trace entries (this function,
347 // SignalHandler::SignalHandler and one signal handler frame)
348 // since they are artifacts of profiling and should not be
349 // measured. Other profiling related frames may be removed by
350 // "pprof" at analysis time. Instead of skipping the top frames,
351 // we could skip nothing, but that would increase the profile size
352 // unnecessarily.
353 int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
354 3, signal_ucontext);
355
356 void **used_stack;
Brian Silverman20350ac2021-11-17 18:19:55 -0800357 if (depth > 0 && stack[1] == stack[0]) {
Austin Schuh745610d2015-09-06 18:19:50 -0700358 // in case of non-frame-pointer-based unwinding we will get
359 // duplicate of PC in stack[1], which we don't want
360 used_stack = stack + 1;
361 } else {
362 used_stack = stack;
363 depth++; // To account for pc value in stack[0];
364 }
365
366 instance->collector_.Add(depth, used_stack);
367 }
368}
369
370#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
371
372extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
373 ProfileHandlerRegisterThread();
374}
375
376extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
377 CpuProfiler::instance_.FlushTable();
378}
379
380extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
381 return CpuProfiler::instance_.Enabled();
382}
383
384extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
385 return CpuProfiler::instance_.Start(fname, NULL);
386}
387
388extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
389 const char *fname, const ProfilerOptions *options) {
390 return CpuProfiler::instance_.Start(fname, options);
391}
392
393extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
394 CpuProfiler::instance_.Stop();
395}
396
397extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
398 ProfilerState* state) {
399 CpuProfiler::instance_.GetCurrentState(state);
400}
401
Brian Silverman20350ac2021-11-17 18:19:55 -0800402extern "C" PERFTOOLS_DLL_DECL int ProfilerGetStackTrace(
403 void** result, int max_depth, int skip_count, const void *uc) {
404 return GetStackTraceWithContext(result, max_depth, skip_count, uc);
405}
406
Austin Schuh745610d2015-09-06 18:19:50 -0700407#else // OS_CYGWIN
408
409// ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
410// work as well for profiling, and also interferes with alarm(). Because of
411// these issues, unless a specific need is identified, profiler support is
412// disabled under Cygwin.
413extern "C" void ProfilerRegisterThread() { }
414extern "C" void ProfilerFlush() { }
415extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
416extern "C" int ProfilerStart(const char* fname) { return 0; }
417extern "C" int ProfilerStartWithOptions(const char *fname,
418 const ProfilerOptions *options) {
419 return 0;
420}
421extern "C" void ProfilerStop() { }
422extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
423 memset(state, 0, sizeof(*state));
424}
Brian Silverman20350ac2021-11-17 18:19:55 -0800425extern "C" int ProfilerGetStackTrace(
426 void** result, int max_depth, int skip_count, const void *uc) {
427 return 0;
428}
Austin Schuh745610d2015-09-06 18:19:50 -0700429
430#endif // OS_CYGWIN
431
432// DEPRECATED routines
433extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
434extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }