1// Copyright (c) 2005, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Sanjay Ghemawat
32//         Chris Demetriou (refactoring)
33//
34// Profile current program by sampling stack-trace every so often
35
36#include "config.h"
37#include "getpc.h"      // should be first to get the _GNU_SOURCE dfn
38#include <signal.h>
39#include <assert.h>
40#include <stdio.h>
41#include <errno.h>
42#include <string.h>
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>  // for getpid()
45#endif
46#if defined(HAVE_SYS_UCONTEXT_H)
47#include <sys/ucontext.h>
48#elif defined(HAVE_UCONTEXT_H)
49#include <ucontext.h>
50#elif defined(HAVE_CYGWIN_SIGNAL_H)
51#include <cygwin/signal.h>
52typedef ucontext ucontext_t;
53#else
54typedef int ucontext_t;   // just to quiet the compiler, mostly
55#endif
56#include <sys/time.h>
57#include <string>
58#include <gperftools/profiler.h>
59#include <gperftools/stacktrace.h>
60#include "base/commandlineflags.h"
61#include "base/logging.h"
62#include "base/googleinit.h"
63#include "base/spinlock.h"
64#include "base/sysinfo.h"             /* for GetUniquePathFromEnv, etc */
65#include "profiledata.h"
66#include "profile-handler.h"
67#ifdef HAVE_CONFLICT_SIGNAL_H
68#include "conflict-signal.h"          /* used on msvc machines */
69#endif
70
71using std::string;
72
73// Collects up all profile data.  This is a singleton, which is
74// initialized by a constructor at startup.
75class CpuProfiler {
76 public:
77  CpuProfiler();
78  ~CpuProfiler();
79
80  // Start profiler to write profile info into fname
81  bool Start(const char* fname, const ProfilerOptions* options);
82
83  // Stop profiling and write the data to disk.
84  void Stop();
85
86  // Write the data to disk (and continue profiling).
87  void FlushTable();
88
89  bool Enabled();
90
91  void GetCurrentState(ProfilerState* state);
92
93  static CpuProfiler instance_;
94
95 private:
96  // This lock implements the locking requirements described in the ProfileData
97  // documentation, specifically:
98  //
99  // lock_ is held all over all collector_ method calls except for the 'Add'
100  // call made from the signal handler, to protect against concurrent use of
101  // collector_'s control routines. Code other than signal handler must
102  // unregister the signal handler before calling any collector_ method.
103  // 'Add' method in the collector is protected by a guarantee from
104  // ProfileHandle that only one instance of prof_handler can run at a time.
105  SpinLock      lock_;
106  ProfileData   collector_;
107
108  // Filter function and its argument, if any.  (NULL means include all
109  // samples).  Set at start, read-only while running.  Written while holding
110  // lock_, read and executed in the context of SIGPROF interrupt.
111  int           (*filter_)(void*);
112  void*         filter_arg_;
113
114  // Opaque token returned by the profile handler. To be used when calling
115  // ProfileHandlerUnregisterCallback.
116  ProfileHandlerToken* prof_handler_token_;
117
118  // Sets up a callback to receive SIGPROF interrupt.
119  void EnableHandler();
120
121  // Disables receiving SIGPROF interrupt.
122  void DisableHandler();
123
124  // Signal handler that records the interrupted pc in the profile data.
125  static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
126                           void* cpu_profiler);
127};
128
129// Profile data structure singleton: Constructor will check to see if
130// profiling should be enabled.  Destructor will write profile data
131// out to disk.
132CpuProfiler CpuProfiler::instance_;
133
134// Initialize profiling: activated if getenv("CPUPROFILE") exists.
135CpuProfiler::CpuProfiler()
136    : prof_handler_token_(NULL) {
137  // TODO(cgd) Move this code *out* of the CpuProfile constructor into a
138  // separate object responsible for initialization. With ProfileHandler there
139  // is no need to limit the number of profilers.
140  char fname[PATH_MAX];
141  if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
142    return;
143  }
144  // We don't enable profiling if setuid -- it's a security risk
145#ifdef HAVE_GETEUID
146  if (getuid() != geteuid())
147    return;
148#endif
149
150  if (!Start(fname, NULL)) {
151    RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
152            fname, strerror(errno));
153  }
154}
155
156bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
157  SpinLockHolder cl(&lock_);
158
159  if (collector_.enabled()) {
160    return false;
161  }
162
163  ProfileHandlerState prof_handler_state;
164  ProfileHandlerGetState(&prof_handler_state);
165
166  ProfileData::Options collector_options;
167  collector_options.set_frequency(prof_handler_state.frequency);
168  if (!collector_.Start(fname, collector_options)) {
169    return false;
170  }
171
172  filter_ = NULL;
173  if (options != NULL && options->filter_in_thread != NULL) {
174    filter_ = options->filter_in_thread;
175    filter_arg_ = options->filter_in_thread_arg;
176  }
177
178  // Setup handler for SIGPROF interrupts
179  EnableHandler();
180
181  return true;
182}
183
184CpuProfiler::~CpuProfiler() {
185  Stop();
186}
187
188// Stop profiling and write out any collected profile data
189void CpuProfiler::Stop() {
190  SpinLockHolder cl(&lock_);
191
192  if (!collector_.enabled()) {
193    return;
194  }
195
196  // Unregister prof_handler to stop receiving SIGPROF interrupts before
197  // stopping the collector.
198  DisableHandler();
199
200  // DisableHandler waits for the currently running callback to complete and
201  // guarantees no future invocations. It is safe to stop the collector.
202  collector_.Stop();
203}
204
205void CpuProfiler::FlushTable() {
206  SpinLockHolder cl(&lock_);
207
208  if (!collector_.enabled()) {
209    return;
210  }
211
212  // Unregister prof_handler to stop receiving SIGPROF interrupts before
213  // flushing the profile data.
214  DisableHandler();
215
216  // DisableHandler waits for the currently running callback to complete and
217  // guarantees no future invocations. It is safe to flush the profile data.
218  collector_.FlushTable();
219
220  EnableHandler();
221}
222
223bool CpuProfiler::Enabled() {
224  SpinLockHolder cl(&lock_);
225  return collector_.enabled();
226}
227
228void CpuProfiler::GetCurrentState(ProfilerState* state) {
229  ProfileData::State collector_state;
230  {
231    SpinLockHolder cl(&lock_);
232    collector_.GetCurrentState(&collector_state);
233  }
234
235  state->enabled = collector_state.enabled;
236  state->start_time = static_cast<time_t>(collector_state.start_time);
237  state->samples_gathered = collector_state.samples_gathered;
238  int buf_size = sizeof(state->profile_name);
239  strncpy(state->profile_name, collector_state.profile_name, buf_size);
240  state->profile_name[buf_size-1] = '\0';
241}
242
243void CpuProfiler::EnableHandler() {
244  RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
245  prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
246  RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
247}
248
249void CpuProfiler::DisableHandler() {
250  RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
251  ProfileHandlerUnregisterCallback(prof_handler_token_);
252  prof_handler_token_ = NULL;
253}
254
255// Signal handler that records the pc in the profile-data structure. We do no
256// synchronization here.  profile-handler.cc guarantees that at most one
257// instance of prof_handler() will run at a time. All other routines that
258// access the data touched by prof_handler() disable this signal handler before
259// accessing the data and therefore cannot execute concurrently with
260// prof_handler().
261void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
262                               void* cpu_profiler) {
263  CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
264
265  if (instance->filter_ == NULL ||
266      (*instance->filter_)(instance->filter_arg_)) {
267    void* stack[ProfileData::kMaxStackDepth];
268
269    // The top-most active routine doesn't show up as a normal
270    // frame, but as the "pc" value in the signal handler context.
271    stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
272
273    // We skip the top two stack trace entries (this function and one
274    // signal handler frame) since they are artifacts of profiling and
275    // should not be measured.  Other profiling related frames may be
276    // removed by "pprof" at analysis time.  Instead of skipping the top
277    // frames, we could skip nothing, but that would increase the
278    // profile size unnecessarily.
279    int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
280                                         2, signal_ucontext);
281    depth++;  // To account for pc value in stack[0];
282
283    instance->collector_.Add(depth, stack);
284  }
285}
286
287#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
288
289extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
290  ProfileHandlerRegisterThread();
291}
292
293extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
294  CpuProfiler::instance_.FlushTable();
295}
296
297extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
298  return CpuProfiler::instance_.Enabled();
299}
300
301extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
302  return CpuProfiler::instance_.Start(fname, NULL);
303}
304
305extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
306    const char *fname, const ProfilerOptions *options) {
307  return CpuProfiler::instance_.Start(fname, options);
308}
309
310extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
311  CpuProfiler::instance_.Stop();
312}
313
314extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
315    ProfilerState* state) {
316  CpuProfiler::instance_.GetCurrentState(state);
317}
318
319#else  // OS_CYGWIN
320
321// ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
322// work as well for profiling, and also interferes with alarm().  Because of
323// these issues, unless a specific need is identified, profiler support is
324// disabled under Cygwin.
325extern "C" void ProfilerRegisterThread() { }
326extern "C" void ProfilerFlush() { }
327extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
328extern "C" int ProfilerStart(const char* fname) { return 0; }
329extern "C" int ProfilerStartWithOptions(const char *fname,
330                                        const ProfilerOptions *options) {
331  return 0;
332}
333extern "C" void ProfilerStop() { }
334extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
335  memset(state, 0, sizeof(*state));
336}
337
338#endif  // OS_CYGWIN
339
340// DEPRECATED routines
341extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
342extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
343