mirror of
https://github.com/facebook/sapling.git
synced 2024-10-06 23:07:18 +03:00
statprof: add threading sampler
Summary: The existing statprof uses signals to perform stack sampling. Those signals can interfere with system calls though. This patch introduces a way of using python threads to perform sampling from a background thread. This also changes the default to be the threaded profiler instead of the sampling one, since the sampling can crash the proces sometimes. In some situations this produces a more accurate stack trace. Test Plan: ``` sudo cp statprof.py /usr/lib64/python2.6/site-packages/statprof.py hg pull --profile # Verified I got output and that it was different from the old statprof (it was # more accurate, as compared with time.time() measurements in the code) ``` Reviewers: #mercurial, ttung, quark Reviewed By: quark Subscribers: quark, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D3402864 Signature: t1:3402864:1465978363:c8455d119cc03c2c475e190aee28587a9d434c4d
This commit is contained in:
parent
50238ee029
commit
b9e78ae8c1
47
statprof.py
47
statprof.py
@ -104,7 +104,8 @@ main thread's work patterns.
|
||||
# no-check-code
|
||||
from __future__ import division
|
||||
|
||||
import json, os, signal, tempfile, sys, getopt
|
||||
import inspect, json, os, signal, tempfile, sys, getopt, threading, traceback
|
||||
import time
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from subprocess import call
|
||||
@ -252,6 +253,18 @@ def profile_signal_handler(signum, frame):
|
||||
state.sample_interval, 0.0)
|
||||
state.last_start_time = clock()
|
||||
|
||||
stopthread = threading.Event()
|
||||
def samplerthread(tid):
|
||||
while not stopthread.is_set():
|
||||
state.accumulate_time(clock())
|
||||
|
||||
frame = sys._current_frames()[tid]
|
||||
state.samples.append(Sample.from_frame(frame, state.accumulated_time))
|
||||
|
||||
state.last_start_time = clock()
|
||||
time.sleep(state.sample_interval)
|
||||
|
||||
stopthread.clear()
|
||||
|
||||
###########################################################################
|
||||
## Profiling API
|
||||
@ -259,29 +272,43 @@ def profile_signal_handler(signum, frame):
|
||||
def is_active():
|
||||
return state.profile_level > 0
|
||||
|
||||
|
||||
def start():
|
||||
lastmechanism = None
|
||||
def start(mechanism='thread'):
|
||||
'''Install the profiling signal handler, and start profiling.'''
|
||||
state.profile_level += 1
|
||||
if state.profile_level == 1:
|
||||
state.last_start_time = clock()
|
||||
rpt = state.remaining_prof_time
|
||||
state.remaining_prof_time = None
|
||||
signal.signal(signal.SIGPROF, profile_signal_handler)
|
||||
signal.setitimer(signal.ITIMER_PROF,
|
||||
rpt or state.sample_interval, 0.0)
|
||||
|
||||
global lastmechanism
|
||||
lastmechanism = mechanism
|
||||
|
||||
if mechanism == 'signal':
|
||||
signal.signal(signal.SIGPROF, profile_signal_handler)
|
||||
signal.setitimer(signal.ITIMER_PROF,
|
||||
rpt or state.sample_interval, 0.0)
|
||||
elif mechanism == 'thread':
|
||||
frame = inspect.currentframe()
|
||||
tid = [k for k, f in sys._current_frames().items() if f == frame][0]
|
||||
state.thread = threading.Thread(target=samplerthread,
|
||||
args=(tid,), name="samplerthread")
|
||||
state.thread.start()
|
||||
|
||||
def stop():
|
||||
'''Stop profiling, and uninstall the profiling signal handler.'''
|
||||
state.profile_level -= 1
|
||||
if state.profile_level == 0:
|
||||
if lastmechanism == 'signal':
|
||||
rpt = signal.setitimer(signal.ITIMER_PROF, 0.0, 0.0)
|
||||
signal.signal(signal.SIGPROF, signal.SIG_IGN)
|
||||
state.remaining_prof_time = rpt[0]
|
||||
elif lastmechanism == 'thread':
|
||||
stopthread.set()
|
||||
state.thread.join()
|
||||
|
||||
state.accumulate_time(clock())
|
||||
state.last_start_time = None
|
||||
rpt = signal.setitimer(signal.ITIMER_PROF, 0.0, 0.0)
|
||||
signal.signal(signal.SIGPROF, signal.SIG_IGN)
|
||||
state.remaining_prof_time = rpt[0]
|
||||
|
||||
statprofpath = os.environ.get('STATPROF_DEST')
|
||||
save_data(statprofpath)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user