This source file includes following definitions.
- Start
- Stop
- FlushTable
- Enabled
- GetCurrentState
- EnableHandler
- DisableHandler
- prof_handler
- ProfilerRegisterThread
- ProfilerFlush
- ProfilingIsEnabledForAllThreads
- ProfilerStart
- ProfilerStartWithOptions
- ProfilerStop
- ProfilerGetCurrentState
- ProfilerRegisterThread
- ProfilerFlush
- ProfilingIsEnabledForAllThreads
- ProfilerStart
- ProfilerStartWithOptions
- ProfilerStop
- ProfilerGetCurrentState
- ProfilerEnable
- ProfilerDisable
#include "config.h"
#include "getpc.h"
#include <signal.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined(HAVE_SYS_UCONTEXT_H)
#include <sys/ucontext.h>
#elif defined(HAVE_UCONTEXT_H)
#include <ucontext.h>
#elif defined(HAVE_CYGWIN_SIGNAL_H)
#include <cygwin/signal.h>
typedef ucontext ucontext_t;
#else
typedef int ucontext_t;
#endif
#include <sys/time.h>
#include <string>
#include <gperftools/profiler.h>
#include <gperftools/stacktrace.h>
#include "base/commandlineflags.h"
#include "base/logging.h"
#include "base/googleinit.h"
#include "base/spinlock.h"
#include "base/sysinfo.h"
#include "profiledata.h"
#include "profile-handler.h"
#ifdef HAVE_CONFLICT_SIGNAL_H
#include "conflict-signal.h"
#endif
using std::string;
class CpuProfiler {
public:
CpuProfiler();
~CpuProfiler();
bool Start(const char* fname, const ProfilerOptions* options);
void Stop();
void FlushTable();
bool Enabled();
void GetCurrentState(ProfilerState* state);
static CpuProfiler instance_;
private:
SpinLock lock_;
ProfileData collector_;
int (*filter_)(void*);
void* filter_arg_;
ProfileHandlerToken* prof_handler_token_;
void EnableHandler();
void DisableHandler();
static void prof_handler(int sig, siginfo_t*, void* signal_ucontext,
void* cpu_profiler);
};
CpuProfiler CpuProfiler::instance_;
CpuProfiler::CpuProfiler()
: prof_handler_token_(NULL) {
char fname[PATH_MAX];
if (!GetUniquePathFromEnv("CPUPROFILE", fname)) {
return;
}
#ifdef HAVE_GETEUID
if (getuid() != geteuid())
return;
#endif
if (!Start(fname, NULL)) {
RAW_LOG(FATAL, "Can't turn on cpu profiling for '%s': %s\n",
fname, strerror(errno));
}
}
bool CpuProfiler::Start(const char* fname, const ProfilerOptions* options) {
SpinLockHolder cl(&lock_);
if (collector_.enabled()) {
return false;
}
ProfileHandlerState prof_handler_state;
ProfileHandlerGetState(&prof_handler_state);
ProfileData::Options collector_options;
collector_options.set_frequency(prof_handler_state.frequency);
if (!collector_.Start(fname, collector_options)) {
return false;
}
filter_ = NULL;
if (options != NULL && options->filter_in_thread != NULL) {
filter_ = options->filter_in_thread;
filter_arg_ = options->filter_in_thread_arg;
}
EnableHandler();
return true;
}
CpuProfiler::~CpuProfiler() {
Stop();
}
void CpuProfiler::Stop() {
SpinLockHolder cl(&lock_);
if (!collector_.enabled()) {
return;
}
DisableHandler();
collector_.Stop();
}
void CpuProfiler::FlushTable() {
SpinLockHolder cl(&lock_);
if (!collector_.enabled()) {
return;
}
DisableHandler();
collector_.FlushTable();
EnableHandler();
}
bool CpuProfiler::Enabled() {
SpinLockHolder cl(&lock_);
return collector_.enabled();
}
void CpuProfiler::GetCurrentState(ProfilerState* state) {
ProfileData::State collector_state;
{
SpinLockHolder cl(&lock_);
collector_.GetCurrentState(&collector_state);
}
state->enabled = collector_state.enabled;
state->start_time = static_cast<time_t>(collector_state.start_time);
state->samples_gathered = collector_state.samples_gathered;
int buf_size = sizeof(state->profile_name);
strncpy(state->profile_name, collector_state.profile_name, buf_size);
state->profile_name[buf_size-1] = '\0';
}
void CpuProfiler::EnableHandler() {
RAW_CHECK(prof_handler_token_ == NULL, "SIGPROF handler already registered");
prof_handler_token_ = ProfileHandlerRegisterCallback(prof_handler, this);
RAW_CHECK(prof_handler_token_ != NULL, "Failed to set up SIGPROF handler");
}
void CpuProfiler::DisableHandler() {
RAW_CHECK(prof_handler_token_ != NULL, "SIGPROF handler is not registered");
ProfileHandlerUnregisterCallback(prof_handler_token_);
prof_handler_token_ = NULL;
}
void CpuProfiler::prof_handler(int sig, siginfo_t*, void* signal_ucontext,
void* cpu_profiler) {
CpuProfiler* instance = static_cast<CpuProfiler*>(cpu_profiler);
if (instance->filter_ == NULL ||
(*instance->filter_)(instance->filter_arg_)) {
void* stack[ProfileData::kMaxStackDepth];
stack[0] = GetPC(*reinterpret_cast<ucontext_t*>(signal_ucontext));
int depth = GetStackTraceWithContext(stack + 1, arraysize(stack) - 1,
2, signal_ucontext);
depth++;
instance->collector_.Add(depth, stack);
}
}
#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
extern "C" PERFTOOLS_DLL_DECL void ProfilerRegisterThread() {
ProfileHandlerRegisterThread();
}
extern "C" PERFTOOLS_DLL_DECL void ProfilerFlush() {
CpuProfiler::instance_.FlushTable();
}
extern "C" PERFTOOLS_DLL_DECL int ProfilingIsEnabledForAllThreads() {
return CpuProfiler::instance_.Enabled();
}
extern "C" PERFTOOLS_DLL_DECL int ProfilerStart(const char* fname) {
return CpuProfiler::instance_.Start(fname, NULL);
}
extern "C" PERFTOOLS_DLL_DECL int ProfilerStartWithOptions(
const char *fname, const ProfilerOptions *options) {
return CpuProfiler::instance_.Start(fname, options);
}
extern "C" PERFTOOLS_DLL_DECL void ProfilerStop() {
CpuProfiler::instance_.Stop();
}
extern "C" PERFTOOLS_DLL_DECL void ProfilerGetCurrentState(
ProfilerState* state) {
CpuProfiler::instance_.GetCurrentState(state);
}
#else
extern "C" void ProfilerRegisterThread() { }
extern "C" void ProfilerFlush() { }
extern "C" int ProfilingIsEnabledForAllThreads() { return 0; }
extern "C" int ProfilerStart(const char* fname) { return 0; }
extern "C" int ProfilerStartWithOptions(const char *fname,
const ProfilerOptions *options) {
return 0;
}
extern "C" void ProfilerStop() { }
extern "C" void ProfilerGetCurrentState(ProfilerState* state) {
memset(state, 0, sizeof(*state));
}
#endif
extern "C" PERFTOOLS_DLL_DECL void ProfilerEnable() { }
extern "C" PERFTOOLS_DLL_DECL void ProfilerDisable() { }