Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: third_party/tcmalloc/chromium/src/profile-handler.cc

Issue 9416072: Fix gperftools to not arm the profiling timer by default. Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009, Google Inc. 1 // Copyright (c) 2009, Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 20 matching lines...) Expand all
31 // Author: Sanjay Ghemawat 31 // Author: Sanjay Ghemawat
32 // Nabeel Mian 32 // Nabeel Mian
33 // 33 //
34 // Implements management of profile timers and the corresponding signal handler. 34 // Implements management of profile timers and the corresponding signal handler.
35 35
36 #include "config.h" 36 #include "config.h"
37 #include "profile-handler.h" 37 #include "profile-handler.h"
38 38
39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__)) 39 #if !(defined(__CYGWIN__) || defined(__CYGWIN32__))
40 40
41 #include <errno.h>
41 #include <stdio.h> 42 #include <stdio.h>
42 #include <errno.h>
43 #include <sys/time.h> 43 #include <sys/time.h>
44 44
45 #include <list> 45 #include <list>
46 #include <map>
46 #include <string> 47 #include <string>
47 48
48 #include "base/dynamic_annotations.h" 49 #include "base/dynamic_annotations.h"
49 #include "base/googleinit.h" 50 #include "base/googleinit.h"
50 #include "base/logging.h" 51 #include "base/logging.h"
51 #include "base/spinlock.h" 52 #include "base/spinlock.h"
52 #include "maybe_threads.h" 53 #include "maybe_threads.h"
53 54
54 using std::list; 55 using std::list;
56 using std::map;
55 using std::string; 57 using std::string;
56 58
57 // This structure is used by ProfileHandlerRegisterCallback and 59 // This structure is used by ProfileHandlerRegisterCallback and
58 // ProfileHandlerUnregisterCallback as a handle to a registered callback. 60 // ProfileHandlerUnregisterCallback as a handle to a registered callback.
59 struct ProfileHandlerToken { 61 struct ProfileHandlerToken {
60 // Sets the callback and associated arg. 62 // Sets the callback and associated arg.
61 ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg) 63 ProfileHandlerToken(ProfileHandlerCallback cb, void* cb_arg)
62 : callback(cb), 64 : callback(cb),
63 callback_arg(cb_arg) { 65 callback_arg(cb_arg) {
64 } 66 }
65 67
66 // Callback function to be invoked on receiving a profile timer interrupt. 68 // Callback function to be invoked on receiving a profile timer interrupt.
67 ProfileHandlerCallback callback; 69 ProfileHandlerCallback callback;
68 // Argument for the callback function. 70 // Argument for the callback function.
69 void* callback_arg; 71 void* callback_arg;
70 }; 72 };
71 73
74 // Blocks a signal from being delivered to the current thread while the object
75 // is alive. Restores previous state upon destruction.
76 class ScopedSignalBlocker {
77 public:
78 ScopedSignalBlocker(int signo) {
79 sigemptyset(&sig_set_);
80 sigaddset(&sig_set_, signo);
81 RAW_CHECK(sigprocmask(SIG_BLOCK, &sig_set_, NULL) == 0,
82 "sigprocmask (block)");
83 }
84 ~ScopedSignalBlocker() {
85 RAW_CHECK(sigprocmask(SIG_UNBLOCK, &sig_set_, NULL) == 0,
86 "sigprocmask (unblock)");
87 }
88
89 private:
90 sigset_t sig_set_;
91 };
92
72 // This class manages profile timers and associated signal handler. This is a 93 // This class manages profile timers and associated signal handler. This is a
73 // a singleton. 94 // a singleton.
74 class ProfileHandler { 95 class ProfileHandler {
75 public: 96 public:
76 // Registers the current thread with the profile handler. On systems which 97 // Registers the current thread with the profile handler.
77 // have a separate interval timer for each thread, this function starts the
78 // timer for the current thread.
79 //
80 // The function also attempts to determine whether or not timers are shared by
81 // all threads in the process. (With LinuxThreads, and with NPTL on some
82 // Linux kernel versions, each thread has separate timers.)
83 //
84 // Prior to determining whether timers are shared, this function will
85 // unconditionally start the timer. However, if this function determines
86 // that timers are shared, then it will stop the timer if no callbacks are
87 // currently registered.
88 void RegisterThread(); 98 void RegisterThread();
89 99
100 // Unregisters the current thread with the profile handler.
101 void UnregisterThread();
102
90 // Registers a callback routine to receive profile timer ticks. The returned 103 // Registers a callback routine to receive profile timer ticks. The returned
91 // token is to be used when unregistering this callback and must not be 104 // token is to be used when unregistering this callback and must not be
92 // deleted by the caller. Registration of the first callback enables the 105 // deleted by the caller.
93 // SIGPROF handler (or SIGALRM if using ITIMER_REAL).
94 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback, 106 ProfileHandlerToken* RegisterCallback(ProfileHandlerCallback callback,
95 void* callback_arg); 107 void* callback_arg);
96 108
97 // Unregisters a previously registered callback. Expects the token returned 109 // Unregisters a previously registered callback. Expects the token returned
98 // by the corresponding RegisterCallback routine. Unregistering the last 110 // by the corresponding RegisterCallback routine.
99 // callback disables the SIGPROF handler (or SIGALRM if using ITIMER_REAL).
100 void UnregisterCallback(ProfileHandlerToken* token) 111 void UnregisterCallback(ProfileHandlerToken* token)
101 NO_THREAD_SAFETY_ANALYSIS; 112 NO_THREAD_SAFETY_ANALYSIS;
102 113
103 // Unregisters all the callbacks, stops the timer if shared, disables the 114 // Unregisters all the callbacks and stops the timer(s).
104 // SIGPROF (or SIGALRM) handler and clears the timer_sharing_ state.
105 void Reset(); 115 void Reset();
106 116
107 // Gets the current state of profile handler. 117 // Gets the current state of profile handler.
108 void GetState(ProfileHandlerState* state); 118 void GetState(ProfileHandlerState* state);
109 119
110 // Initializes and returns the ProfileHandler singleton. 120 // Initializes and returns the ProfileHandler singleton.
111 static ProfileHandler* Instance(); 121 static ProfileHandler* Instance();
112 122
113 private: 123 private:
114 ProfileHandler(); 124 ProfileHandler();
115 ~ProfileHandler(); 125 ~ProfileHandler();
116 126
117 // Largest allowed frequency. 127 // Largest allowed frequency.
118 static const int32 kMaxFrequency = 4000; 128 static const int32 kMaxFrequency = 4000;
119 // Default frequency. 129 // Default frequency.
120 static const int32 kDefaultFrequency = 100; 130 static const int32 kDefaultFrequency = 100;
121 131
122 // ProfileHandler singleton. 132 // ProfileHandler singleton.
123 static ProfileHandler* instance_; 133 static ProfileHandler* instance_;
124 134
125 // pthread_once_t for one time initialization of ProfileHandler singleton. 135 // pthread_once_t for one time initialization of ProfileHandler singleton.
126 static pthread_once_t once_; 136 static pthread_once_t once_;
127 137
138 #if defined(HAVE_TLS)
139 // Timer state as configured previously. This bit is kept in
140 // |registered_threads_| if TLS is not available.
141 static __thread bool timer_running_;
142 #endif
143
128 // Initializes the ProfileHandler singleton via GoogleOnceInit. 144 // Initializes the ProfileHandler singleton via GoogleOnceInit.
129 static void Init(); 145 static void Init();
130 146
131 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received. 147 // The number of SIGPROF (or SIGALRM for ITIMER_REAL) interrupts received.
132 int64 interrupts_ GUARDED_BY(signal_lock_); 148 int64 interrupts_ GUARDED_BY(signal_lock_);
133 149
134 // SIGPROF/SIGALRM interrupt frequency, read-only after construction. 150 // SIGPROF/SIGALRM interrupt frequency, read-only after construction.
135 int32 frequency_; 151 int32 frequency_;
136 152
137 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM) 153 // ITIMER_PROF (which uses SIGPROF), or ITIMER_REAL (which uses SIGALRM)
138 int timer_type_; 154 int timer_type_;
139 155
140 // Counts the number of callbacks registered. 156 // Counts the number of callbacks registered.
141 int32 callback_count_ GUARDED_BY(control_lock_); 157 int32 callback_count_ GUARDED_BY(control_lock_);
142 158
143 // Is profiling allowed at all? 159 // Is profiling allowed at all?
144 bool allowed_; 160 bool allowed_;
145 161
146 // Whether or not the threading system provides interval timers that are
147 // shared by all threads in a process.
148 enum {
149 // No timer initialization attempted yet.
150 TIMERS_UNTOUCHED,
151 // First thread has registered and set timer.
152 TIMERS_ONE_SET,
153 // Timers are shared by all threads.
154 TIMERS_SHARED,
155 // Timers are separate in each thread.
156 TIMERS_SEPARATE
157 } timer_sharing_ GUARDED_BY(control_lock_);
158
159 // This lock serializes the registration of threads and protects the 162 // This lock serializes the registration of threads and protects the
160 // callbacks_ list below. 163 // callbacks_ list below.
161 // Locking order: 164 // Locking order:
162 // In the context of a signal handler, acquire signal_lock_ to walk the 165 // In the context of a signal handler, acquire signal_lock_ to walk the
163 // callback list. Otherwise, acquire control_lock_, disable the signal 166 // callback list. Otherwise, acquire control_lock_, disable the signal
164 // handler and then acquire signal_lock_. 167 // handler and then acquire signal_lock_.
165 SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_); 168 SpinLock control_lock_ ACQUIRED_BEFORE(signal_lock_);
166 SpinLock signal_lock_; 169 SpinLock signal_lock_;
167 170
171 // Set of threads registered through RegisterThread. This is consulted
172 // whenever timers are switched on or off to post a signal to these threads
173 // so they can arm their timers. Locking rules as for |callbacks_| below. If
174 // TLS is not available, this map is also used to keep the thread's timer
175 // state.
176 map<pthread_t, bool> registered_threads_ GUARDED_BY(signal_lock_);
177
168 // Holds the list of registered callbacks. We expect the list to be pretty 178 // Holds the list of registered callbacks. We expect the list to be pretty
169 // small. Currently, the cpu profiler (base/profiler) and thread module 179 // small. Currently, the cpu profiler (base/profiler) and thread module
170 // (base/thread.h) are the only two components registering callbacks. 180 // (base/thread.h) are the only two components registering callbacks.
171 // Following are the locking requirements for callbacks_: 181 // Following are the locking requirements for callbacks_:
172 // For read-write access outside the SIGPROF handler: 182 // For read-write access outside the SIGPROF handler:
173 // - Acquire control_lock_ 183 // - Acquire control_lock_
174 // - Disable SIGPROF handler. 184 // - Disable SIGPROF handler.
175 // - Acquire signal_lock_ 185 // - Acquire signal_lock_
176 // For read-only access in the context of SIGPROF handler 186 // For read-only access in the context of SIGPROF handler
177 // (Read-write access is *not allowed* in the SIGPROF handler) 187 // (Read-write access is *not allowed* in the SIGPROF handler)
178 // - Acquire signal_lock_ 188 // - Acquire signal_lock_
179 // For read-only access outside SIGPROF handler: 189 // For read-only access outside SIGPROF handler:
180 // - Acquire control_lock_ 190 // - Acquire control_lock_
181 typedef list<ProfileHandlerToken*> CallbackList; 191 typedef list<ProfileHandlerToken*> CallbackList;
182 typedef CallbackList::iterator CallbackIterator; 192 typedef CallbackList::iterator CallbackIterator;
183 CallbackList callbacks_ GUARDED_BY(signal_lock_); 193 CallbackList callbacks_ GUARDED_BY(signal_lock_);
184 194
185 // Starts the interval timer. If the thread library shares timers between 195 // Returns the signal to be used with |timer_type_| (SIGPROF or SIGALARM).
186 // threads, this function starts the shared timer. Otherwise, this will start 196 int signal_number() {
187 // the timer in the current thread. 197 return (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
188 void StartTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 198 }
189 199
190 // Stops the interval timer. If the thread library shares timers between 200 // Starts or stops the interval timer(s). In case of non-shared timers, this
191 // threads, this fucntion stops the shared timer. Otherwise, this will stop 201 // will post a signal to all registered threads, causing them to arm their
192 // the timer in the current thread. 202 // timers.
193 void StopTimer() EXCLUSIVE_LOCKS_REQUIRED(control_lock_); 203 void UpdateTimers(bool enable) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_);
194 204
195 // Returns true if the profile interval timer is enabled in the current 205 // Configures the timer. If |frequency| is 0, the timer will be disabled.
196 // thread. This actually checks the kernel's interval timer setting. (It is 206 void SetupTimer(int32 frequency) EXCLUSIVE_LOCKS_REQUIRED(signal_lock_);
197 // used to detect whether timers are shared or separate.)
198 bool IsTimerRunning() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
199
200 // Sets the timer interrupt signal handler.
201 void EnableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
202
203 // Disables (ignores) the timer interrupt signal.
204 void DisableHandler() EXCLUSIVE_LOCKS_REQUIRED(control_lock_);
205 207
206 // Returns true if the handler is not being used by something else. 208 // Returns true if the handler is not being used by something else.
207 // This checks the kernel's signal handler table. 209 // This checks the kernel's signal handler table.
208 bool IsSignalHandlerAvailable(); 210 bool IsSignalHandlerAvailable();
209 211
210 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks . 212 // SIGPROF/SIGALRM handler. Iterate over and call all the registered callbacks .
211 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext); 213 static void SignalHandler(int sig, siginfo_t* sinfo, void* ucontext);
212 214
213 DISALLOW_COPY_AND_ASSIGN(ProfileHandler); 215 DISALLOW_COPY_AND_ASSIGN(ProfileHandler);
214 }; 216 };
215 217
216 ProfileHandler* ProfileHandler::instance_ = NULL; 218 ProfileHandler* ProfileHandler::instance_ = NULL;
217 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT; 219 pthread_once_t ProfileHandler::once_ = PTHREAD_ONCE_INIT;
218 220
221 #if defined(HAVE_TLS)
222 bool __thread ProfileHandler::timer_running_ = false;
223 #endif
224
219 const int32 ProfileHandler::kMaxFrequency; 225 const int32 ProfileHandler::kMaxFrequency;
220 const int32 ProfileHandler::kDefaultFrequency; 226 const int32 ProfileHandler::kDefaultFrequency;
221 227
222 // If we are LD_PRELOAD-ed against a non-pthreads app, then 228 // If we are LD_PRELOAD-ed against a non-pthreads app, then pthread_* functions
223 // pthread_once won't be defined. We declare it here, for that 229 // won't be defined. We declare them here, for that case (with weak linkage)
224 // case (with weak linkage) which will cause the non-definition to 230 // which will cause the non-definition to resolve to NULL. We can then check
225 // resolve to NULL. We can then check for NULL or not in Instance. 231 // for NULL or not in Instance.
226 extern "C" int pthread_once(pthread_once_t *, void (*)(void)) 232 extern "C" int pthread_once(pthread_once_t *, void (*)(void))
227 ATTRIBUTE_WEAK; 233 ATTRIBUTE_WEAK;
234 extern "C" int pthread_kill(pthread_t thread_id, int signo)
235 ATTRIBUTE_WEAK;
228 236
229 void ProfileHandler::Init() { 237 void ProfileHandler::Init() {
230 instance_ = new ProfileHandler(); 238 instance_ = new ProfileHandler();
231 } 239 }
232 240
233 ProfileHandler* ProfileHandler::Instance() { 241 ProfileHandler* ProfileHandler::Instance() {
234 if (pthread_once) { 242 if (pthread_once) {
235 pthread_once(&once_, Init); 243 pthread_once(&once_, Init);
236 } 244 }
237 if (instance_ == NULL) { 245 if (instance_ == NULL) {
238 // This will be true on systems that don't link in pthreads, 246 // This will be true on systems that don't link in pthreads,
239 // including on FreeBSD where pthread_once has a non-zero address 247 // including on FreeBSD where pthread_once has a non-zero address
240 // (but doesn't do anything) even when pthreads isn't linked in. 248 // (but doesn't do anything) even when pthreads isn't linked in.
241 Init(); 249 Init();
242 assert(instance_ != NULL); 250 assert(instance_ != NULL);
243 } 251 }
244 return instance_; 252 return instance_;
245 } 253 }
246 254
247 ProfileHandler::ProfileHandler() 255 ProfileHandler::ProfileHandler()
248 : interrupts_(0), 256 : interrupts_(0),
249 callback_count_(0), 257 callback_count_(0),
250 allowed_(true), 258 allowed_(true) {
251 timer_sharing_(TIMERS_UNTOUCHED) {
252 SpinLockHolder cl(&control_lock_); 259 SpinLockHolder cl(&control_lock_);
253 260
254 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF); 261 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
255 262
256 // Get frequency of interrupts (if specified) 263 // Get frequency of interrupts (if specified)
257 char junk; 264 char junk;
258 const char* fr = getenv("CPUPROFILE_FREQUENCY"); 265 const char* fr = getenv("CPUPROFILE_FREQUENCY");
259 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) && 266 if (fr != NULL && (sscanf(fr, "%u%c", &frequency_, &junk) == 1) &&
260 (frequency_ > 0)) { 267 (frequency_ > 0)) {
261 // Limit to kMaxFrequency 268 // Limit to kMaxFrequency
262 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_; 269 frequency_ = (frequency_ > kMaxFrequency) ? kMaxFrequency : frequency_;
263 } else { 270 } else {
264 frequency_ = kDefaultFrequency; 271 frequency_ = kDefaultFrequency;
265 } 272 }
266 273
267 if (!allowed_) { 274 if (!allowed_) {
268 return; 275 return;
269 } 276 }
270 277
271 // If something else is using the signal handler, 278 // If something else is using the signal handler,
272 // assume it has priority over us and stop. 279 // assume it has priority over us and stop.
273 if (!IsSignalHandlerAvailable()) { 280 if (!IsSignalHandlerAvailable()) {
274 RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.", 281 RAW_LOG(INFO, "Disabling profiler because %s handler is already in use.",
275 timer_type_ == ITIMER_REAL ? "SIGALRM" : "SIGPROF"); 282 signal_number());
276 allowed_ = false; 283 allowed_ = false;
277 return; 284 return;
278 } 285 }
279 286
280 // Ignore signals until we decide to turn profiling on. (Paranoia; 287 // Install the signal handler.
281 // should already be ignored.) 288 struct sigaction sa;
282 DisableHandler(); 289 sa.sa_sigaction = SignalHandler;
290 sa.sa_flags = SA_RESTART | SA_SIGINFO;
291 sigemptyset(&sa.sa_mask);
292 RAW_CHECK(sigaction(signal_number(), &sa, NULL) == 0, "sigprof (enable)");
283 } 293 }
284 294
285 ProfileHandler::~ProfileHandler() { 295 ProfileHandler::~ProfileHandler() {
286 Reset(); 296 Reset();
287 } 297 }
288 298
289 void ProfileHandler::RegisterThread() { 299 void ProfileHandler::RegisterThread() {
290 SpinLockHolder cl(&control_lock_); 300 SpinLockHolder cl(&control_lock_);
291 301
292 if (!allowed_) { 302 if (!allowed_) {
293 return; 303 return;
294 } 304 }
295 305
296 // We try to detect whether timers are being shared by setting a 306 // Record the thread identifier and start the timer if profiling is on.
297 // timer in the first call to this function, then checking whether 307 ScopedSignalBlocker block(signal_number());
298 // it's set in the second call. 308 SpinLockHolder sl(&signal_lock_);
299 // 309 registered_threads_[pthread_self()] = false;
300 // Note that this detection method requires that the first two calls 310 SetupTimer(callback_count_ > 0 ? frequency_ : 0);
301 // to RegisterThread must be made from different threads. (Subsequent 311 }
302 // calls will see timer_sharing_ set to either TIMERS_SEPARATE or 312
303 // TIMERS_SHARED, and won't try to detect the timer sharing type.) 313 void ProfileHandler::UnregisterThread() {
304 // 314 ScopedSignalBlocker block(signal_number());
305 // Also note that if timer settings were inherited across new thread 315 SpinLockHolder sl(&signal_lock_);
306 // creation but *not* shared, this approach wouldn't work. That's 316 registered_threads_.erase(pthread_self());
307 // not an issue for any Linux threading implementation, and should
308 // not be a problem for a POSIX-compliant threads implementation.
309 switch (timer_sharing_) {
310 case TIMERS_UNTOUCHED:
311 StartTimer();
312 timer_sharing_ = TIMERS_ONE_SET;
313 break;
314 case TIMERS_ONE_SET:
315 // If the timer is running, that means that the main thread's
316 // timer setup is seen in this (second) thread -- and therefore
317 // that timers are shared.
318 if (IsTimerRunning()) {
319 timer_sharing_ = TIMERS_SHARED;
320 // If callback is already registered, we have to keep the timer
321 // running. If not, we disable the timer here.
322 if (callback_count_ == 0) {
323 StopTimer();
324 }
325 } else {
326 timer_sharing_ = TIMERS_SEPARATE;
327 StartTimer();
328 }
329 break;
330 case TIMERS_SHARED:
331 // Nothing needed.
332 break;
333 case TIMERS_SEPARATE:
334 StartTimer();
335 break;
336 }
337 } 317 }
338 318
339 ProfileHandlerToken* ProfileHandler::RegisterCallback( 319 ProfileHandlerToken* ProfileHandler::RegisterCallback(
340 ProfileHandlerCallback callback, void* callback_arg) { 320 ProfileHandlerCallback callback, void* callback_arg) {
341 321
342 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg); 322 ProfileHandlerToken* token = new ProfileHandlerToken(callback, callback_arg);
343 323
344 SpinLockHolder cl(&control_lock_); 324 SpinLockHolder cl(&control_lock_);
345 DisableHandler();
346 { 325 {
326 ScopedSignalBlocker block(signal_number());
347 SpinLockHolder sl(&signal_lock_); 327 SpinLockHolder sl(&signal_lock_);
348 callbacks_.push_back(token); 328 callbacks_.push_back(token);
329 ++callback_count_;
330 UpdateTimers(true);
349 } 331 }
350 // Start the timer if timer is shared and this is a first callback.
351 if ((callback_count_ == 0) && (timer_sharing_ == TIMERS_SHARED)) {
352 StartTimer();
353 }
354 ++callback_count_;
355 EnableHandler();
356 return token; 332 return token;
357 } 333 }
358 334
359 void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) { 335 void ProfileHandler::UnregisterCallback(ProfileHandlerToken* token) {
360 SpinLockHolder cl(&control_lock_); 336 SpinLockHolder cl(&control_lock_);
361 for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end(); 337 for (CallbackIterator it = callbacks_.begin(); it != callbacks_.end();
362 ++it) { 338 ++it) {
363 if ((*it) == token) { 339 if ((*it) == token) {
364 RAW_CHECK(callback_count_ > 0, "Invalid callback count"); 340 RAW_CHECK(callback_count_ > 0, "Invalid callback count");
365 DisableHandler();
366 { 341 {
342 ScopedSignalBlocker block(signal_number());
367 SpinLockHolder sl(&signal_lock_); 343 SpinLockHolder sl(&signal_lock_);
368 delete *it; 344 delete *it;
369 callbacks_.erase(it); 345 callbacks_.erase(it);
370 } 346 --callback_count_;
371 --callback_count_; 347 if (callback_count_ == 0)
372 if (callback_count_ > 0) { 348 UpdateTimers(false);
373 EnableHandler();
374 } else if (timer_sharing_ == TIMERS_SHARED) {
375 StopTimer();
376 } 349 }
377 return; 350 return;
378 } 351 }
379 } 352 }
380 // Unknown token. 353 // Unknown token.
381 RAW_LOG(FATAL, "Invalid token"); 354 RAW_LOG(FATAL, "Invalid token");
382 } 355 }
383 356
384 void ProfileHandler::Reset() { 357 void ProfileHandler::Reset() {
385 SpinLockHolder cl(&control_lock_); 358 SpinLockHolder cl(&control_lock_);
386 DisableHandler();
387 { 359 {
360 ScopedSignalBlocker block(signal_number());
388 SpinLockHolder sl(&signal_lock_); 361 SpinLockHolder sl(&signal_lock_);
389 CallbackIterator it = callbacks_.begin(); 362 CallbackIterator it = callbacks_.begin();
390 while (it != callbacks_.end()) { 363 while (it != callbacks_.end()) {
391 CallbackIterator tmp = it; 364 CallbackIterator tmp = it;
392 ++it; 365 ++it;
393 delete *tmp; 366 delete *tmp;
394 callbacks_.erase(tmp); 367 callbacks_.erase(tmp);
395 } 368 }
369 callback_count_ = 0;
370 UpdateTimers(false);
396 } 371 }
397 callback_count_ = 0;
398 if (timer_sharing_ == TIMERS_SHARED) {
399 StopTimer();
400 }
401 timer_sharing_ = TIMERS_UNTOUCHED;
402 } 372 }
403 373
404 void ProfileHandler::GetState(ProfileHandlerState* state) { 374 void ProfileHandler::GetState(ProfileHandlerState* state) {
405 SpinLockHolder cl(&control_lock_); 375 SpinLockHolder cl(&control_lock_);
406 DisableHandler();
407 { 376 {
377 ScopedSignalBlocker block(signal_number());
408 SpinLockHolder sl(&signal_lock_); // Protects interrupts_. 378 SpinLockHolder sl(&signal_lock_); // Protects interrupts_.
409 state->interrupts = interrupts_; 379 state->interrupts = interrupts_;
410 } 380 }
411 if (callback_count_ > 0) {
412 EnableHandler();
413 }
414 state->frequency = frequency_; 381 state->frequency = frequency_;
415 state->callback_count = callback_count_; 382 state->callback_count = callback_count_;
416 state->allowed = allowed_; 383 state->allowed = allowed_;
417 } 384 }
418 385
419 void ProfileHandler::StartTimer() { 386 void ProfileHandler::UpdateTimers(bool enabled) {
420 if (!allowed_) { 387 if (!allowed_) {
421 return; 388 return;
422 } 389 }
390 SetupTimer(enabled ? frequency_ : 0);
391
392 // Tell other threads to start their timers.
393 for (map<pthread_t, bool>::const_iterator thread(registered_threads_.begin());
394 thread != registered_threads_.end();
395 ++thread) {
396 if (thread->first != pthread_self() && pthread_kill) {
397 int err = pthread_kill(thread->first, signal_number());
398 if (err == ESRCH) {
399 // Thread exited.
400 registered_threads_.erase(thread->first);
401 } else {
402 RAW_CHECK(err == 0, "pthread_kill");
403 }
404 }
405 }
406 }
407
408 void ProfileHandler::SetupTimer(int32 frequency) {
409 bool enable = (frequency > 0);
410 #if defined(HAVE_TLS)
411 bool& timer_running = timer_running_;
412 #else
413 bool& timer_running = registered_threads_[pthread_self()];
414 #endif
415 if (enable == timer_running)
416 return;
423 struct itimerval timer; 417 struct itimerval timer;
424 timer.it_interval.tv_sec = 0; 418 timer.it_interval.tv_sec = 0;
425 timer.it_interval.tv_usec = 1000000 / frequency_; 419 timer.it_interval.tv_usec = (enable ? (1000000 / frequency) : 0);
426 timer.it_value = timer.it_interval; 420 timer.it_value = timer.it_interval;
427 setitimer(timer_type_, &timer, 0); 421 setitimer(timer_type_, &timer, 0);
428 } 422 timer_running = enable;
429
430 void ProfileHandler::StopTimer() {
431 if (!allowed_) {
432 return;
433 }
434 struct itimerval timer;
435 memset(&timer, 0, sizeof timer);
436 setitimer(timer_type_, &timer, 0);
437 }
438
439 bool ProfileHandler::IsTimerRunning() {
440 if (!allowed_) {
441 return false;
442 }
443 struct itimerval current_timer;
444 RAW_CHECK(0 == getitimer(timer_type_, &current_timer), "getitimer");
445 return (current_timer.it_value.tv_sec != 0 ||
446 current_timer.it_value.tv_usec != 0);
447 }
448
449 void ProfileHandler::EnableHandler() {
450 if (!allowed_) {
451 return;
452 }
453 struct sigaction sa;
454 sa.sa_sigaction = SignalHandler;
455 sa.sa_flags = SA_RESTART | SA_SIGINFO;
456 sigemptyset(&sa.sa_mask);
457 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
458 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (enable)");
459 }
460
461 void ProfileHandler::DisableHandler() {
462 if (!allowed_) {
463 return;
464 }
465 struct sigaction sa;
466 sa.sa_handler = SIG_IGN;
467 sa.sa_flags = SA_RESTART;
468 sigemptyset(&sa.sa_mask);
469 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM);
470 RAW_CHECK(sigaction(signal_number, &sa, NULL) == 0, "sigprof (disable)");
471 } 423 }
472 424
473 bool ProfileHandler::IsSignalHandlerAvailable() { 425 bool ProfileHandler::IsSignalHandlerAvailable() {
474 struct sigaction sa; 426 struct sigaction sa;
475 const int signal_number = (timer_type_ == ITIMER_PROF ? SIGPROF : SIGALRM); 427 RAW_CHECK(sigaction(signal_number(), NULL, &sa) == 0,
476 RAW_CHECK(sigaction(signal_number, NULL, &sa) == 0, "is-signal-handler avail") ; 428 "is-signal-handler avail");
477 429
478 // We only take over the handler if the current one is unset. 430 // We only take over the handler if the current one is unset.
479 // It must be SIG_IGN or SIG_DFL, not some other function. 431 // It must be SIG_IGN or SIG_DFL, not some other function.
480 // SIG_IGN must be allowed because when profiling is allowed but 432 // SIG_IGN must be allowed because when profiling is allowed but
481 // not actively in use, this code keeps the handler set to SIG_IGN. 433 // not actively in use, this code keeps the handler set to SIG_IGN.
482 // That setting will be inherited across fork+exec. In order for 434 // That setting will be inherited across fork+exec. In order for
483 // any child to be able to use profiling, SIG_IGN must be treated 435 // any child to be able to use profiling, SIG_IGN must be treated
484 // as available. 436 // as available.
485 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL; 437 return sa.sa_handler == SIG_IGN || sa.sa_handler == SIG_DFL;
486 } 438 }
487 439
488 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) { 440 void ProfileHandler::SignalHandler(int sig, siginfo_t* sinfo, void* ucontext) {
489 int saved_errno = errno; 441 int saved_errno = errno;
490 // At this moment, instance_ must be initialized because the handler is 442 // At this moment, instance_ must be initialized because the handler is
491 // enabled in RegisterThread or RegisterCallback only after 443 // enabled in RegisterThread or RegisterCallback only after
492 // ProfileHandler::Instance runs. 444 // ProfileHandler::Instance runs.
493 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_); 445 ProfileHandler* instance = ANNOTATE_UNPROTECTED_READ(instance_);
494 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized"); 446 RAW_CHECK(instance != NULL, "ProfileHandler is not initialized");
495 { 447 {
496 SpinLockHolder sl(&instance->signal_lock_); 448 SpinLockHolder sl(&instance->signal_lock_);
497 ++instance->interrupts_; 449 ++instance->interrupts_;
450 // Enable/Disable the timer if necessary.
451 instance->SetupTimer(
452 instance->callbacks_.empty() ? 0 : instance->frequency_);
498 for (CallbackIterator it = instance->callbacks_.begin(); 453 for (CallbackIterator it = instance->callbacks_.begin();
499 it != instance->callbacks_.end(); 454 it != instance->callbacks_.end();
500 ++it) { 455 ++it) {
501 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg); 456 (*it)->callback(sig, sinfo, ucontext, (*it)->callback_arg);
502 } 457 }
503 } 458 }
504 errno = saved_errno; 459 errno = saved_errno;
505 } 460 }
506 461
507 // This module initializer registers the main thread, so it must be 462 // This module initializer registers the main thread, so it must be
508 // executed in the context of the main thread. 463 // executed in the context of the main thread.
509 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread()); 464 REGISTER_MODULE_INITIALIZER(profile_main, ProfileHandlerRegisterThread());
510 465
511 extern "C" void ProfileHandlerRegisterThread() { 466 extern "C" void ProfileHandlerRegisterThread() {
512 ProfileHandler::Instance()->RegisterThread(); 467 ProfileHandler::Instance()->RegisterThread();
513 } 468 }
514 469
470 extern "C" void ProfileHandlerUnregisterThread() {
471 ProfileHandler::Instance()->UnregisterThread();
472 }
473
515 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( 474 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
516 ProfileHandlerCallback callback, void* callback_arg) { 475 ProfileHandlerCallback callback, void* callback_arg) {
517 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg); 476 return ProfileHandler::Instance()->RegisterCallback(callback, callback_arg);
518 } 477 }
519 478
520 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { 479 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
521 ProfileHandler::Instance()->UnregisterCallback(token); 480 ProfileHandler::Instance()->UnregisterCallback(token);
522 } 481 }
523 482
524 extern "C" void ProfileHandlerReset() { 483 extern "C" void ProfileHandlerReset() {
525 return ProfileHandler::Instance()->Reset(); 484 return ProfileHandler::Instance()->Reset();
526 } 485 }
527 486
528 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { 487 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
529 ProfileHandler::Instance()->GetState(state); 488 ProfileHandler::Instance()->GetState(state);
530 } 489 }
531 490
532 #else // OS_CYGWIN 491 #else // OS_CYGWIN
533 492
534 // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't 493 // ITIMER_PROF doesn't work under cygwin. ITIMER_REAL is available, but doesn't
535 // work as well for profiling, and also interferes with alarm(). Because of 494 // work as well for profiling, and also interferes with alarm(). Because of
536 // these issues, unless a specific need is identified, profiler support is 495 // these issues, unless a specific need is identified, profiler support is
537 // disabled under Cygwin. 496 // disabled under Cygwin.
538 extern "C" void ProfileHandlerRegisterThread() { 497 extern "C" void ProfileHandlerRegisterThread() {
539 } 498 }
540 499
500 extern "C" void ProfileHandlerUnregisterThread() {
501 }
502
541 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback( 503 extern "C" ProfileHandlerToken* ProfileHandlerRegisterCallback(
542 ProfileHandlerCallback callback, void* callback_arg) { 504 ProfileHandlerCallback callback, void* callback_arg) {
543 return NULL; 505 return NULL;
544 } 506 }
545 507
546 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) { 508 extern "C" void ProfileHandlerUnregisterCallback(ProfileHandlerToken* token) {
547 } 509 }
548 510
549 extern "C" void ProfileHandlerReset() { 511 extern "C" void ProfileHandlerReset() {
550 } 512 }
551 513
552 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) { 514 extern "C" void ProfileHandlerGetState(ProfileHandlerState* state) {
553 } 515 }
554 516
555 #endif // OS_CYGWIN 517 #endif // OS_CYGWIN
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/profile-handler.h ('k') | third_party/tcmalloc/chromium/src/profiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698