diff options
author | Mark Probst <mark.probst@gmail.com> | 2014-10-08 23:28:57 +0400 |
---|---|---|
committer | Mark Probst <mark.probst@gmail.com> | 2014-11-26 21:38:46 +0300 |
commit | a3e7d28caa7704b45bddc2c3c647078844a2a62e (patch) | |
tree | 68cfde5d7d77cfa3437482184f24357964880419 /tools | |
parent | 4318dac63c3ae2b2d1ab8ad9989a706420ace9e2 (diff) |
[sgen] Nicer visualization of concurrent collector pauses in gcpausevis.py.
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/sgen/gcpausevis.py | 223 |
1 files changed, 168 insertions, 55 deletions
diff --git a/tools/sgen/gcpausevis.py b/tools/sgen/gcpausevis.py index a309e02093d..52f0ab26ee3 100755 --- a/tools/sgen/gcpausevis.py +++ b/tools/sgen/gcpausevis.py @@ -40,6 +40,22 @@ if len (files) != 1: data = [] +class Event: + def __init__(self, **kwargs): + self.minor_work = kwargs['minor_work'] + self.major_work = kwargs['major_work'] + self.start = kwargs['start'] + self.stop = kwargs['stop'] + self.gc_type = kwargs['gc_type'] + def __repr__(self): + return 'Event(minor_work={}, major_work={}, start={}, stop={}, gc_type={})'.format( + self.minor_work, + self.major_work, + self.start, + self.stop, + self.gc_type, + ) + grep_input = open (files [0]) proc = subprocess.Popen ([sgen_grep_path, '--pause-times'], stdin = grep_input, stdout = subprocess.PIPE) for line in iter (proc.stdout.readline, ''): @@ -61,87 +77,184 @@ for line in iter (proc.stdout.readline, ''): minor_work = True if concurrent: major_work = True - gctype = "nursery+update" + gc_type = "nursery+update" else: - gctype = "nursery" + gc_type = "nursery" else: major_work = True if concurrent: if finish: minor_work = True - gctype = "nursery+finish" + gc_type = "nursery+finish" else: - gctype = "start" + gc_type = "start" else: - gctype = "full" + gc_type = "full" - rec = (minor_work, major_work, start, start + msecs, kind, gctype) + rec = Event( + minor_work=minor_work, + major_work=major_work, + start=start, + stop=start + msecs, + kind=kind, + gc_type=gc_type, + ) print rec data.append (rec) +class MajorGCEventGroup: + pass + +class FullMajorGCEventGroup(MajorGCEventGroup): + def __init__(self, event): + self.event = event + def __repr__(self): + return 'FullMajorGCEventGroup({})'.format( + self.event, + ) + +class ConcurrentMajorGCEventGroup(MajorGCEventGroup): + def __init__(self, start, updates, finish): + self.start = start + self.updates = updates + self.finish = finish + def __repr__(self): + return 'ConcurrentMajorEventGroup({}, {}, {})'.format( + self.start, + self.updates, + self.finish, + ) + +# ([Event], int) -> (MajorGCEventGroup, int) | None +def parse_next_major_gc(data, i): + assert i >= 0 + # Find start or full event. + while i < len(data) and data[i].gc_type not in ['start', 'full']: + i += 1 + if i == len(data): + return None + # If full event, done. + if data[i].gc_type == 'full': + return (FullMajorGCEventGroup(data[i]), i + 1) + start_event = data[i] + update_events = [] + # Filter update events and find finish event. + while i < len(data) and data[i].gc_type != 'nursery+finish': + if data[i].gc_type == 'nursery+update': + update_events.append(data[i]) + i += 1 + if i == len(data): + return None + finish_event = data[i] + i += 1 + return (ConcurrentMajorGCEventGroup(start_event, update_events, finish_event), i) + +# [Event] -> [MajorGCEventGroup] +def parse_major_gcs(data): + major_gc_events = [] + i = 0 + while True: + maybe_event_group = parse_next_major_gc(data, i) + if maybe_event_group is None: + return major_gc_events + event_group, i = maybe_event_group + major_gc_events.append(event_group) + if show_histogram: minor_pausetimes = [] major_pausetimes = [] for rec in data: - (minor_work, major_work, start_ts, finish_ts, kind, gctype) = rec - pause = finish_ts - start_ts - if minor_work and major_work and show_minor and show_major: + pause = rec.stop - rec.start + if rec.minor_work and rec.major_work and show_minor and show_major: major_pausetimes.append (pause) else: - if minor_work: + if rec.minor_work: minor_pausetimes.append (pause) - if major_work: + if rec.major_work: major_pausetimes.append (pause) pausetimes = [] + colors = [] if show_minor: - pausetimes += minor_pausetimes + pausetimes.append(minor_pausetimes) + colors.append('blue') if show_major: - pausetimes += major_pausetimes - plt.hist (pausetimes, 100) + pausetimes.append(major_pausetimes) + colors.append('red') + + plt.hist (pausetimes, 100, stacked=True, log=True, color=colors) plt.xlabel ('Pause time in msec') else: - data = np.array (data, dtype = [('caption', '|S20'), ('start', int), ('stop', int), ('kind', '|S20')]) - cap, start, stop=data['caption'], data['start'], data['stop'] - - #Check the status, because we paint all lines with the same color - #together - is_sync= (data['kind']=='SYNC') - not_sync=np.logical_not(is_sync) - - #Get unique captions and there indices and the inverse mapping - captions, unique_idx, caption_inv=np.unique(cap, 1,1) - print captions - - #Build y values from the number of unique captions. - y=(caption_inv+1)/float(len(captions)+1) - - #Plot function - def timelines(y, xstart, xstop,color='b'): - """Plot timelines at y from xstart to xstop with given color.""" - plt.hlines(y,xstart,xstop,color,lw=4) - plt.vlines(xstart, y+0.03,y-0.03,color,lw=2) - plt.vlines(xstop, y+0.03,y-0.03,color,lw=2) - - #Plot ok tl black - timelines(y[is_sync],start[is_sync],stop[is_sync],'r') - #Plot fail tl red - timelines(y[not_sync],start[not_sync],stop[not_sync],'k') - - #Setup the plot - ax=plt.gca() - #ax.xaxis_date() - #myFmt = DateFormatter('%H:%M:%S') - #ax.xaxis.set_major_formatter(myFmt) - #ax.xaxis.set_major_locator(SecondLocator(0,interval=20)) - - #To adjust the xlimits a timedelta is needed. - delta=(stop.max()-start.min())/10 - - plt.yticks(y[unique_idx],captions) - plt.ylim(0,1) - plt.xlim(start.min()-delta, stop.max()+delta) - plt.xlabel('Time') + major_gc_event_groups = parse_major_gcs(data) + + def bar(**kwargs): + indices = kwargs['indices'] + pauses = kwargs['pauses'] + color = kwargs['color'] + if 'bottom' in kwargs: + bottom = kwargs['bottom'] + else: + bottom = 0 + plt.bar( + [index for index in indices if pauses[index] is not None], + np.array([pause for pause in pauses if pause is not None]), + color=color, + bottom=bottom, + ) + + indices = np.arange(len(major_gc_event_groups)) + start_pauses = [ + event_group.start.stop - event_group.start.start + if isinstance(event_group, ConcurrentMajorGCEventGroup) else None + for event_group in major_gc_event_groups + ] + bar( + indices=indices, + pauses=start_pauses, + color='red', + ) + update_pauses = [ + sum([ + update_event.stop - update_event.start + for update_event in event_group.updates + ]) if isinstance(event_group, ConcurrentMajorGCEventGroup) else None + for event_group in major_gc_event_groups + ] + bar( + indices=indices, + pauses=update_pauses, + color='green', + bottom=[pause for pause in start_pauses if pause is not None], + ) + finish_pauses = [ + event_group.finish.stop - event_group.finish.start + if isinstance(event_group, ConcurrentMajorGCEventGroup) else None + for event_group in major_gc_event_groups + ] + start_update_pauses = [ + a + b + for a, b in zip(start_pauses, update_pauses) + if a is not None and b is not None + ] + bar( + indices=indices, + pauses=finish_pauses, + color='blue', + bottom=start_update_pauses, + ) + full_pauses = [ + event_group.event.stop - event_group.event.start + if isinstance(event_group, FullMajorGCEventGroup) else None + for event_group in major_gc_event_groups + ] + bar( + indices=indices, + pauses=full_pauses, + color='black', + ) + + plt.ylabel("Pause Time (ms)") + plt.xlabel("Collection") plt.show() |