summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2019-05-08 11:06:38 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2019-05-08 22:56:45 +0100
commitd13b904305289df1d3ab81f86350d7ff99d2966d (patch)
treed257dfb716476880b316a7aa8cbebc9c505255d3 /scripts
parented5198463f61274f6f78bc5b1e2cded63d750c4c (diff)
downloadpoky-d13b904305289df1d3ab81f86350d7ff99d2966d.tar.gz
scripts/pybootchart: Fix mixed indentation
The script had a toxic mix of tabs and spaces, fix this. (From OE-Core rev: 5eebe246e9444a5a7dbf4d8683ae08c468cfc401) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/pybootchartgui/pybootchartgui/draw.py1378
1 files changed, 689 insertions, 689 deletions
diff --git a/scripts/pybootchartgui/pybootchartgui/draw.py b/scripts/pybootchartgui/pybootchartgui/draw.py
index 201ce4577f..019070a7db 100644
--- a/scripts/pybootchartgui/pybootchartgui/draw.py
+++ b/scripts/pybootchartgui/pybootchartgui/draw.py
@@ -23,18 +23,18 @@ from operator import itemgetter
23 23
24class RenderOptions: 24class RenderOptions:
25 25
26 def __init__(self, app_options): 26 def __init__(self, app_options):
27 # should we render a cumulative CPU time chart 27 # should we render a cumulative CPU time chart
28 self.cumulative = True 28 self.cumulative = True
29 self.charts = True 29 self.charts = True
30 self.kernel_only = False 30 self.kernel_only = False
31 self.app_options = app_options 31 self.app_options = app_options
32 32
33 def proc_tree (self, trace): 33 def proc_tree (self, trace):
34 if self.kernel_only: 34 if self.kernel_only:
35 return trace.kernel_tree 35 return trace.kernel_tree
36 else: 36 else:
37 return trace.proc_tree 37 return trace.proc_tree
38 38
39# Process tree background color. 39# Process tree background color.
40BACK_COLOR = (1.0, 1.0, 1.0, 1.0) 40BACK_COLOR = (1.0, 1.0, 1.0, 1.0)
@@ -136,11 +136,11 @@ TASK_COLOR_PACKAGE_WRITE = (0.0, 0.50, 0.50, 1.0)
136# Distinct colors used for different disk volumnes. 136# Distinct colors used for different disk volumnes.
137# If we have more volumns, colors get re-used. 137# If we have more volumns, colors get re-used.
138VOLUME_COLORS = [ 138VOLUME_COLORS = [
139 (1.0, 1.0, 0.00, 1.0), 139 (1.0, 1.0, 0.00, 1.0),
140 (0.0, 1.00, 0.00, 1.0), 140 (0.0, 1.00, 0.00, 1.0),
141 (1.0, 0.00, 1.00, 1.0), 141 (1.0, 0.00, 1.00, 1.0),
142 (0.0, 0.00, 1.00, 1.0), 142 (0.0, 0.00, 1.00, 1.0),
143 (0.0, 1.00, 1.00, 1.0), 143 (0.0, 1.00, 1.00, 1.0),
144] 144]
145 145
146# Process states 146# Process states
@@ -152,7 +152,7 @@ STATE_STOPPED = 4
152STATE_ZOMBIE = 5 152STATE_ZOMBIE = 5
153 153
154STATE_COLORS = [(0, 0, 0, 0), PROC_COLOR_R, PROC_COLOR_S, PROC_COLOR_D, \ 154STATE_COLORS = [(0, 0, 0, 0), PROC_COLOR_R, PROC_COLOR_S, PROC_COLOR_D, \
155 PROC_COLOR_T, PROC_COLOR_Z, PROC_COLOR_X, PROC_COLOR_W] 155 PROC_COLOR_T, PROC_COLOR_Z, PROC_COLOR_X, PROC_COLOR_W]
156 156
157# CumulativeStats Types 157# CumulativeStats Types
158STAT_TYPE_CPU = 0 158STAT_TYPE_CPU = 0
@@ -160,80 +160,80 @@ STAT_TYPE_IO = 1
160 160
161# Convert ps process state to an int 161# Convert ps process state to an int
162def get_proc_state(flag): 162def get_proc_state(flag):
163 return "RSDTZXW".find(flag) + 1 163 return "RSDTZXW".find(flag) + 1
164 164
165def draw_text(ctx, text, color, x, y): 165def draw_text(ctx, text, color, x, y):
166 ctx.set_source_rgba(*color) 166 ctx.set_source_rgba(*color)
167 ctx.move_to(x, y) 167 ctx.move_to(x, y)
168 ctx.show_text(text) 168 ctx.show_text(text)
169 169
170def draw_fill_rect(ctx, color, rect): 170def draw_fill_rect(ctx, color, rect):
171 ctx.set_source_rgba(*color) 171 ctx.set_source_rgba(*color)
172 ctx.rectangle(*rect) 172 ctx.rectangle(*rect)
173 ctx.fill() 173 ctx.fill()
174 174
175def draw_rect(ctx, color, rect): 175def draw_rect(ctx, color, rect):
176 ctx.set_source_rgba(*color) 176 ctx.set_source_rgba(*color)
177 ctx.rectangle(*rect) 177 ctx.rectangle(*rect)
178 ctx.stroke() 178 ctx.stroke()
179 179
180def draw_legend_box(ctx, label, fill_color, x, y, s): 180def draw_legend_box(ctx, label, fill_color, x, y, s):
181 draw_fill_rect(ctx, fill_color, (x, y - s, s, s)) 181 draw_fill_rect(ctx, fill_color, (x, y - s, s, s))
182 draw_rect(ctx, PROC_BORDER_COLOR, (x, y - s, s, s)) 182 draw_rect(ctx, PROC_BORDER_COLOR, (x, y - s, s, s))
183 draw_text(ctx, label, TEXT_COLOR, x + s + 5, y) 183 draw_text(ctx, label, TEXT_COLOR, x + s + 5, y)
184 184
185def draw_legend_line(ctx, label, fill_color, x, y, s): 185def draw_legend_line(ctx, label, fill_color, x, y, s):
186 draw_fill_rect(ctx, fill_color, (x, y - s/2, s + 1, 3)) 186 draw_fill_rect(ctx, fill_color, (x, y - s/2, s + 1, 3))
187 ctx.arc(x + (s + 1)/2.0, y - (s - 3)/2.0, 2.5, 0, 2.0 * math.pi) 187 ctx.arc(x + (s + 1)/2.0, y - (s - 3)/2.0, 2.5, 0, 2.0 * math.pi)
188 ctx.fill() 188 ctx.fill()
189 draw_text(ctx, label, TEXT_COLOR, x + s + 5, y) 189 draw_text(ctx, label, TEXT_COLOR, x + s + 5, y)
190 190
191def draw_label_in_box(ctx, color, label, x, y, w, maxx): 191def draw_label_in_box(ctx, color, label, x, y, w, maxx):
192 label_w = ctx.text_extents(label)[2] 192 label_w = ctx.text_extents(label)[2]
193 label_x = x + w / 2 - label_w / 2 193 label_x = x + w / 2 - label_w / 2
194 if label_w + 10 > w: 194 if label_w + 10 > w:
195 label_x = x + w + 5 195 label_x = x + w + 5
196 if label_x + label_w > maxx: 196 if label_x + label_w > maxx:
197 label_x = x - label_w - 5 197 label_x = x - label_w - 5
198 draw_text(ctx, label, color, label_x, y) 198 draw_text(ctx, label, color, label_x, y)
199 199
200def draw_sec_labels(ctx, options, rect, sec_w, nsecs): 200def draw_sec_labels(ctx, options, rect, sec_w, nsecs):
201 ctx.set_font_size(AXIS_FONT_SIZE) 201 ctx.set_font_size(AXIS_FONT_SIZE)
202 prev_x = 0 202 prev_x = 0
203 for i in range(0, rect[2] + 1, sec_w): 203 for i in range(0, rect[2] + 1, sec_w):
204 if ((i / sec_w) % nsecs == 0) : 204 if ((i / sec_w) % nsecs == 0) :
205 if options.app_options.as_minutes : 205 if options.app_options.as_minutes :
206 label = "%.1f" % (i / sec_w / 60.0) 206 label = "%.1f" % (i / sec_w / 60.0)
207 else : 207 else :
208 label = "%d" % (i / sec_w) 208 label = "%d" % (i / sec_w)
209 label_w = ctx.text_extents(label)[2] 209 label_w = ctx.text_extents(label)[2]
210 x = rect[0] + i - label_w/2 210 x = rect[0] + i - label_w/2
211 if x >= prev_x: 211 if x >= prev_x:
212 draw_text(ctx, label, TEXT_COLOR, x, rect[1] - 2) 212 draw_text(ctx, label, TEXT_COLOR, x, rect[1] - 2)
213 prev_x = x + label_w 213 prev_x = x + label_w
214 214
215def draw_box_ticks(ctx, rect, sec_w): 215def draw_box_ticks(ctx, rect, sec_w):
216 draw_rect(ctx, BORDER_COLOR, tuple(rect)) 216 draw_rect(ctx, BORDER_COLOR, tuple(rect))
217 217
218 ctx.set_line_cap(cairo.LINE_CAP_SQUARE) 218 ctx.set_line_cap(cairo.LINE_CAP_SQUARE)
219 219
220 for i in range(sec_w, rect[2] + 1, sec_w): 220 for i in range(sec_w, rect[2] + 1, sec_w):
221 if ((i / sec_w) % 10 == 0) : 221 if ((i / sec_w) % 10 == 0) :
222 ctx.set_line_width(1.5) 222 ctx.set_line_width(1.5)
223 elif sec_w < 5 : 223 elif sec_w < 5 :
224 continue 224 continue
225 else : 225 else :
226 ctx.set_line_width(1.0) 226 ctx.set_line_width(1.0)
227 if ((i / sec_w) % 30 == 0) : 227 if ((i / sec_w) % 30 == 0) :
228 ctx.set_source_rgba(*TICK_COLOR_BOLD) 228 ctx.set_source_rgba(*TICK_COLOR_BOLD)
229 else : 229 else :
230 ctx.set_source_rgba(*TICK_COLOR) 230 ctx.set_source_rgba(*TICK_COLOR)
231 ctx.move_to(rect[0] + i, rect[1] + 1) 231 ctx.move_to(rect[0] + i, rect[1] + 1)
232 ctx.line_to(rect[0] + i, rect[1] + rect[3] - 1) 232 ctx.line_to(rect[0] + i, rect[1] + rect[3] - 1)
233 ctx.stroke() 233 ctx.stroke()
234 ctx.set_line_width(1.0) 234 ctx.set_line_width(1.0)
235 235
236 ctx.set_line_cap(cairo.LINE_CAP_BUTT) 236 ctx.set_line_cap(cairo.LINE_CAP_BUTT)
237 237
238def draw_annotations(ctx, proc_tree, times, rect): 238def draw_annotations(ctx, proc_tree, times, rect):
239 ctx.set_line_cap(cairo.LINE_CAP_SQUARE) 239 ctx.set_line_cap(cairo.LINE_CAP_SQUARE)
@@ -252,51 +252,51 @@ def draw_annotations(ctx, proc_tree, times, rect):
252 ctx.set_dash([]) 252 ctx.set_dash([])
253 253
254def draw_chart(ctx, color, fill, chart_bounds, data, proc_tree, data_range): 254def draw_chart(ctx, color, fill, chart_bounds, data, proc_tree, data_range):
255 ctx.set_line_width(0.5) 255 ctx.set_line_width(0.5)
256 x_shift = proc_tree.start_time 256 x_shift = proc_tree.start_time
257 257
258 def transform_point_coords(point, x_base, y_base, \ 258 def transform_point_coords(point, x_base, y_base, \
259 xscale, yscale, x_trans, y_trans): 259 xscale, yscale, x_trans, y_trans):
260 x = (point[0] - x_base) * xscale + x_trans 260 x = (point[0] - x_base) * xscale + x_trans
261 y = (point[1] - y_base) * -yscale + y_trans + chart_bounds[3] 261 y = (point[1] - y_base) * -yscale + y_trans + chart_bounds[3]
262 return x, y 262 return x, y
263 263
264 max_x = max (x for (x, y) in data) 264 max_x = max (x for (x, y) in data)
265 max_y = max (y for (x, y) in data) 265 max_y = max (y for (x, y) in data)
266 # avoid divide by zero 266 # avoid divide by zero
267 if max_y == 0: 267 if max_y == 0:
268 max_y = 1.0 268 max_y = 1.0
269 xscale = float (chart_bounds[2]) / (max_x - x_shift) 269 xscale = float (chart_bounds[2]) / (max_x - x_shift)
270 # If data_range is given, scale the chart so that the value range in 270 # If data_range is given, scale the chart so that the value range in
271 # data_range matches the chart bounds exactly. 271 # data_range matches the chart bounds exactly.
272 # Otherwise, scale so that the actual data matches the chart bounds. 272 # Otherwise, scale so that the actual data matches the chart bounds.
273 if data_range: 273 if data_range:
274 yscale = float(chart_bounds[3]) / (data_range[1] - data_range[0]) 274 yscale = float(chart_bounds[3]) / (data_range[1] - data_range[0])
275 ybase = data_range[0] 275 ybase = data_range[0]
276 else: 276 else:
277 yscale = float(chart_bounds[3]) / max_y 277 yscale = float(chart_bounds[3]) / max_y
278 ybase = 0 278 ybase = 0
279 279
280 first = transform_point_coords (data[0], x_shift, ybase, xscale, yscale, \ 280 first = transform_point_coords (data[0], x_shift, ybase, xscale, yscale, \
281 chart_bounds[0], chart_bounds[1]) 281 chart_bounds[0], chart_bounds[1])
282 last = transform_point_coords (data[-1], x_shift, ybase, xscale, yscale, \ 282 last = transform_point_coords (data[-1], x_shift, ybase, xscale, yscale, \
283 chart_bounds[0], chart_bounds[1]) 283 chart_bounds[0], chart_bounds[1])
284 284
285 ctx.set_source_rgba(*color) 285 ctx.set_source_rgba(*color)
286 ctx.move_to(*first) 286 ctx.move_to(*first)
287 for point in data: 287 for point in data:
288 x, y = transform_point_coords (point, x_shift, ybase, xscale, yscale, \ 288 x, y = transform_point_coords (point, x_shift, ybase, xscale, yscale, \
289 chart_bounds[0], chart_bounds[1]) 289 chart_bounds[0], chart_bounds[1])
290 ctx.line_to(x, y) 290 ctx.line_to(x, y)
291 if fill: 291 if fill:
292 ctx.stroke_preserve() 292 ctx.stroke_preserve()
293 ctx.line_to(last[0], chart_bounds[1]+chart_bounds[3]) 293 ctx.line_to(last[0], chart_bounds[1]+chart_bounds[3])
294 ctx.line_to(first[0], chart_bounds[1]+chart_bounds[3]) 294 ctx.line_to(first[0], chart_bounds[1]+chart_bounds[3])
295 ctx.line_to(first[0], first[1]) 295 ctx.line_to(first[0], first[1])
296 ctx.fill() 296 ctx.fill()
297 else: 297 else:
298 ctx.stroke() 298 ctx.stroke()
299 ctx.set_line_width(1.0) 299 ctx.set_line_width(1.0)
300 300
301bar_h = 55 301bar_h = 55
302meminfo_bar_h = 2 * bar_h 302meminfo_bar_h = 2 * bar_h
@@ -311,338 +311,338 @@ CUML_HEIGHT = 2000 # Increased value to accomodate CPU and I/O Graphs
311OPTIONS = None 311OPTIONS = None
312 312
313def extents(options, xscale, trace): 313def extents(options, xscale, trace):
314 start = min(trace.start.keys()) 314 start = min(trace.start.keys())
315 end = start 315 end = start
316 316
317 processes = 0 317 processes = 0
318 for proc in trace.processes: 318 for proc in trace.processes:
319 if not options.app_options.show_all and \ 319 if not options.app_options.show_all and \
320 trace.processes[proc][1] - trace.processes[proc][0] < options.app_options.mintime: 320 trace.processes[proc][1] - trace.processes[proc][0] < options.app_options.mintime:
321 continue 321 continue
322 322
323 if trace.processes[proc][1] > end: 323 if trace.processes[proc][1] > end:
324 end = trace.processes[proc][1] 324 end = trace.processes[proc][1]
325 processes += 1 325 processes += 1
326 326
327 if trace.min is not None and trace.max is not None: 327 if trace.min is not None and trace.max is not None:
328 start = trace.min 328 start = trace.min
329 end = trace.max 329 end = trace.max
330 330
331 w = int ((end - start) * sec_w_base * xscale) + 2 * off_x 331 w = int ((end - start) * sec_w_base * xscale) + 2 * off_x
332 h = proc_h * processes + header_h + 2 * off_y 332 h = proc_h * processes + header_h + 2 * off_y
333 333
334 if options.charts: 334 if options.charts:
335 if trace.cpu_stats: 335 if trace.cpu_stats:
336 h += 30 + bar_h 336 h += 30 + bar_h
337 if trace.disk_stats: 337 if trace.disk_stats:
338 h += 30 + bar_h 338 h += 30 + bar_h
339 if trace.monitor_disk: 339 if trace.monitor_disk:
340 h += 30 + bar_h 340 h += 30 + bar_h
341 if trace.mem_stats: 341 if trace.mem_stats:
342 h += meminfo_bar_h 342 h += meminfo_bar_h
343 343
344 return (w, h) 344 return (w, h)
345 345
346def clip_visible(clip, rect): 346def clip_visible(clip, rect):
347 xmax = max (clip[0], rect[0]) 347 xmax = max (clip[0], rect[0])
348 ymax = max (clip[1], rect[1]) 348 ymax = max (clip[1], rect[1])
349 xmin = min (clip[0] + clip[2], rect[0] + rect[2]) 349 xmin = min (clip[0] + clip[2], rect[0] + rect[2])
350 ymin = min (clip[1] + clip[3], rect[1] + rect[3]) 350 ymin = min (clip[1] + clip[3], rect[1] + rect[3])
351 return (xmin > xmax and ymin > ymax) 351 return (xmin > xmax and ymin > ymax)
352 352
353def render_charts(ctx, options, clip, trace, curr_y, w, h, sec_w): 353def render_charts(ctx, options, clip, trace, curr_y, w, h, sec_w):
354 proc_tree = options.proc_tree(trace) 354 proc_tree = options.proc_tree(trace)
355 355
356 # render bar legend 356 # render bar legend
357 if trace.cpu_stats: 357 if trace.cpu_stats:
358 ctx.set_font_size(LEGEND_FONT_SIZE) 358 ctx.set_font_size(LEGEND_FONT_SIZE)
359 359
360 draw_legend_box(ctx, "CPU (user+sys)", CPU_COLOR, off_x, curr_y+20, leg_s) 360 draw_legend_box(ctx, "CPU (user+sys)", CPU_COLOR, off_x, curr_y+20, leg_s)
361 draw_legend_box(ctx, "I/O (wait)", IO_COLOR, off_x + 120, curr_y+20, leg_s) 361 draw_legend_box(ctx, "I/O (wait)", IO_COLOR, off_x + 120, curr_y+20, leg_s)
362 362
363 # render I/O wait 363 # render I/O wait
364 chart_rect = (off_x, curr_y+30, w, bar_h) 364 chart_rect = (off_x, curr_y+30, w, bar_h)
365 if clip_visible (clip, chart_rect): 365 if clip_visible (clip, chart_rect):
366 draw_box_ticks (ctx, chart_rect, sec_w) 366 draw_box_ticks (ctx, chart_rect, sec_w)
367 draw_annotations (ctx, proc_tree, trace.times, chart_rect) 367 draw_annotations (ctx, proc_tree, trace.times, chart_rect)
368 draw_chart (ctx, IO_COLOR, True, chart_rect, \ 368 draw_chart (ctx, IO_COLOR, True, chart_rect, \
369 [(sample.time, sample.user + sample.sys + sample.io) for sample in trace.cpu_stats], \ 369 [(sample.time, sample.user + sample.sys + sample.io) for sample in trace.cpu_stats], \
370 proc_tree, None) 370 proc_tree, None)
371 # render CPU load 371 # render CPU load
372 draw_chart (ctx, CPU_COLOR, True, chart_rect, \ 372 draw_chart (ctx, CPU_COLOR, True, chart_rect, \
373 [(sample.time, sample.user + sample.sys) for sample in trace.cpu_stats], \ 373 [(sample.time, sample.user + sample.sys) for sample in trace.cpu_stats], \
374 proc_tree, None) 374 proc_tree, None)
375 375
376 curr_y = curr_y + 30 + bar_h 376 curr_y = curr_y + 30 + bar_h
377 377
378 # render second chart 378 # render second chart
379 if trace.disk_stats: 379 if trace.disk_stats:
380 draw_legend_line(ctx, "Disk throughput", DISK_TPUT_COLOR, off_x, curr_y+20, leg_s) 380 draw_legend_line(ctx, "Disk throughput", DISK_TPUT_COLOR, off_x, curr_y+20, leg_s)
381 draw_legend_box(ctx, "Disk utilization", IO_COLOR, off_x + 120, curr_y+20, leg_s) 381 draw_legend_box(ctx, "Disk utilization", IO_COLOR, off_x + 120, curr_y+20, leg_s)
382 382
383 # render I/O utilization 383 # render I/O utilization
384 chart_rect = (off_x, curr_y+30, w, bar_h) 384 chart_rect = (off_x, curr_y+30, w, bar_h)
385 if clip_visible (clip, chart_rect): 385 if clip_visible (clip, chart_rect):
386 draw_box_ticks (ctx, chart_rect, sec_w) 386 draw_box_ticks (ctx, chart_rect, sec_w)
387 draw_annotations (ctx, proc_tree, trace.times, chart_rect) 387 draw_annotations (ctx, proc_tree, trace.times, chart_rect)
388 draw_chart (ctx, IO_COLOR, True, chart_rect, \ 388 draw_chart (ctx, IO_COLOR, True, chart_rect, \
389 [(sample.time, sample.util) for sample in trace.disk_stats], \ 389 [(sample.time, sample.util) for sample in trace.disk_stats], \
390 proc_tree, None) 390 proc_tree, None)
391 391
392 # render disk throughput 392 # render disk throughput
393 max_sample = max (trace.disk_stats, key = lambda s: s.tput) 393 max_sample = max (trace.disk_stats, key = lambda s: s.tput)
394 if clip_visible (clip, chart_rect): 394 if clip_visible (clip, chart_rect):
395 draw_chart (ctx, DISK_TPUT_COLOR, False, chart_rect, \ 395 draw_chart (ctx, DISK_TPUT_COLOR, False, chart_rect, \
396 [(sample.time, sample.tput) for sample in trace.disk_stats], \ 396 [(sample.time, sample.tput) for sample in trace.disk_stats], \
397 proc_tree, None) 397 proc_tree, None)
398 398
399 pos_x = off_x + ((max_sample.time - proc_tree.start_time) * w / proc_tree.duration) 399 pos_x = off_x + ((max_sample.time - proc_tree.start_time) * w / proc_tree.duration)
400 400
401 shift_x, shift_y = -20, 20 401 shift_x, shift_y = -20, 20
402 if (pos_x < off_x + 245): 402 if (pos_x < off_x + 245):
403 shift_x, shift_y = 5, 40 403 shift_x, shift_y = 5, 40
404 404
405 label = "%dMB/s" % round ((max_sample.tput) / 1024.0) 405 label = "%dMB/s" % round ((max_sample.tput) / 1024.0)
406 draw_text (ctx, label, DISK_TPUT_COLOR, pos_x + shift_x, curr_y + shift_y) 406 draw_text (ctx, label, DISK_TPUT_COLOR, pos_x + shift_x, curr_y + shift_y)
407 407
408 curr_y = curr_y + 30 + bar_h 408 curr_y = curr_y + 30 + bar_h
409 409
410 # render disk space usage 410 # render disk space usage
411 # 411 #
412 # Draws the amount of disk space used on each volume relative to the 412 # Draws the amount of disk space used on each volume relative to the
413 # lowest recorded amount. The graphs for each volume are stacked above 413 # lowest recorded amount. The graphs for each volume are stacked above
414 # each other so that total disk usage is visible. 414 # each other so that total disk usage is visible.
415 if trace.monitor_disk: 415 if trace.monitor_disk:
416 ctx.set_font_size(LEGEND_FONT_SIZE) 416 ctx.set_font_size(LEGEND_FONT_SIZE)
417 # Determine set of volumes for which we have 417 # Determine set of volumes for which we have
418 # information and the minimal amount of used disk 418 # information and the minimal amount of used disk
419 # space for each. Currently samples are allowed to 419 # space for each. Currently samples are allowed to
420 # not have a values for all volumes; drawing could be 420 # not have a values for all volumes; drawing could be
421 # made more efficient if that wasn't the case. 421 # made more efficient if that wasn't the case.
422 volumes = set() 422 volumes = set()
423 min_used = {} 423 min_used = {}
424 for sample in trace.monitor_disk: 424 for sample in trace.monitor_disk:
425 for volume, used in sample.records.items(): 425 for volume, used in sample.records.items():
426 volumes.add(volume) 426 volumes.add(volume)
427 if volume not in min_used or min_used[volume] > used: 427 if volume not in min_used or min_used[volume] > used:
428 min_used[volume] = used 428 min_used[volume] = used
429 volumes = sorted(list(volumes)) 429 volumes = sorted(list(volumes))
430 disk_scale = 0 430 disk_scale = 0
431 for i, volume in enumerate(volumes): 431 for i, volume in enumerate(volumes):
432 volume_scale = max([sample.records[volume] - min_used[volume] 432 volume_scale = max([sample.records[volume] - min_used[volume]
433 for sample in trace.monitor_disk 433 for sample in trace.monitor_disk
434 if volume in sample.records]) 434 if volume in sample.records])
435 # Does not take length of volume name into account, but fixed offset 435 # Does not take length of volume name into account, but fixed offset
436 # works okay in practice. 436 # works okay in practice.
437 draw_legend_box(ctx, '%s (max: %u MiB)' % (volume, volume_scale / 1024 / 1024), 437 draw_legend_box(ctx, '%s (max: %u MiB)' % (volume, volume_scale / 1024 / 1024),
438 VOLUME_COLORS[i % len(VOLUME_COLORS)], 438 VOLUME_COLORS[i % len(VOLUME_COLORS)],
439 off_x + i * 250, curr_y+20, leg_s) 439 off_x + i * 250, curr_y+20, leg_s)
440 disk_scale += volume_scale 440 disk_scale += volume_scale
441 441
442 # render used amount of disk space 442 # render used amount of disk space
443 chart_rect = (off_x, curr_y+30, w, bar_h) 443 chart_rect = (off_x, curr_y+30, w, bar_h)
444 if clip_visible (clip, chart_rect): 444 if clip_visible (clip, chart_rect):
445 draw_box_ticks (ctx, chart_rect, sec_w) 445 draw_box_ticks (ctx, chart_rect, sec_w)
446 draw_annotations (ctx, proc_tree, trace.times, chart_rect) 446 draw_annotations (ctx, proc_tree, trace.times, chart_rect)
447 for i in range(len(volumes), 0, -1): 447 for i in range(len(volumes), 0, -1):
448 draw_chart (ctx, VOLUME_COLORS[(i - 1) % len(VOLUME_COLORS)], True, chart_rect, \ 448 draw_chart (ctx, VOLUME_COLORS[(i - 1) % len(VOLUME_COLORS)], True, chart_rect, \
449 [(sample.time, 449 [(sample.time,
450 # Sum up used space of all volumes including the current one 450 # Sum up used space of all volumes including the current one
451 # so that the graphs appear as stacked on top of each other. 451 # so that the graphs appear as stacked on top of each other.
452 reduce(lambda x,y: x+y, 452 reduce(lambda x,y: x+y,
453 [sample.records[volume] - min_used[volume] 453 [sample.records[volume] - min_used[volume]
454 for volume in volumes[0:i] 454 for volume in volumes[0:i]
455 if volume in sample.records], 455 if volume in sample.records],
456 0)) 456 0))
457 for sample in trace.monitor_disk], \ 457 for sample in trace.monitor_disk], \
458 proc_tree, [0, disk_scale]) 458 proc_tree, [0, disk_scale])
459 459
460 curr_y = curr_y + 30 + bar_h 460 curr_y = curr_y + 30 + bar_h
461 461
462 # render mem usage 462 # render mem usage
463 chart_rect = (off_x, curr_y+30, w, meminfo_bar_h) 463 chart_rect = (off_x, curr_y+30, w, meminfo_bar_h)
464 mem_stats = trace.mem_stats 464 mem_stats = trace.mem_stats
465 if mem_stats and clip_visible (clip, chart_rect): 465 if mem_stats and clip_visible (clip, chart_rect):
466 mem_scale = max(sample.buffers for sample in mem_stats) 466 mem_scale = max(sample.buffers for sample in mem_stats)
467 draw_legend_box(ctx, "Mem cached (scale: %u MiB)" % (float(mem_scale) / 1024), MEM_CACHED_COLOR, off_x, curr_y+20, leg_s) 467 draw_legend_box(ctx, "Mem cached (scale: %u MiB)" % (float(mem_scale) / 1024), MEM_CACHED_COLOR, off_x, curr_y+20, leg_s)
468 draw_legend_box(ctx, "Used", MEM_USED_COLOR, off_x + 240, curr_y+20, leg_s) 468 draw_legend_box(ctx, "Used", MEM_USED_COLOR, off_x + 240, curr_y+20, leg_s)
469 draw_legend_box(ctx, "Buffers", MEM_BUFFERS_COLOR, off_x + 360, curr_y+20, leg_s) 469 draw_legend_box(ctx, "Buffers", MEM_BUFFERS_COLOR, off_x + 360, curr_y+20, leg_s)
470 draw_legend_line(ctx, "Swap (scale: %u MiB)" % max([(sample.swap)/1024 for sample in mem_stats]), \ 470 draw_legend_line(ctx, "Swap (scale: %u MiB)" % max([(sample.swap)/1024 for sample in mem_stats]), \
471 MEM_SWAP_COLOR, off_x + 480, curr_y+20, leg_s) 471 MEM_SWAP_COLOR, off_x + 480, curr_y+20, leg_s)
472 draw_box_ticks(ctx, chart_rect, sec_w) 472 draw_box_ticks(ctx, chart_rect, sec_w)
473 draw_annotations(ctx, proc_tree, trace.times, chart_rect) 473 draw_annotations(ctx, proc_tree, trace.times, chart_rect)
474 draw_chart(ctx, MEM_BUFFERS_COLOR, True, chart_rect, \ 474 draw_chart(ctx, MEM_BUFFERS_COLOR, True, chart_rect, \
475 [(sample.time, sample.buffers) for sample in trace.mem_stats], \ 475 [(sample.time, sample.buffers) for sample in trace.mem_stats], \
476 proc_tree, [0, mem_scale]) 476 proc_tree, [0, mem_scale])
477 draw_chart(ctx, MEM_USED_COLOR, True, chart_rect, \ 477 draw_chart(ctx, MEM_USED_COLOR, True, chart_rect, \
478 [(sample.time, sample.used) for sample in mem_stats], \ 478 [(sample.time, sample.used) for sample in mem_stats], \
479 proc_tree, [0, mem_scale]) 479 proc_tree, [0, mem_scale])
480 draw_chart(ctx, MEM_CACHED_COLOR, True, chart_rect, \ 480 draw_chart(ctx, MEM_CACHED_COLOR, True, chart_rect, \
481 [(sample.time, sample.cached) for sample in mem_stats], \ 481 [(sample.time, sample.cached) for sample in mem_stats], \
482 proc_tree, [0, mem_scale]) 482 proc_tree, [0, mem_scale])
483 draw_chart(ctx, MEM_SWAP_COLOR, False, chart_rect, \ 483 draw_chart(ctx, MEM_SWAP_COLOR, False, chart_rect, \
484 [(sample.time, float(sample.swap)) for sample in mem_stats], \ 484 [(sample.time, float(sample.swap)) for sample in mem_stats], \
485 proc_tree, None) 485 proc_tree, None)
486 486
487 curr_y = curr_y + meminfo_bar_h 487 curr_y = curr_y + meminfo_bar_h
488 488
489 return curr_y 489 return curr_y
490 490
491def render_processes_chart(ctx, options, trace, curr_y, w, h, sec_w): 491def render_processes_chart(ctx, options, trace, curr_y, w, h, sec_w):
492 chart_rect = [off_x, curr_y+header_h, w, h - 2 * off_y - header_h - leg_s + proc_h] 492 chart_rect = [off_x, curr_y+header_h, w, h - 2 * off_y - header_h - leg_s + proc_h]
493 493
494 draw_legend_box (ctx, "Configure", \ 494 draw_legend_box (ctx, "Configure", \
495 TASK_COLOR_CONFIGURE, off_x , curr_y + 45, leg_s) 495 TASK_COLOR_CONFIGURE, off_x , curr_y + 45, leg_s)
496 draw_legend_box (ctx, "Compile", \ 496 draw_legend_box (ctx, "Compile", \
497 TASK_COLOR_COMPILE, off_x+120, curr_y + 45, leg_s) 497 TASK_COLOR_COMPILE, off_x+120, curr_y + 45, leg_s)
498 draw_legend_box (ctx, "Install", \ 498 draw_legend_box (ctx, "Install", \
499 TASK_COLOR_INSTALL, off_x+240, curr_y + 45, leg_s) 499 TASK_COLOR_INSTALL, off_x+240, curr_y + 45, leg_s)
500 draw_legend_box (ctx, "Populate Sysroot", \ 500 draw_legend_box (ctx, "Populate Sysroot", \
501 TASK_COLOR_SYSROOT, off_x+360, curr_y + 45, leg_s) 501 TASK_COLOR_SYSROOT, off_x+360, curr_y + 45, leg_s)
502 draw_legend_box (ctx, "Package", \ 502 draw_legend_box (ctx, "Package", \
503 TASK_COLOR_PACKAGE, off_x+480, curr_y + 45, leg_s) 503 TASK_COLOR_PACKAGE, off_x+480, curr_y + 45, leg_s)
504 draw_legend_box (ctx, "Package Write", 504 draw_legend_box (ctx, "Package Write",
505 TASK_COLOR_PACKAGE_WRITE, off_x+600, curr_y + 45, leg_s) 505 TASK_COLOR_PACKAGE_WRITE, off_x+600, curr_y + 45, leg_s)
506 506
507 ctx.set_font_size(PROC_TEXT_FONT_SIZE) 507 ctx.set_font_size(PROC_TEXT_FONT_SIZE)
508 508
509 draw_box_ticks(ctx, chart_rect, sec_w) 509 draw_box_ticks(ctx, chart_rect, sec_w)
510 draw_sec_labels(ctx, options, chart_rect, sec_w, 30) 510 draw_sec_labels(ctx, options, chart_rect, sec_w, 30)
511 511
512 y = curr_y+header_h 512 y = curr_y+header_h
513 513
514 offset = trace.min or min(trace.start.keys()) 514 offset = trace.min or min(trace.start.keys())
515 for s in sorted(trace.start.keys()): 515 for s in sorted(trace.start.keys()):
516 for val in sorted(trace.start[s]): 516 for val in sorted(trace.start[s]):
517 if not options.app_options.show_all and \ 517 if not options.app_options.show_all and \
518 trace.processes[val][1] - s < options.app_options.mintime: 518 trace.processes[val][1] - s < options.app_options.mintime:
519 continue 519 continue
520 task = val.split(":")[1] 520 task = val.split(":")[1]
521 #print val 521 #print val
522 #print trace.processes[val][1] 522 #print trace.processes[val][1]
523 #print s 523 #print s
524 x = chart_rect[0] + (s - offset) * sec_w 524 x = chart_rect[0] + (s - offset) * sec_w
525 w = ((trace.processes[val][1] - s) * sec_w) 525 w = ((trace.processes[val][1] - s) * sec_w)
526 526
527 #print "proc at %s %s %s %s" % (x, y, w, proc_h) 527 #print "proc at %s %s %s %s" % (x, y, w, proc_h)
528 col = None 528 col = None
529 if task == "do_compile": 529 if task == "do_compile":
530 col = TASK_COLOR_COMPILE 530 col = TASK_COLOR_COMPILE
531 elif task == "do_configure": 531 elif task == "do_configure":
532 col = TASK_COLOR_CONFIGURE 532 col = TASK_COLOR_CONFIGURE
533 elif task == "do_install": 533 elif task == "do_install":
534 col = TASK_COLOR_INSTALL 534 col = TASK_COLOR_INSTALL
535 elif task == "do_populate_sysroot": 535 elif task == "do_populate_sysroot":
536 col = TASK_COLOR_SYSROOT 536 col = TASK_COLOR_SYSROOT
537 elif task == "do_package": 537 elif task == "do_package":
538 col = TASK_COLOR_PACKAGE 538 col = TASK_COLOR_PACKAGE
539 elif task == "do_package_write_rpm" or \ 539 elif task == "do_package_write_rpm" or \
540 task == "do_package_write_deb" or \ 540 task == "do_package_write_deb" or \
541 task == "do_package_write_ipk": 541 task == "do_package_write_ipk":
542 col = TASK_COLOR_PACKAGE_WRITE 542 col = TASK_COLOR_PACKAGE_WRITE
543 else: 543 else:
544 col = WHITE 544 col = WHITE
545 545
546 if col: 546 if col:
547 draw_fill_rect(ctx, col, (x, y, w, proc_h)) 547 draw_fill_rect(ctx, col, (x, y, w, proc_h))
548 draw_rect(ctx, PROC_BORDER_COLOR, (x, y, w, proc_h)) 548 draw_rect(ctx, PROC_BORDER_COLOR, (x, y, w, proc_h))
549 549
550 draw_label_in_box(ctx, PROC_TEXT_COLOR, val, x, y + proc_h - 4, w, proc_h) 550 draw_label_in_box(ctx, PROC_TEXT_COLOR, val, x, y + proc_h - 4, w, proc_h)
551 y = y + proc_h 551 y = y + proc_h
552 552
553 return curr_y 553 return curr_y
554 554
555# 555#
556# Render the chart. 556# Render the chart.
557# 557#
558def render(ctx, options, xscale, trace): 558def render(ctx, options, xscale, trace):
559 (w, h) = extents (options, xscale, trace) 559 (w, h) = extents (options, xscale, trace)
560 global OPTIONS 560 global OPTIONS
561 OPTIONS = options.app_options 561 OPTIONS = options.app_options
562 562
563 # x, y, w, h 563 # x, y, w, h
564 clip = ctx.clip_extents() 564 clip = ctx.clip_extents()
565 565
566 sec_w = int (xscale * sec_w_base) 566 sec_w = int (xscale * sec_w_base)
567 ctx.set_line_width(1.0) 567 ctx.set_line_width(1.0)
568 ctx.select_font_face(FONT_NAME) 568 ctx.select_font_face(FONT_NAME)
569 draw_fill_rect(ctx, WHITE, (0, 0, max(w, MIN_IMG_W), h)) 569 draw_fill_rect(ctx, WHITE, (0, 0, max(w, MIN_IMG_W), h))
570 w -= 2*off_x 570 w -= 2*off_x
571 curr_y = off_y; 571 curr_y = off_y;
572 572
573 if options.charts: 573 if options.charts:
574 curr_y = render_charts (ctx, options, clip, trace, curr_y, w, h, sec_w) 574 curr_y = render_charts (ctx, options, clip, trace, curr_y, w, h, sec_w)
575 575
576 curr_y = render_processes_chart (ctx, options, trace, curr_y, w, h, sec_w) 576 curr_y = render_processes_chart (ctx, options, trace, curr_y, w, h, sec_w)
577 577
578 return 578 return
579 579
580 proc_tree = options.proc_tree (trace) 580 proc_tree = options.proc_tree (trace)
581 581
582 # draw the title and headers 582 # draw the title and headers
583 if proc_tree.idle: 583 if proc_tree.idle:
584 duration = proc_tree.idle 584 duration = proc_tree.idle
585 else: 585 else:
586 duration = proc_tree.duration 586 duration = proc_tree.duration
587 587
588 if not options.kernel_only: 588 if not options.kernel_only:
589 curr_y = draw_header (ctx, trace.headers, duration) 589 curr_y = draw_header (ctx, trace.headers, duration)
590 else: 590 else:
591 curr_y = off_y; 591 curr_y = off_y;
592 592
593 # draw process boxes 593 # draw process boxes
594 proc_height = h 594 proc_height = h
595 if proc_tree.taskstats and options.cumulative: 595 if proc_tree.taskstats and options.cumulative:
596 proc_height -= CUML_HEIGHT 596 proc_height -= CUML_HEIGHT
597 597
598 draw_process_bar_chart(ctx, clip, options, proc_tree, trace.times, 598 draw_process_bar_chart(ctx, clip, options, proc_tree, trace.times,
599 curr_y, w, proc_height, sec_w) 599 curr_y, w, proc_height, sec_w)
600 600
601 curr_y = proc_height 601 curr_y = proc_height
602 ctx.set_font_size(SIG_FONT_SIZE) 602 ctx.set_font_size(SIG_FONT_SIZE)
603 draw_text(ctx, SIGNATURE, SIG_COLOR, off_x + 5, proc_height - 8) 603 draw_text(ctx, SIGNATURE, SIG_COLOR, off_x + 5, proc_height - 8)
604 604
605 # draw a cumulative CPU-time-per-process graph 605 # draw a cumulative CPU-time-per-process graph
606 if proc_tree.taskstats and options.cumulative: 606 if proc_tree.taskstats and options.cumulative:
607 cuml_rect = (off_x, curr_y + off_y, w, CUML_HEIGHT/2 - off_y * 2) 607 cuml_rect = (off_x, curr_y + off_y, w, CUML_HEIGHT/2 - off_y * 2)
608 if clip_visible (clip, cuml_rect): 608 if clip_visible (clip, cuml_rect):
609 draw_cuml_graph(ctx, proc_tree, cuml_rect, duration, sec_w, STAT_TYPE_CPU) 609 draw_cuml_graph(ctx, proc_tree, cuml_rect, duration, sec_w, STAT_TYPE_CPU)
610 610
611 # draw a cumulative I/O-time-per-process graph 611 # draw a cumulative I/O-time-per-process graph
612 if proc_tree.taskstats and options.cumulative: 612 if proc_tree.taskstats and options.cumulative:
613 cuml_rect = (off_x, curr_y + off_y * 100, w, CUML_HEIGHT/2 - off_y * 2) 613 cuml_rect = (off_x, curr_y + off_y * 100, w, CUML_HEIGHT/2 - off_y * 2)
614 if clip_visible (clip, cuml_rect): 614 if clip_visible (clip, cuml_rect):
615 draw_cuml_graph(ctx, proc_tree, cuml_rect, duration, sec_w, STAT_TYPE_IO) 615 draw_cuml_graph(ctx, proc_tree, cuml_rect, duration, sec_w, STAT_TYPE_IO)
616 616
617def draw_process_bar_chart(ctx, clip, options, proc_tree, times, curr_y, w, h, sec_w): 617def draw_process_bar_chart(ctx, clip, options, proc_tree, times, curr_y, w, h, sec_w):
618 header_size = 0 618 header_size = 0
619 if not options.kernel_only: 619 if not options.kernel_only:
620 draw_legend_box (ctx, "Running (%cpu)", 620 draw_legend_box (ctx, "Running (%cpu)",
621 PROC_COLOR_R, off_x , curr_y + 45, leg_s) 621 PROC_COLOR_R, off_x , curr_y + 45, leg_s)
622 draw_legend_box (ctx, "Unint.sleep (I/O)", 622 draw_legend_box (ctx, "Unint.sleep (I/O)",
623 PROC_COLOR_D, off_x+120, curr_y + 45, leg_s) 623 PROC_COLOR_D, off_x+120, curr_y + 45, leg_s)
624 draw_legend_box (ctx, "Sleeping", 624 draw_legend_box (ctx, "Sleeping",
625 PROC_COLOR_S, off_x+240, curr_y + 45, leg_s) 625 PROC_COLOR_S, off_x+240, curr_y + 45, leg_s)
626 draw_legend_box (ctx, "Zombie", 626 draw_legend_box (ctx, "Zombie",
627 PROC_COLOR_Z, off_x+360, curr_y + 45, leg_s) 627 PROC_COLOR_Z, off_x+360, curr_y + 45, leg_s)
628 header_size = 45 628 header_size = 45
629 629
630 chart_rect = [off_x, curr_y + header_size + 15, 630 chart_rect = [off_x, curr_y + header_size + 15,
631 w, h - 2 * off_y - (curr_y + header_size + 15) + proc_h] 631 w, h - 2 * off_y - (curr_y + header_size + 15) + proc_h]
632 ctx.set_font_size (PROC_TEXT_FONT_SIZE) 632 ctx.set_font_size (PROC_TEXT_FONT_SIZE)
633 633
634 draw_box_ticks (ctx, chart_rect, sec_w) 634 draw_box_ticks (ctx, chart_rect, sec_w)
635 if sec_w > 100: 635 if sec_w > 100:
636 nsec = 1 636 nsec = 1
637 else: 637 else:
638 nsec = 5 638 nsec = 5
639 draw_sec_labels (ctx, options, chart_rect, sec_w, nsec) 639 draw_sec_labels (ctx, options, chart_rect, sec_w, nsec)
640 draw_annotations (ctx, proc_tree, times, chart_rect) 640 draw_annotations (ctx, proc_tree, times, chart_rect)
641 641
642 y = curr_y + 60 642 y = curr_y + 60
643 for root in proc_tree.process_tree: 643 for root in proc_tree.process_tree:
644 draw_processes_recursively(ctx, root, proc_tree, y, proc_h, chart_rect, clip) 644 draw_processes_recursively(ctx, root, proc_tree, y, proc_h, chart_rect, clip)
645 y = y + proc_h * proc_tree.num_nodes([root]) 645 y = y + proc_h * proc_tree.num_nodes([root])
646 646
647 647
648def draw_header (ctx, headers, duration): 648def draw_header (ctx, headers, duration):
@@ -678,291 +678,291 @@ def draw_header (ctx, headers, duration):
678 return header_y 678 return header_y
679 679
680def draw_processes_recursively(ctx, proc, proc_tree, y, proc_h, rect, clip) : 680def draw_processes_recursively(ctx, proc, proc_tree, y, proc_h, rect, clip) :
681 x = rect[0] + ((proc.start_time - proc_tree.start_time) * rect[2] / proc_tree.duration) 681 x = rect[0] + ((proc.start_time - proc_tree.start_time) * rect[2] / proc_tree.duration)
682 w = ((proc.duration) * rect[2] / proc_tree.duration) 682 w = ((proc.duration) * rect[2] / proc_tree.duration)
683 683
684 draw_process_activity_colors(ctx, proc, proc_tree, x, y, w, proc_h, rect, clip) 684 draw_process_activity_colors(ctx, proc, proc_tree, x, y, w, proc_h, rect, clip)
685 draw_rect(ctx, PROC_BORDER_COLOR, (x, y, w, proc_h)) 685 draw_rect(ctx, PROC_BORDER_COLOR, (x, y, w, proc_h))
686 ipid = int(proc.pid) 686 ipid = int(proc.pid)
687 if not OPTIONS.show_all: 687 if not OPTIONS.show_all:
688 cmdString = proc.cmd 688 cmdString = proc.cmd
689 else: 689 else:
690 cmdString = '' 690 cmdString = ''
691 if (OPTIONS.show_pid or OPTIONS.show_all) and ipid is not 0: 691 if (OPTIONS.show_pid or OPTIONS.show_all) and ipid is not 0:
692 cmdString = cmdString + " [" + str(ipid // 1000) + "]" 692 cmdString = cmdString + " [" + str(ipid // 1000) + "]"
693 if OPTIONS.show_all: 693 if OPTIONS.show_all:
694 if proc.args: 694 if proc.args:
695 cmdString = cmdString + " '" + "' '".join(proc.args) + "'" 695 cmdString = cmdString + " '" + "' '".join(proc.args) + "'"
696 else: 696 else:
697 cmdString = cmdString + " " + proc.exe 697 cmdString = cmdString + " " + proc.exe
698 698
699 draw_label_in_box(ctx, PROC_TEXT_COLOR, cmdString, x, y + proc_h - 4, w, rect[0] + rect[2]) 699 draw_label_in_box(ctx, PROC_TEXT_COLOR, cmdString, x, y + proc_h - 4, w, rect[0] + rect[2])
700 700
701 next_y = y + proc_h 701 next_y = y + proc_h
702 for child in proc.child_list: 702 for child in proc.child_list:
703 if next_y > clip[1] + clip[3]: 703 if next_y > clip[1] + clip[3]:
704 break 704 break
705 child_x, child_y = draw_processes_recursively(ctx, child, proc_tree, next_y, proc_h, rect, clip) 705 child_x, child_y = draw_processes_recursively(ctx, child, proc_tree, next_y, proc_h, rect, clip)
706 draw_process_connecting_lines(ctx, x, y, child_x, child_y, proc_h) 706 draw_process_connecting_lines(ctx, x, y, child_x, child_y, proc_h)
707 next_y = next_y + proc_h * proc_tree.num_nodes([child]) 707 next_y = next_y + proc_h * proc_tree.num_nodes([child])
708 708
709 return x, y 709 return x, y
710 710
711 711
712def draw_process_activity_colors(ctx, proc, proc_tree, x, y, w, proc_h, rect, clip): 712def draw_process_activity_colors(ctx, proc, proc_tree, x, y, w, proc_h, rect, clip):
713 713
714 if y > clip[1] + clip[3] or y + proc_h + 2 < clip[1]: 714 if y > clip[1] + clip[3] or y + proc_h + 2 < clip[1]:
715 return 715 return
716 716
717 draw_fill_rect(ctx, PROC_COLOR_S, (x, y, w, proc_h)) 717 draw_fill_rect(ctx, PROC_COLOR_S, (x, y, w, proc_h))
718 718
719 last_tx = -1 719 last_tx = -1
720 for sample in proc.samples : 720 for sample in proc.samples :
721 tx = rect[0] + round(((sample.time - proc_tree.start_time) * rect[2] / proc_tree.duration)) 721 tx = rect[0] + round(((sample.time - proc_tree.start_time) * rect[2] / proc_tree.duration))
722 722
723 # samples are sorted chronologically 723 # samples are sorted chronologically
724 if tx < clip[0]: 724 if tx < clip[0]:
725 continue 725 continue
726 if tx > clip[0] + clip[2]: 726 if tx > clip[0] + clip[2]:
727 break 727 break
728 728
729 tw = round(proc_tree.sample_period * rect[2] / float(proc_tree.duration)) 729 tw = round(proc_tree.sample_period * rect[2] / float(proc_tree.duration))
730 if last_tx != -1 and abs(last_tx - tx) <= tw: 730 if last_tx != -1 and abs(last_tx - tx) <= tw:
731 tw -= last_tx - tx 731 tw -= last_tx - tx
732 tx = last_tx 732 tx = last_tx
733 tw = max (tw, 1) # nice to see at least something 733 tw = max (tw, 1) # nice to see at least something
734 734
735 last_tx = tx + tw 735 last_tx = tx + tw
736 state = get_proc_state( sample.state ) 736 state = get_proc_state( sample.state )
737 737
738 color = STATE_COLORS[state] 738 color = STATE_COLORS[state]
739 if state == STATE_RUNNING: 739 if state == STATE_RUNNING:
740 alpha = min (sample.cpu_sample.user + sample.cpu_sample.sys, 1.0) 740 alpha = min (sample.cpu_sample.user + sample.cpu_sample.sys, 1.0)
741 color = tuple(list(PROC_COLOR_R[0:3]) + [alpha]) 741 color = tuple(list(PROC_COLOR_R[0:3]) + [alpha])
742# print "render time %d [ tx %d tw %d ], sample state %s color %s alpha %g" % (sample.time, tx, tw, state, color, alpha) 742# print "render time %d [ tx %d tw %d ], sample state %s color %s alpha %g" % (sample.time, tx, tw, state, color, alpha)
743 elif state == STATE_SLEEPING: 743 elif state == STATE_SLEEPING:
744 continue 744 continue
745 745
746 draw_fill_rect(ctx, color, (tx, y, tw, proc_h)) 746 draw_fill_rect(ctx, color, (tx, y, tw, proc_h))
747 747
748def draw_process_connecting_lines(ctx, px, py, x, y, proc_h): 748def draw_process_connecting_lines(ctx, px, py, x, y, proc_h):
749 ctx.set_source_rgba(*DEP_COLOR) 749 ctx.set_source_rgba(*DEP_COLOR)
750 ctx.set_dash([2, 2]) 750 ctx.set_dash([2, 2])
751 if abs(px - x) < 3: 751 if abs(px - x) < 3:
752 dep_off_x = 3 752 dep_off_x = 3
753 dep_off_y = proc_h / 4 753 dep_off_y = proc_h / 4
754 ctx.move_to(x, y + proc_h / 2) 754 ctx.move_to(x, y + proc_h / 2)
755 ctx.line_to(px - dep_off_x, y + proc_h / 2) 755 ctx.line_to(px - dep_off_x, y + proc_h / 2)
756 ctx.line_to(px - dep_off_x, py - dep_off_y) 756 ctx.line_to(px - dep_off_x, py - dep_off_y)
757 ctx.line_to(px, py - dep_off_y) 757 ctx.line_to(px, py - dep_off_y)
758 else: 758 else:
759 ctx.move_to(x, y + proc_h / 2) 759 ctx.move_to(x, y + proc_h / 2)
760 ctx.line_to(px, y + proc_h / 2) 760 ctx.line_to(px, y + proc_h / 2)
761 ctx.line_to(px, py) 761 ctx.line_to(px, py)
762 ctx.stroke() 762 ctx.stroke()
763 ctx.set_dash([]) 763 ctx.set_dash([])
764 764
765# elide the bootchart collector - it is quite distorting 765# elide the bootchart collector - it is quite distorting
766def elide_bootchart(proc): 766def elide_bootchart(proc):
767 return proc.cmd == 'bootchartd' or proc.cmd == 'bootchart-colle' 767 return proc.cmd == 'bootchartd' or proc.cmd == 'bootchart-colle'
768 768
769class CumlSample: 769class CumlSample:
770 def __init__(self, proc): 770 def __init__(self, proc):
771 self.cmd = proc.cmd 771 self.cmd = proc.cmd
772 self.samples = [] 772 self.samples = []
773 self.merge_samples (proc) 773 self.merge_samples (proc)
774 self.color = None 774 self.color = None
775 775
776 def merge_samples(self, proc): 776 def merge_samples(self, proc):
777 self.samples.extend (proc.samples) 777 self.samples.extend (proc.samples)
778 self.samples.sort (key = lambda p: p.time) 778 self.samples.sort (key = lambda p: p.time)
779 779
780 def next(self): 780 def next(self):
781 global palette_idx 781 global palette_idx
782 palette_idx += HSV_STEP 782 palette_idx += HSV_STEP
783 return palette_idx 783 return palette_idx
784 784
785 def get_color(self): 785 def get_color(self):
786 if self.color is None: 786 if self.color is None:
787 i = self.next() % HSV_MAX_MOD 787 i = self.next() % HSV_MAX_MOD
788 h = 0.0 788 h = 0.0
789 if i is not 0: 789 if i is not 0:
790 h = (1.0 * i) / HSV_MAX_MOD 790 h = (1.0 * i) / HSV_MAX_MOD
791 s = 0.5 791 s = 0.5
792 v = 1.0 792 v = 1.0
793 c = colorsys.hsv_to_rgb (h, s, v) 793 c = colorsys.hsv_to_rgb (h, s, v)
794 self.color = (c[0], c[1], c[2], 1.0) 794 self.color = (c[0], c[1], c[2], 1.0)
795 return self.color 795 return self.color
796 796
797 797
798def draw_cuml_graph(ctx, proc_tree, chart_bounds, duration, sec_w, stat_type): 798def draw_cuml_graph(ctx, proc_tree, chart_bounds, duration, sec_w, stat_type):
799 global palette_idx 799 global palette_idx
800 palette_idx = 0 800 palette_idx = 0
801 801
802 time_hash = {} 802 time_hash = {}
803 total_time = 0.0 803 total_time = 0.0
804 m_proc_list = {} 804 m_proc_list = {}
805 805
806 if stat_type is STAT_TYPE_CPU: 806 if stat_type is STAT_TYPE_CPU:
807 sample_value = 'cpu' 807 sample_value = 'cpu'
808 else: 808 else:
809 sample_value = 'io' 809 sample_value = 'io'
810 for proc in proc_tree.process_list: 810 for proc in proc_tree.process_list:
811 if elide_bootchart(proc): 811 if elide_bootchart(proc):
812 continue 812 continue
813 813
814 for sample in proc.samples: 814 for sample in proc.samples:
815 total_time += getattr(sample.cpu_sample, sample_value) 815 total_time += getattr(sample.cpu_sample, sample_value)
816 if not sample.time in time_hash: 816 if not sample.time in time_hash:
817 time_hash[sample.time] = 1 817 time_hash[sample.time] = 1
818 818
819 # merge pids with the same cmd 819 # merge pids with the same cmd
820 if not proc.cmd in m_proc_list: 820 if not proc.cmd in m_proc_list:
821 m_proc_list[proc.cmd] = CumlSample (proc) 821 m_proc_list[proc.cmd] = CumlSample (proc)
822 continue 822 continue
823 s = m_proc_list[proc.cmd] 823 s = m_proc_list[proc.cmd]
824 s.merge_samples (proc) 824 s.merge_samples (proc)
825 825
826 # all the sample times 826 # all the sample times
827 times = sorted(time_hash) 827 times = sorted(time_hash)
828 if len (times) < 2: 828 if len (times) < 2:
829 print("degenerate boot chart") 829 print("degenerate boot chart")
830 return 830 return
831 831
832 pix_per_ns = chart_bounds[3] / total_time 832 pix_per_ns = chart_bounds[3] / total_time
833# print "total time: %g pix-per-ns %g" % (total_time, pix_per_ns) 833# print "total time: %g pix-per-ns %g" % (total_time, pix_per_ns)
834 834
835 # FIXME: we have duplicates in the process list too [!] - why !? 835 # FIXME: we have duplicates in the process list too [!] - why !?
836 836
837 # Render bottom up, left to right 837 # Render bottom up, left to right
838 below = {} 838 below = {}
839 for time in times: 839 for time in times:
840 below[time] = chart_bounds[1] + chart_bounds[3] 840 below[time] = chart_bounds[1] + chart_bounds[3]
841 841
842 # same colors each time we render 842 # same colors each time we render
843 random.seed (0) 843 random.seed (0)
844 844
845 ctx.set_line_width(1) 845 ctx.set_line_width(1)
846 846
847 legends = [] 847 legends = []
848 labels = [] 848 labels = []
849 849
850 # render each pid in order 850 # render each pid in order
851 for cs in m_proc_list.values(): 851 for cs in m_proc_list.values():
852 row = {} 852 row = {}
853 cuml = 0.0 853 cuml = 0.0
854 854
855 # print "pid : %s -> %g samples %d" % (proc.cmd, cuml, len (cs.samples)) 855 # print "pid : %s -> %g samples %d" % (proc.cmd, cuml, len (cs.samples))
856 for sample in cs.samples: 856 for sample in cs.samples:
857 cuml += getattr(sample.cpu_sample, sample_value) 857 cuml += getattr(sample.cpu_sample, sample_value)
858 row[sample.time] = cuml 858 row[sample.time] = cuml
859 859
860 process_total_time = cuml 860 process_total_time = cuml
861 861
862 # hide really tiny processes 862 # hide really tiny processes
863 if cuml * pix_per_ns <= 2: 863 if cuml * pix_per_ns <= 2:
864 continue 864 continue
865 865
866 last_time = times[0] 866 last_time = times[0]
867 y = last_below = below[last_time] 867 y = last_below = below[last_time]
868 last_cuml = cuml = 0.0 868 last_cuml = cuml = 0.0
869 869
870 ctx.set_source_rgba(*cs.get_color()) 870 ctx.set_source_rgba(*cs.get_color())
871 for time in times: 871 for time in times:
872 render_seg = False 872 render_seg = False
873 873
874 # did the underlying trend increase ? 874 # did the underlying trend increase ?
875 if below[time] != last_below: 875 if below[time] != last_below:
876 last_below = below[last_time] 876 last_below = below[last_time]
877 last_cuml = cuml 877 last_cuml = cuml
878 render_seg = True 878 render_seg = True
879 879
880 # did we move up a pixel increase ? 880 # did we move up a pixel increase ?
881 if time in row: 881 if time in row:
882 nc = round (row[time] * pix_per_ns) 882 nc = round (row[time] * pix_per_ns)
883 if nc != cuml: 883 if nc != cuml:
884 last_cuml = cuml 884 last_cuml = cuml
885 cuml = nc 885 cuml = nc
886 render_seg = True 886 render_seg = True
887 887
888# if last_cuml > cuml: 888# if last_cuml > cuml:
889# assert fail ... - un-sorted process samples 889# assert fail ... - un-sorted process samples
890 890
891 # draw the trailing rectangle from the last time to 891 # draw the trailing rectangle from the last time to
892 # before now, at the height of the last segment. 892 # before now, at the height of the last segment.
893 if render_seg: 893 if render_seg:
894 w = math.ceil ((time - last_time) * chart_bounds[2] / proc_tree.duration) + 1 894 w = math.ceil ((time - last_time) * chart_bounds[2] / proc_tree.duration) + 1
895 x = chart_bounds[0] + round((last_time - proc_tree.start_time) * chart_bounds[2] / proc_tree.duration) 895 x = chart_bounds[0] + round((last_time - proc_tree.start_time) * chart_bounds[2] / proc_tree.duration)
896 ctx.rectangle (x, below[last_time] - last_cuml, w, last_cuml) 896 ctx.rectangle (x, below[last_time] - last_cuml, w, last_cuml)
897 ctx.fill() 897 ctx.fill()
898# ctx.stroke() 898# ctx.stroke()
899 last_time = time 899 last_time = time
900 y = below [time] - cuml 900 y = below [time] - cuml
901 901
902 row[time] = y 902 row[time] = y
903 903
904 # render the last segment 904 # render the last segment
905 x = chart_bounds[0] + round((last_time - proc_tree.start_time) * chart_bounds[2] / proc_tree.duration) 905 x = chart_bounds[0] + round((last_time - proc_tree.start_time) * chart_bounds[2] / proc_tree.duration)
906 y = below[last_time] - cuml 906 y = below[last_time] - cuml
907 ctx.rectangle (x, y, chart_bounds[2] - x, cuml) 907 ctx.rectangle (x, y, chart_bounds[2] - x, cuml)
908 ctx.fill() 908 ctx.fill()
909# ctx.stroke() 909# ctx.stroke()
910 910
911 # render legend if it will fit 911 # render legend if it will fit
912 if cuml > 8: 912 if cuml > 8:
913 label = cs.cmd 913 label = cs.cmd
914 extnts = ctx.text_extents(label) 914 extnts = ctx.text_extents(label)
915 label_w = extnts[2] 915 label_w = extnts[2]
916 label_h = extnts[3] 916 label_h = extnts[3]
917# print "Text extents %g by %g" % (label_w, label_h) 917# print "Text extents %g by %g" % (label_w, label_h)
918 labels.append((label, 918 labels.append((label,
919 chart_bounds[0] + chart_bounds[2] - label_w - off_x * 2, 919 chart_bounds[0] + chart_bounds[2] - label_w - off_x * 2,
920 y + (cuml + label_h) / 2)) 920 y + (cuml + label_h) / 2))
921 if cs in legends: 921 if cs in legends:
922 print("ARGH - duplicate process in list !") 922 print("ARGH - duplicate process in list !")
923 923
924 legends.append ((cs, process_total_time)) 924 legends.append ((cs, process_total_time))
925 925
926 below = row 926 below = row
927 927
928 # render grid-lines over the top 928 # render grid-lines over the top
929 draw_box_ticks(ctx, chart_bounds, sec_w) 929 draw_box_ticks(ctx, chart_bounds, sec_w)
930 930
931 # render labels 931 # render labels
932 for l in labels: 932 for l in labels:
933 draw_text(ctx, l[0], TEXT_COLOR, l[1], l[2]) 933 draw_text(ctx, l[0], TEXT_COLOR, l[1], l[2])
934 934
935 # Render legends 935 # Render legends
936 font_height = 20 936 font_height = 20
937 label_width = 300 937 label_width = 300
938 LEGENDS_PER_COL = 15 938 LEGENDS_PER_COL = 15
939 LEGENDS_TOTAL = 45 939 LEGENDS_TOTAL = 45
940 ctx.set_font_size (TITLE_FONT_SIZE) 940 ctx.set_font_size (TITLE_FONT_SIZE)
941 dur_secs = duration / 100 941 dur_secs = duration / 100
942 cpu_secs = total_time / 1000000000 942 cpu_secs = total_time / 1000000000
943 943
944 # misleading - with multiple CPUs ... 944 # misleading - with multiple CPUs ...
945# idle = ((dur_secs - cpu_secs) / dur_secs) * 100.0 945# idle = ((dur_secs - cpu_secs) / dur_secs) * 100.0
946 if stat_type is STAT_TYPE_CPU: 946 if stat_type is STAT_TYPE_CPU:
947 label = "Cumulative CPU usage, by process; total CPU: " \ 947 label = "Cumulative CPU usage, by process; total CPU: " \
948 " %.5g(s) time: %.3g(s)" % (cpu_secs, dur_secs) 948 " %.5g(s) time: %.3g(s)" % (cpu_secs, dur_secs)
949 else: 949 else:
950 label = "Cumulative I/O usage, by process; total I/O: " \ 950 label = "Cumulative I/O usage, by process; total I/O: " \
951 " %.5g(s) time: %.3g(s)" % (cpu_secs, dur_secs) 951 " %.5g(s) time: %.3g(s)" % (cpu_secs, dur_secs)
952 952
953 draw_text(ctx, label, TEXT_COLOR, chart_bounds[0] + off_x, 953 draw_text(ctx, label, TEXT_COLOR, chart_bounds[0] + off_x,
954 chart_bounds[1] + font_height) 954 chart_bounds[1] + font_height)
955 955
956 i = 0 956 i = 0
957 legends = sorted(legends, key=itemgetter(1), reverse=True) 957 legends = sorted(legends, key=itemgetter(1), reverse=True)
958 ctx.set_font_size(TEXT_FONT_SIZE) 958 ctx.set_font_size(TEXT_FONT_SIZE)
959 for t in legends: 959 for t in legends:
960 cs = t[0] 960 cs = t[0]
961 time = t[1] 961 time = t[1]
962 x = chart_bounds[0] + off_x + int (i/LEGENDS_PER_COL) * label_width 962 x = chart_bounds[0] + off_x + int (i/LEGENDS_PER_COL) * label_width
963 y = chart_bounds[1] + font_height * ((i % LEGENDS_PER_COL) + 2) 963 y = chart_bounds[1] + font_height * ((i % LEGENDS_PER_COL) + 2)
964 str = "%s - %.0f(ms) (%2.2f%%)" % (cs.cmd, time/1000000, (time/total_time) * 100.0) 964 str = "%s - %.0f(ms) (%2.2f%%)" % (cs.cmd, time/1000000, (time/total_time) * 100.0)
965 draw_legend_box(ctx, str, cs.color, x, y, leg_s) 965 draw_legend_box(ctx, str, cs.color, x, y, leg_s)
966 i = i + 1 966 i = i + 1
967 if i >= LEGENDS_TOTAL: 967 if i >= LEGENDS_TOTAL:
968 break 968 break