This source file includes following definitions.
- Init
- Instance
- timer_sharing_
- RegisterThread
- RegisterCallback
- UnregisterCallback
- Reset
- GetState
- StartTimer
- StopTimer
- IsTimerRunning
- EnableHandler
- DisableHandler
- IsSignalHandlerAvailable
- SignalHandler
- ProfileHandlerRegisterThread
- ProfileHandlerRegisterCallback
- ProfileHandlerUnregisterCallback
- ProfileHandlerReset
- ProfileHandlerGetState
- ProfileHandlerRegisterThread
- ProfileHandlerRegisterCallback
- ProfileHandlerUnregisterCallback
- ProfileHandlerReset
- ProfileHandlerGetState
#include "config.h"
#include "profile-handler.h"
#if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <list>
#include <string>
#include "base/dynamic_annotations.h"
#include "base/googleinit.h"
#include "base/logging.h"
#include "base/spinlock.h"
#include "maybe_threads.h"
using std::list;
using std::string;
struct ProfileHandlerToken {
ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg)
: callback(cb),
callback_arg(cb_arg) {
}
ProfileHandlerCallback callback;
void* callback_arg;
};
class ProfileHandler {
public:
void RegisterThread();
ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback,
void* callback_arg);
void UnregisterCallback(ProfileHandlerToken* token)
NO_THREAD_SAFETY_ANALYSIS;
void Reset();
void GetState(ProfileHandlerState* state);
static ProfileHandler* Instance();
private:
ProfileHandler();
~ProfileHandler();
static const int32 kMaxFrequency = 4000;
static const int32 kDefaultFrequency = 100;
static ProfileHandler* instance_;
static pthread_once_t once_;
static void Init();
int64 interrupts_ GUARDED_BY(signal_lock_);
int32 frequency_;
int timer_type_;
int32 callback_count_ GUARDED_BY(control_lock_);
bool allowed_;
enum {
TIMERS_UNTOUCHED,
TIMERS_ONE_SET,
TIMERS_SHARED,
TIMERS_SEPARATE
} timer_sharing_ GUARDED_BY(control_lock_);
SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_);
SpinLock signal_lock_;
typedef list<ProfileHandlerToken*> CallbackList;
typedef CallbackList::iterator CallbackIterator;
CallbackList callbacks_ GUARDED_BY(signal_lock_);
void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
bool IsSignalHandlerAvailable();
static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext);
DISALLOW_COPY_AND_ASSIGN(ProfileHandler);
};
ProfileHandler* ProfileHandler::instance_ = NULL;
pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT;
const int32 ProfileHandler::kMaxFrequency;
const int32 ProfileHandler::kDefaultFrequency;
extern "C" int pthread_once(pthread_once_t *, void (*)(void))
ATTRIBUTE_WEAK;
void ProfileHandler::Init() {
instance_ = new ProfileHandler();
}
ProfileHandler* ProfileHandler::Instance() {
if (pthread_once) {
pthread_once(&once_, Init);
}
if (instance_ == NULL) {
Init();
assert(instance_ != NULL);
}
return instance_;
}
ProfileHandler::ProfileHandler()
: interrupts_(0),
callback_count_(0),
allowed_(true),
timer_sharing_(TIMERS_UNTOUCHED) {
SpinLockHolder cl(&control_lock_);
timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
char junk;
const char* fr = getenv("CPUPROFILE_FREQUENCY");
if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) &&
(frequency_ > 0)) {
frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_;
} else {
frequency_ = kDefaultFrequency;
}
if (!allowed_) {
return;
}
if (!IsSignalHandlerAvailable()) {
RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.",
timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF");
allowed_ = false;
return;
}
DisableHandler();
}
ProfileHandler::~ProfileHandler() {
Reset();
}
void ProfileHandler::RegisterThread() {
SpinLockHolder cl(&control_lock_);
if (!allowed_) {
return;
}
switch (timer_sharing_) {
case TIMERS_UNTOUCHED:
StartTimer();
timer_sharing_ = TIMERS_ONE_SET;
break;
case TIMERS_ONE_SET:
if (IsTimerRunning()) {
timer_sharing_ = TIMERS_SHARED;
if (callback_count_ == 0) {
StopTimer();
}
} else {
timer_sharing_ = TIMERS_SEPARATE;
StartTimer();
}
break;
case TIMERS_SHARED:
break;
case TIMERS_SEPARATE:
StartTimer();
break;
}
}
ProfileHandlerToken* ProfileHandler::RegisterCallback(
ProfileHandlerCallback callback, void* callback_arg) {
ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg);
SpinLockHolder cl(&control_lock_);
DisableHandler();
{
SpinLockHolder sl(&signal_lock_);
callbacks_.push_back(token);
}
if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) {
StartTimer();
}
++callback_count_;
EnableHandler();
return token;
}
void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) {
SpinLockHolder cl(&control_lock_);
for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end();
++it) {
if ((*it) == token) {
RAW_CHECK(callback_count_ > 0, "Invalid callback count");
DisableHandler();
{
SpinLockHolder sl(&signal_lock_);
delete *it;
callbacks_.erase(it);
}
--callback_count_;
if (callback_count_ > 0) {
EnableHandler();
} else if (timer_sharing_ == TIMERS_SHARED) {
StopTimer();
}
return;
}
}
RAW_LOG(FATAL, "Invalid token");
}
void ProfileHandler::Reset() {
SpinLockHolder cl(&control_lock_);
DisableHandler();
{
SpinLockHolder sl(&signal_lock_);
CallbackIterator it = callbacks_.begin();
while (it != callbacks_.end()) {
CallbackIterator tmp = it;
++it;
delete *tmp;
callbacks_.erase(tmp);
}
}
callback_count_ = 0;
if (timer_sharing_ == TIMERS_SHARED) {
StopTimer();
}
timer_sharing_ = TIMERS_UNTOUCHED;
}
void ProfileHandler::GetState(ProfileHandlerState* state) {
SpinLockHolder cl(&control_lock_);
DisableHandler();
{
SpinLockHolder sl(&signal_lock_);
state->interrupts = interrupts_;
}
if (callback_count_ > 0) {
EnableHandler();
}
state->frequency = frequency_;
state->callback_count = callback_count_;
state->allowed = allowed_;
}
void ProfileHandler::StartTimer() {
if (!allowed_) {
return;
}
struct itimerval timer;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 1000000 / frequency_;
timer.it_value = timer.it_interval;
setitimer(timer_type_, &timer, 0);
}
void ProfileHandler::StopTimer() {
if (!allowed_) {
return;
}
struct itimerval timer;
memset(&timer, 0, sizeof timer);
setitimer(timer_type_, &timer, 0);
}
bool ProfileHandler::IsTimerRunning() {
if (!allowed_) {
return false;
}
struct itimerval current_timer;
RAW_CHECK(0 == getitimer(timer_type_, ¤t_timer), "getitimer");
return (current_timer.it_value.tv_sec != 0 ||
current_timer.it_value.tv_usec != 0);
}
void ProfileHandler::EnableHandler() {
if (!allowed_) {
return;
}
struct sigaction sa;
sa.sa_sigaction = SignalHandler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&sa.sa_mask);
const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)");
}
void ProfileHandler::DisableHandler() {
if (!allowed_) {
return;
}
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)");
}
bool ProfileHandler::IsSignalHandlerAvailable() {
struct sigaction sa;
const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail");
return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL;
}
void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) {
int saved_errno = errno;
ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_);
RAW_CHECK(instance != NULL, "ProfileHandler is not initialized");
{
SpinLockHolder sl(&instance->signal_lock_);
++instance->interrupts_;
for (CallbackIterator it = instance->callbacks_.begin();
it != instance->callbacks_.end();
++it) {
(*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg);
}
}
errno = saved_errno;
}
REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread());
extern "C" void ProfileHandlerRegisterThread() {
ProfileHandler::Instance()->RegisterThread();
}
extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
ProfileHandlerCallback callback, void* callback_arg) {
return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg);
}
extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
ProfileHandler::Instance()->UnregisterCallback(token);
}
extern "C" void ProfileHandlerReset() {
return ProfileHandler::Instance()->Reset();
}
extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
ProfileHandler::Instance()->GetState(state);
}
#else
extern "C" void ProfileHandlerRegisterThread() {
}
extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
ProfileHandlerCallback callback, void* callback_arg) {
return NULL;
}
extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
}
extern "C" void ProfileHandlerReset() {
}
extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
}
#endif