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#elif defined(__ANDROID__)
54// Do not define ucontext_t here.
55#else
56typedef int ucontext_t;   // just to quiet the compiler, mostly
57#endif
58#include <sys/time.h>
59#include <string>
60#include <gperftools/profiler.h>
61#include <gperftools/stacktrace.h>
62#include "base/commandlineflags.h"
63#include "base/logging.h"
64#include "base/googleinit.h"
65#include "base/spinlock.h"
66#include "base/sysinfo.h"             /* for GetUniquePathFromEnv, etc */
67#include "profiledata.h"
68#include "profile-handler.h"
69#ifdef HAVE_CONFLICT_SIGNAL_H
70#include "conflict-signal.h"          /* used on msvc machines */
71#endif
72
73using std::string;
74
75// Collects up all profile data.  This is a singleton, which is
76// initialized by a constructor at startup.
77class CpuProfiler {
78 public:
79  CpuProfiler();
80  ~CpuProfiler();
81
82  // Start profiler to write profile info into fname
83  bool Start(const char* fname, const ProfilerOptions* options);
84
85  // Stop profiling and write the data to disk.
86  void Stop();
87
88  // Write the data to disk (and continue profiling).
89  void FlushTable();
90
91  bool Enabled();
92
93  void GetCurrentState(ProfilerState* state);
94
95  static CpuProfiler instance_;
96
97 private:
98  // This lock implements the locking requirements described in the ProfileData
99  // documentation, specifically:
100  //
101  // lock_ is held all over all collector_ method calls except for the 'Add'
102  // call made from the signal handler, to protect against concurrent use of
103  // collector_'s control routines. Code other than signal handler must
104  // unregister the signal handler before calling any collector_ method.
105  // 'Add' method in the collector is protected by a guarantee from
106  // ProfileHandle that only one instance of prof_handler can run at a time.
107  SpinLock      lock_;
108  ProfileData   collector_;
109
110  // Filter function and its argument, if any.  (NULL means include all
111  // samples).  Set at start, read-only while running.  Written while holding
112  // lock_, read and executed in the context of SIGPROF interrupt.
113  int           (*filter_)(void*);
114  void*         filter_arg_;
115
116  // Opaque token returned by the profile handler. To be used when calling
117  // ProfileHandlerUnregisterCallback.
118  ProfileHandlerToken* prof_handler_token_;
119
120  // Sets up a callback to receive SIGPROF interrupt.
121  void EnableHandler();
122
123  // Disables receiving SIGPROF interrupt.
124  void DisableHandler();
125
126  // Signal handler that records the interrupted pc in the profile data.
127  static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
128                           void* cpu_profiler);
129};
130
131// Profile data structure singleton: Constructor will check to see if
132// profiling should be enabled.  Destructor will write profile data
133// out to disk.
134CpuProfiler CpuProfiler::instance_;
135
136// Initialize profiling: activated if getenv("CPUPROFILE") exists.
137CpuProfiler::CpuProfiler()
138    : prof_handler_token_(NULL) {
139  // TODO(cgd) Move this code *out* of the CpuProfile constructor into a
140  // separate object responsible for initialization. With ProfileHandler there
141  // is no need to limit the number of profilers.
142  char fname[PATH_MAX];
143  if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
144    return;
145  }
146  // We don't enable profiling if setuid -- it's a security risk
147#ifdef HAVE_GETEUID
148  if (getuid() != geteuid())
149    return;
150#endif
151
152  if (!Start(fname, NULL)) {
153    RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
154            fname, strerror(errno));
155  }
156}
157
158bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
159  SpinLockHolder cl(&lock_);
160
161  if (collector_.enabled()) {
162    return false;
163  }
164
165  ProfileHandlerState prof_handler_state;
166  ProfileHandlerGetState(&prof_handler_state);
167
168  ProfileData::Options collector_options;
169  collector_options.set_frequency(prof_handler_state.frequency);
170  if (!collector_.Start(fname, collector_options)) {
171    return false;
172  }
173
174  filter_ = NULL;
175  if (options != NULL && options->filter_in_thread != NULL) {
176    filter_ = options->filter_in_thread;
177    filter_arg_ = options->filter_in_thread_arg;
178  }
179
180  // Setup handler for SIGPROF interrupts
181  EnableHandler();
182
183  return true;
184}
185
186CpuProfiler::~CpuProfiler() {
187  Stop();
188}
189
190// Stop profiling and write out any collected profile data
191void CpuProfiler::Stop() {
192  SpinLockHolder cl(&lock_);
193
194  if (!collector_.enabled()) {
195    return;
196  }
197
198  // Unregister prof_handler to stop receiving SIGPROF interrupts before
199  // stopping the collector.
200  DisableHandler();
201
202  // DisableHandler waits for the currently running callback to complete and
203  // guarantees no future invocations. It is safe to stop the collector.
204  collector_.Stop();
205}
206
207void CpuProfiler::FlushTable() {
208  SpinLockHolder cl(&lock_);
209
210  if (!collector_.enabled()) {
211    return;
212  }
213
214  // Unregister prof_handler to stop receiving SIGPROF interrupts before
215  // flushing the profile data.
216  DisableHandler();
217
218  // DisableHandler waits for the currently running callback to complete and
219  // guarantees no future invocations. It is safe to flush the profile data.
220  collector_.FlushTable();
221
222  EnableHandler();
223}
224
225bool CpuProfiler::Enabled() {
226  SpinLockHolder cl(&lock_);
227  return collector_.enabled();
228}
229
230void CpuProfiler::GetCurrentState(ProfilerState* state) {
231  ProfileData::State collector_state;
232  {
233    SpinLockHolder cl(&lock_);
234    collector_.GetCurrentState(&collector_state);
235  }
236
237  state->enabled = collector_state.enabled;
238  state->start_time = static_cast<time_t>(collector_state.start_time);
239  state->samples_gathered = collector_state.samples_gathered;
240  int buf_size = sizeof(state->profile_name);
241  strncpy(state->profile_name, collector_state.profile_name, buf_size);
242  state->profile_name[buf_size-1] = '\0';
243}
244
245void CpuProfiler::EnableHandler() {
246  RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
247  prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
248  RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
249}
250
251void CpuProfiler::DisableHandler() {
252  RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
253  ProfileHandlerUnregisterCallback(prof_handler_token_);
254  prof_handler_token_ = NULL;
255}
256
257// Signal handler that records the pc in the profile-data structure. We do no
258// synchronization here.  profile-handler.cc guarantees that at most one
259// instance of prof_handler() will run at a time. All other routines that
260// access the data touched by prof_handler() disable this signal handler before
261// accessing the data and therefore cannot execute concurrently with
262// prof_handler().
263void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
264                               void* cpu_profiler) {
265  CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
266
267  if (instance->filter_ == NULL ||
268      (*instance->filter_)(instance->filter_arg_)) {
269    void* stack[ProfileData::kMaxStackDepth];
270
271    // The top-most active routine doesn't show up as a normal
272    // frame, but as the "pc" value in the signal handler context.
273    stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
274
275    // We skip the top two stack trace entries (this function and one
276    // signal handler frame) since they are artifacts of profiling and
277    // should not be measured.  Other profiling related frames may be
278    // removed by "pprof" at analysis time.  Instead of skipping the top
279    // frames, we could skip nothing, but that would increase the
280    // profile size unnecessarily.
281    int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
282                                         2, signal_ucontext);
283    depth++;  // To account for pc value in stack[0];
284
285    instance->collector_.Add(depth, stack);
286  }
287}
288
289#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
290
291extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
292  ProfileHandlerRegisterThread();
293}
294
295extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
296  CpuProfiler::instance_.FlushTable();
297}
298
299extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
300  return CpuProfiler::instance_.Enabled();
301}
302
303extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
304  return CpuProfiler::instance_.Start(fname, NULL);
305}
306
307extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
308    const char *fname, const ProfilerOptions *options) {
309  return CpuProfiler::instance_.Start(fname, options);
310}
311
312extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
313  CpuProfiler::instance_.Stop();
314}
315
316extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
317    ProfilerState* state) {
318  CpuProfiler::instance_.GetCurrentState(state);
319}
320
321#else  // OS_CYGWIN
322
323// ITIMER_PROF doesn't work under cygwin.  ITIMER_REAL is available, but doesn't
324// work as well for profiling, and also interferes with alarm().  Because of
325// these issues, unless a specific need is identified, profiler support is
326// disabled under Cygwin.
327extern "C" void ProfilerRegisterThread() { }
328extern "C" void ProfilerFlush() { }
329extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
330extern "C" int ProfilerStart(const char* fname) { return 0; }
331extern "C" int ProfilerStartWithOptions(const char *fname,
332                                        const ProfilerOptions *options) {
333  return 0;
334}
335extern "C" void ProfilerStop() { }
336extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
337  memset(state, 0, sizeof(*state));
338}
339
340#endif  // OS_CYGWIN
341
342// DEPRECATED routines
343extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
344extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }
345