[PATCH 07 of 10 V2] statprof: support stacked collection
Yuya Nishihara
yuya at tcha.org
Sun Sep 4 05:37:45 UTC 2016
On Wed, 17 Aug 2016 09:03:45 -0700, Gregory Szorc wrote:
> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1471449673 25200
> # Wed Aug 17 09:01:13 2016 -0700
> # Node ID bf247c2f0136d23100b0098fe152cfabbb511c1b
> # Parent 7409c675a2be190605f07277627b095976f56da8
> statprof: support stacked collection
> -def samplerthread(tid):
> +def samplerthread():
> while not stopthread.is_set():
> state.accumulate_time(clock())
>
> - frame = sys._current_frames()[tid]
> + frame = sys._current_frames()[state.threadid]
> state.samples.append(Sample.from_frame(frame, state.accumulated_time))
[snip]
> def start(mechanism='thread'):
> '''Install the profiling signal handler, and start profiling.'''
> + # Store old state if present.
> + if state.profile_level > 0:
> + laststate = {
> + 'samples': state.samples,
> + 'tid': state.threadid,
> + 'accumulated_time': state.accumulated_time,
> + }
> + _statestack.append(laststate)
> +
> + state.samples = []
> + state.accumulated_time = 0.0
> + frame = inspect.currentframe()
> + tid = [k for k, f in sys._current_frames().items() if f == frame][0]
> + state.threadid = tid
> +
> state.profile_level += 1
> if state.profile_level == 1:
> state.last_start_time = clock()
> rpt = state.remaining_prof_time
> state.remaining_prof_time = None
>
> 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")
> + 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)
> @@ -317,16 +338,39 @@ def stop():
> state.thread.join()
>
> state.accumulate_time(clock())
> state.last_start_time = None
> statprofpath = os.environ.get('STATPROF_DEST')
> if statprofpath:
> save_data(statprofpath)
>
> + return CollectedData(state.samples, state.accumulated_time,
> + state.sample_interval)
> + elif state.profile_level > 0:
> + newstate = _statestack.pop()
> +
> + data = CollectedData(state.samples, state.accumulated_time,
> + state.sample_interval)
> +
> + # Merge the just collected data onto the base state since the base
> + # state was active while this one was collecting.
> + newstate['samples'].extend(state.samples)
> + newstate['threadid'] = newstate['tid']
> + newstate['accumulated_time'] += state.accumulated_time
> +
> + # Now make the base state the active state.
> + state.samples = newstate['samples']
> + state.threadid = newstate['tid']
> + state.accumulated_time = newstate['accumulated_time']
> +
> + return data
I don't think states can form a stack because start/stop will be called by
arbitrary threads. Instead, samplerthread would need to record activities of
all threads of profiling enabled.
But, in either ways, I don't think statprof can show a good result if
more than one threads are actively running and switched at random.
The other patches look generally good to me.
More information about the Mercurial-devel
mailing list