summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick LoPresti <lopresti@gmail.com>2015-05-25 11:56:51 -0700
committerAliaksey Kandratsenka <alk@tut.by>2015-05-30 10:25:42 -0700
commit019362fefcdca39a46d1a831ed46266c24b9a273 (patch)
treef7c9d9a429b0aa77c4d28788de3ede2e310f84ca
parent81d8d2a9e7f941a2051781fd0fe62c683c32f1ef (diff)
downloadgperftools-019362fefcdca39a46d1a831ed46266c24b9a273.tar.gz
Add support for CPUPROFILE_TIMER_SIGNAL environment variable.
Which both enables per-thread timers and allows the signal number for the timer to be selected. [alk@tut.by: reformatted commit message for subject line length] Signed-off-by: Aliaksey Kandratsenka <alk@tut.by>
-rw-r--r--src/profile-handler.cc58
-rw-r--r--src/tests/profile-handler_unittest.cc5
2 files changed, 40 insertions, 23 deletions
diff --git a/src/profile-handler.cc b/src/profile-handler.cc
index 1518ed4..66c9d74 100644
--- a/src/profile-handler.cc
+++ b/src/profile-handler.cc
@@ -147,6 +147,9 @@ class ProfileHandler {
// ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM)
int timer_type_;
+ // Signal number for timer signal.
+ int signal_number_;
+
// Counts the number of callbacks registered.
int32 callback_count_ GUARDED_BY(control_lock_);
@@ -286,7 +289,8 @@ static void CreateThreadTimerKey(pthread_key_t *pkey) {
}
}
-static void StartLinuxThreadTimer(int timer_type, int32 frequency, pthread_key_t timer_key) {
+static void StartLinuxThreadTimer(int timer_type, int signal_number,
+ int32 frequency, pthread_key_t timer_key) {
int rv;
struct sigevent sevp;
timer_t timerid;
@@ -294,7 +298,6 @@ static void StartLinuxThreadTimer(int timer_type, int32 frequency, pthread_key_t
memset(&sevp, 0, sizeof(sevp));
sevp.sigev_notify = SIGEV_THREAD_ID;
sevp._sigev_un._tid = sys_gettid();
- const int signal_number = (timer_type == ITIMER_PROF ? SIGPROF : SIGALRM);
sevp.sigev_signo = signal_number;
clockid_t clock = CLOCK_THREAD_CPUTIME_ID;
if (timer_type == ITIMER_REAL) {
@@ -348,6 +351,7 @@ ProfileHandler::ProfileHandler()
SpinLockHolder cl(&control_lock_);
timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
+ signal_number_ = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
// Get frequency of interrupts (if specified)
char junk;
@@ -364,32 +368,43 @@ ProfileHandler::ProfileHandler()
return;
}
- // If something else is using the signal handler,
- // assume it has priority over us and stop.
- if (!IsSignalHandlerAvailable()) {
- RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.",
- timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF");
- allowed_ = false;
- return;
- }
+#if HAVE_LINUX_SIGEV_THREAD_ID
+ // Do this early because we might be overriding signal number.
- // Ignore signals until we decide to turn profiling on. (Paranoia;
- // should already be ignored.)
- DisableHandler();
+ const char *per_thread = getenv("CPUPROFILE_PER_THREAD_TIMERS");
+ const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
-#if HAVE_LINUX_SIGEV_THREAD_ID
- if (getenv("CPUPROFILE_PER_THREAD_TIMERS")) {
+ if (per_thread || signal_number) {
if (timer_create && pthread_once) {
timer_sharing_ = TIMERS_SEPARATE;
CreateThreadTimerKey(&thread_timer_key);
per_thread_timer_enabled_ = true;
+ // Override signal number if requested.
+ if (signal_number) {
+ signal_number_ = strtol(signal_number, NULL, 0);
+ }
} else {
RAW_LOG(INFO,
- "Not enabling linux-per-thread-timers mode due to lack of timer_create."
+ "Ignoring CPUPROFILE_PER_THREAD_TIMERS and\n"
+ " CPUPROFILE_TIMER_SIGNAL due to lack of timer_create().\n"
" Preload or link to librt.so for this to work");
}
}
#endif
+
+ // If something else is using the signal handler,
+ // assume it has priority over us and stop.
+ if (!IsSignalHandlerAvailable()) {
+ RAW_LOG(INFO, "Disabling profiler because signal %d handler is already in use.",
+ signal_number_);
+ allowed_ = false;
+ return;
+ }
+
+ // Ignore signals until we decide to turn profiling on. (Paranoia;
+ // should already be ignored.)
+ DisableHandler();
+
}
ProfileHandler::~ProfileHandler() {
@@ -538,7 +553,7 @@ void ProfileHandler::StartTimer() {
#if HAVE_LINUX_SIGEV_THREAD_ID
if (per_thread_timer_enabled_) {
- StartLinuxThreadTimer(timer_type_, frequency_, thread_timer_key);
+ StartLinuxThreadTimer(timer_type_, signal_number_, frequency_, thread_timer_key);
return;
}
#endif
@@ -584,8 +599,7 @@ void ProfileHandler::EnableHandler() {
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)");
+ RAW_CHECK(sigaction(signal_number_, &sa, NULL) == 0, "sigprof (enable)");
}
void ProfileHandler::DisableHandler() {
@@ -596,14 +610,12 @@ void ProfileHandler::DisableHandler() {
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)");
+ 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");
+ RAW_CHECK(sigaction(signal_number_, NULL, &sa) == 0, "is-signal-handler avail");
// We only take over the handler if the current one is unset.
// It must be SIG_IGN or SIG_DFL, not some other function.
diff --git a/src/tests/profile-handler_unittest.cc b/src/tests/profile-handler_unittest.cc
index e49d23e..72a4640 100644
--- a/src/tests/profile-handler_unittest.cc
+++ b/src/tests/profile-handler_unittest.cc
@@ -212,6 +212,11 @@ class ProfileHandlerTest {
timer_separate_ = threads_have_separate_timers();
#if HAVE_LINUX_SIGEV_THREAD_ID
linux_per_thread_timers_mode_ = (getenv("CPUPROFILE_PER_THREAD_TIMERS") != NULL);
+ const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
+ if (signal_number) {
+ signal_number_ = strtol(signal_number, NULL, 0);
+ linux_per_thread_timers_mode_ = true;
+ }
#endif
Delay(kTimerResetInterval);
}