2 import matplotlib
.pyplot
as plt
3 from matplotlib
.dates
import DateFormatter
, MinuteLocator
, SecondLocator
5 from StringIO
import StringIO
9 from optparse
import OptionParser
12 parser
= OptionParser (usage
= "Usage: %prog [options] BINARY-PROTOCOL")
13 parser
.add_option ('--histogram', action
= 'store_true', dest
= 'histogram', help = "pause time histogram")
14 parser
.add_option ('--scatter', action
= 'store_true', dest
= 'scatter', help = "pause time scatterplot")
15 parser
.add_option ('--minor', action
= 'store_true', dest
= 'minor', help = "only show minor collections in histogram")
16 parser
.add_option ('--major', action
= 'store_true', dest
= 'major', help = "only show major collections in histogram")
17 (options
, files
) = parser
.parse_args ()
19 show_histogram
= False
31 if (options
.minor
or options
.major
) and not options
.scatter
:
34 script_path
= os
.path
.realpath (__file__
)
35 sgen_grep_path
= os
.path
.join (os
.path
.dirname (script_path
), 'sgen-grep-binprot')
37 if not os
.path
.isfile (sgen_grep_path
):
38 sys
.stderr
.write ('Error: `%s` does not exist.\n' % sgen_grep_path
)
48 def __init__(self
, **kwargs
):
49 self
.minor_work
= kwargs
['minor_work']
50 self
.major_work
= kwargs
['major_work']
51 self
.start
= kwargs
['start']
52 self
.stop
= kwargs
['stop']
53 self
.gc_type
= kwargs
['gc_type']
55 return 'Event(minor_work={}, major_work={}, start={}, stop={}, gc_type={})'.format(
63 grep_input
= open (files
[0])
64 proc
= subprocess
.Popen ([sgen_grep_path
, '--pause-times'], stdin
= grep_input
, stdout
= subprocess
.PIPE
)
65 for line
in iter (proc
.stdout
.readline
, ''):
66 m
= re
.match ('^pause-time (\d+) (\d+) (\d+) (\d+) (\d+)', line
)
68 minor_work
= major_work
= False
69 generation
= int (m
.group (1))
70 concurrent
= int (m
.group (2)) != 0
71 finish
= int (m
.group (3)) != 0
72 msecs
= int (m
.group (4)) / 10.0 / 1000.0
73 start
= int (m
.group (5)) / 10.0 / 1000.0
84 gc_type
= "nursery+update"
92 gc_type
= "nursery+finish"
99 minor_work
=minor_work
,
100 major_work
=major_work
,
109 class MajorGCEventGroup
:
112 class FullMajorGCEventGroup(MajorGCEventGroup
):
113 def __init__(self
, event
):
116 return 'FullMajorGCEventGroup({})'.format(
120 class ConcurrentMajorGCEventGroup(MajorGCEventGroup
):
121 def __init__(self
, start
, updates
, finish
):
123 self
.updates
= updates
126 return 'ConcurrentMajorEventGroup({}, {}, {})'.format(
132 # ([Event], int) -> (MajorGCEventGroup, int) | None
133 def parse_next_major_gc(data
, i
):
135 # Find start or full event.
136 while i
< len(data
) and data
[i
].gc_type
not in ['start', 'full', 'nursery+update']:
140 # If full event, done.
141 if data
[i
].gc_type
== 'full':
142 return (FullMajorGCEventGroup(data
[i
]), i
+ 1)
143 start_event
= data
[i
]
145 # Filter update events and find finish event.
146 while i
< len(data
) and data
[i
].gc_type
!= 'nursery+finish':
147 if data
[i
].gc_type
== 'nursery+update':
148 update_events
.append(data
[i
])
152 finish_event
= data
[i
]
154 return (ConcurrentMajorGCEventGroup(start_event
, update_events
, finish_event
), i
)
156 # [Event] -> [MajorGCEventGroup]
157 def parse_major_gcs(data
):
161 maybe_event_group
= parse_next_major_gc(data
, i
)
162 if maybe_event_group
is None:
163 return major_gc_events
164 event_group
, i
= maybe_event_group
165 major_gc_events
.append(event_group
)
167 if show_histogram
or show_scatter
:
178 pause
= rec
.stop
- rec
.start
185 color
= 'red' if show_major
else None
187 color
= 'blue' if show_minor
else None
190 timeline_x
.append(rec
.start
)
191 timeline_y
.append(pause
)
192 timeline_c
.append(color
)
196 prev_time
= 0 if i
==0 else (1.3)**(i
+5)
197 if len(bin_names
) <= i
:
198 bin_data_minor
.append(0)
199 bin_data_both
.append(0)
200 bin_data_major
.append(0)
201 bin_names
.append('%d-%dms' % (int(prev_time
), int(time
)))
205 bin_data_both
[i
] += pause
207 bin_data_major
[i
] += pause
209 bin_data_minor
[i
] += pause
212 bin_data_minor
=np
.array(bin_data_minor
)
213 bin_data_both
=np
.array(bin_data_both
)
214 bin_data_major
=np
.array(bin_data_major
)
217 plt
.scatter(timeline_x
, timeline_y
, c
=timeline_c
)
220 plt
.bar(range(len(bin_data_minor
)), bin_data_minor
, color
='blue', label
="minor") #, align='center')
221 plt
.bar(range(len(bin_data_both
)), bin_data_both
, bottom
=bin_data_minor
, color
='purple', label
="minor & major")
223 plt
.bar(range(len(bin_data_major
)), bin_data_major
, bottom
=(bin_data_minor
+bin_data_both
), color
='red', label
="only major")
225 plt
.bar(range(len(bin_data_both
)), bin_data_both
, color
='purple', label
="minor & major")
226 plt
.bar(range(len(bin_data_major
)), bin_data_major
, bottom
=bin_data_both
, color
='red')
227 plt
.xticks(range(len(bin_names
)), bin_names
)
228 plt
.ylabel('Cumulative time spent in GC pauses (ms)')
229 plt
.xlabel('GC pause length')
230 plt
.xticks(rotation
=60)
231 plt
.legend(loc
='upper left')
233 major_gc_event_groups
= parse_major_gcs(data
)
236 indices
= kwargs
['indices']
237 pauses
= kwargs
['pauses']
238 color
= kwargs
['color']
239 if 'bottom' in kwargs
:
240 bottom
= kwargs
['bottom']
244 [index
for index
in indices
if pauses
[index
] is not None],
245 np
.array([pause
for pause
in pauses
if pause
is not None]),
250 indices
= np
.arange(len(major_gc_event_groups
))
252 event_group
.start
.stop
- event_group
.start
.start
253 if isinstance(event_group
, ConcurrentMajorGCEventGroup
) else None
254 for event_group
in major_gc_event_groups
263 update_event
.stop
- update_event
.start
264 for update_event
in event_group
.updates
265 ]) if isinstance(event_group
, ConcurrentMajorGCEventGroup
) else None
266 for event_group
in major_gc_event_groups
270 pauses
=update_pauses
,
272 bottom
=[pause
for pause
in start_pauses
if pause
is not None],
275 event_group
.finish
.stop
- event_group
.finish
.start
276 if isinstance(event_group
, ConcurrentMajorGCEventGroup
) else None
277 for event_group
in major_gc_event_groups
279 start_update_pauses
= [
281 for a
, b
in zip(start_pauses
, update_pauses
)
282 if a
is not None and b
is not None
286 pauses
=finish_pauses
,
288 bottom
=start_update_pauses
,
291 event_group
.event
.stop
- event_group
.event
.start
292 if isinstance(event_group
, FullMajorGCEventGroup
) else None
293 for event_group
in major_gc_event_groups
301 plt
.ylabel("Pause Time (ms)")
302 plt
.xlabel("Collection")