diff options
author | Markus Lehtonen <markus.lehtonen@linux.intel.com> | 2017-09-15 16:04:38 +0300 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2017-09-18 11:07:30 +0100 |
commit | 81aef784fdbd2e8a543475b1892c3d6a1fe97872 (patch) | |
tree | d787e9402d3fa667eee19a4447f46b440e7eda5c /scripts/oe-build-perf-report | |
parent | b5fb3dd904cd22212c720f3c79d71952ecbaa9c2 (diff) | |
download | poky-81aef784fdbd2e8a543475b1892c3d6a1fe97872.tar.gz |
scripts/oe-build-perf-report: summary of task resource usage
Utilize buildstats, if available, and show a summary of the resource
usage of bitbake tasks in the html report. The details provided are:
- total number of tasks
- top 5 resource-hungry tasks (cputime)
- top 5 increase in resource usage (cputime)
- top 5 decrease in resource usage (cputime)
[YOCTO #11381]
(From OE-Core rev: ddd9443cb2432af2c15b358bfda708393fa3c417)
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/oe-build-perf-report')
-rwxr-xr-x | scripts/oe-build-perf-report | 90 |
1 files changed, 67 insertions, 23 deletions
diff --git a/scripts/oe-build-perf-report b/scripts/oe-build-perf-report index 8d730cd20a..0b2f730e57 100755 --- a/scripts/oe-build-perf-report +++ b/scripts/oe-build-perf-report | |||
@@ -32,6 +32,7 @@ from build_perf.report import (metadata_xml_to_json, results_xml_to_json, | |||
32 | aggregate_data, aggregate_metadata, measurement_stats, | 32 | aggregate_data, aggregate_metadata, measurement_stats, |
33 | AggregateTestData) | 33 | AggregateTestData) |
34 | from build_perf import html | 34 | from build_perf import html |
35 | from buildstats import BuildStats, diff_buildstats | ||
35 | 36 | ||
36 | scriptpath.add_oe_lib_path() | 37 | scriptpath.add_oe_lib_path() |
37 | 38 | ||
@@ -333,12 +334,31 @@ def print_diff_report(metadata_l, data_l, metadata_r, data_r): | |||
333 | print() | 334 | print() |
334 | 335 | ||
335 | 336 | ||
336 | def print_html_report(data, id_comp): | 337 | class BSSummary(object): |
338 | def __init__(self, bs1, bs2): | ||
339 | self.tasks = {'count': bs2.num_tasks, | ||
340 | 'change': '{:+d}'.format(bs2.num_tasks - bs1.num_tasks)} | ||
341 | self.top_consumer = None | ||
342 | self.top_decrease = None | ||
343 | self.top_increase = None | ||
344 | |||
345 | tasks_diff = diff_buildstats(bs1, bs2, 'cputime') | ||
346 | |||
347 | # Get top consumers of resources | ||
348 | tasks_diff = sorted(tasks_diff, key=attrgetter('value2')) | ||
349 | self.top_consumer = tasks_diff[-5:] | ||
350 | |||
351 | # Get biggest increase and decrease in resource usage | ||
352 | tasks_diff = sorted(tasks_diff, key=attrgetter('absdiff')) | ||
353 | self.top_decrease = tasks_diff[0:5] | ||
354 | self.top_increase = tasks_diff[-5:] | ||
355 | |||
356 | |||
357 | def print_html_report(data, id_comp, buildstats): | ||
337 | """Print report in html format""" | 358 | """Print report in html format""" |
338 | # Handle metadata | 359 | # Handle metadata |
339 | metadata = metadata_diff(data[id_comp].metadata, data[-1].metadata) | 360 | metadata = metadata_diff(data[id_comp].metadata, data[-1].metadata) |
340 | 361 | ||
341 | |||
342 | # Generate list of tests | 362 | # Generate list of tests |
343 | tests = [] | 363 | tests = [] |
344 | for test in data[-1].results['tests'].keys(): | 364 | for test in data[-1].results['tests'].keys(): |
@@ -388,6 +408,16 @@ def print_html_report(data, id_comp): | |||
388 | new_meas['value'] = samples[-1] | 408 | new_meas['value'] = samples[-1] |
389 | new_meas['value_type'] = samples[-1]['val_cls'] | 409 | new_meas['value_type'] = samples[-1]['val_cls'] |
390 | 410 | ||
411 | # Compare buildstats | ||
412 | bs_key = test + '.' + meas | ||
413 | rev = metadata['commit_num']['value'] | ||
414 | comp_rev = metadata['commit_num']['value_old'] | ||
415 | if (rev in buildstats and bs_key in buildstats[rev] and | ||
416 | comp_rev in buildstats and bs_key in buildstats[comp_rev]): | ||
417 | new_meas['buildstats'] = BSSummary(buildstats[comp_rev][bs_key], | ||
418 | buildstats[rev][bs_key]) | ||
419 | |||
420 | |||
391 | new_test['measurements'].append(new_meas) | 421 | new_test['measurements'].append(new_meas) |
392 | tests.append(new_test) | 422 | tests.append(new_test) |
393 | 423 | ||
@@ -401,8 +431,8 @@ def print_html_report(data, id_comp): | |||
401 | chart_opts=chart_opts)) | 431 | chart_opts=chart_opts)) |
402 | 432 | ||
403 | 433 | ||
404 | def dump_buildstats(repo, outdir, notes_ref, revs): | 434 | def get_buildstats(repo, notes_ref, revs, outdir=None): |
405 | """Dump buildstats of test results""" | 435 | """Get the buildstats from git notes""" |
406 | full_ref = 'refs/notes/' + notes_ref | 436 | full_ref = 'refs/notes/' + notes_ref |
407 | if not repo.rev_parse(full_ref): | 437 | if not repo.rev_parse(full_ref): |
408 | log.error("No buildstats found, please try running " | 438 | log.error("No buildstats found, please try running " |
@@ -411,9 +441,10 @@ def dump_buildstats(repo, outdir, notes_ref, revs): | |||
411 | return | 441 | return |
412 | 442 | ||
413 | missing = False | 443 | missing = False |
414 | log.info("Writing out buildstats from 'refs/notes/%s' into '%s'", | 444 | buildstats = {} |
415 | notes_ref, outdir) | 445 | log.info("Parsing buildstats from 'refs/notes/%s'", notes_ref) |
416 | for rev in revs: | 446 | for rev in revs: |
447 | buildstats[rev.commit_number] = {} | ||
417 | log.debug('Dumping buildstats for %s (%s)', rev.commit_number, | 448 | log.debug('Dumping buildstats for %s (%s)', rev.commit_number, |
418 | rev.commit) | 449 | rev.commit) |
419 | for tag in rev.tags: | 450 | for tag in rev.tags: |
@@ -425,19 +456,32 @@ def dump_buildstats(repo, outdir, notes_ref, revs): | |||
425 | log.warning("Buildstats not found for %s", tag) | 456 | log.warning("Buildstats not found for %s", tag) |
426 | bs_all = {} | 457 | bs_all = {} |
427 | missing = True | 458 | missing = True |
428 | for measurement, buildstats in bs_all.items(): | 459 | |
429 | tag_base, run_id = tag.rsplit('/', 1) | 460 | for measurement, bs in bs_all.items(): |
430 | tag_base = tag_base.replace('/', '_') | 461 | # Write out onto disk |
431 | bs_dir = os.path.join(outdir, measurement, tag_base) | 462 | if outdir: |
432 | if not os.path.exists(bs_dir): | 463 | tag_base, run_id = tag.rsplit('/', 1) |
433 | os.makedirs(bs_dir) | 464 | tag_base = tag_base.replace('/', '_') |
434 | with open(os.path.join(bs_dir, run_id + '.json'), 'w') as f: | 465 | bs_dir = os.path.join(outdir, measurement, tag_base) |
435 | json.dump(buildstats, f, indent=2) | 466 | if not os.path.exists(bs_dir): |
467 | os.makedirs(bs_dir) | ||
468 | with open(os.path.join(bs_dir, run_id + '.json'), 'w') as f: | ||
469 | json.dump(bs, f, indent=2) | ||
470 | |||
471 | # Read buildstats into a dict | ||
472 | _bs = BuildStats.from_json(bs) | ||
473 | if measurement not in buildstats[rev.commit_number]: | ||
474 | buildstats[rev.commit_number][measurement] = _bs | ||
475 | else: | ||
476 | buildstats[rev.commit_number][measurement].aggregate(_bs) | ||
477 | |||
436 | if missing: | 478 | if missing: |
437 | log.info("Buildstats were missing for some test runs, please " | 479 | log.info("Buildstats were missing for some test runs, please " |
438 | "run 'git fetch origin %s:%s' and try again", | 480 | "run 'git fetch origin %s:%s' and try again", |
439 | full_ref, full_ref) | 481 | full_ref, full_ref) |
440 | 482 | ||
483 | return buildstats | ||
484 | |||
441 | 485 | ||
442 | def auto_args(repo, args): | 486 | def auto_args(repo, args): |
443 | """Guess arguments, if not defined by the user""" | 487 | """Guess arguments, if not defined by the user""" |
@@ -584,20 +628,20 @@ def main(argv=None): | |||
584 | index_r = index_r - index_0 | 628 | index_r = index_r - index_0 |
585 | index_l = index_l - index_0 | 629 | index_l = index_l - index_0 |
586 | 630 | ||
631 | # Read buildstats only when needed | ||
632 | buildstats = None | ||
633 | if args.dump_buildstats or args.html: | ||
634 | outdir = 'oe-build-perf-buildstats' if args.dump_buildstats else None | ||
635 | notes_ref = 'buildstats/{}/{}/{}'.format(args.hostname, args.branch, | ||
636 | args.machine) | ||
637 | buildstats = get_buildstats(repo, notes_ref, [rev_l, rev_r], outdir) | ||
638 | |||
587 | # Print report | 639 | # Print report |
588 | if not args.html: | 640 | if not args.html: |
589 | print_diff_report(data[index_l].metadata, data[index_l].results, | 641 | print_diff_report(data[index_l].metadata, data[index_l].results, |
590 | data[index_r].metadata, data[index_r].results) | 642 | data[index_r].metadata, data[index_r].results) |
591 | else: | 643 | else: |
592 | print_html_report(data, index_l) | 644 | print_html_report(data, index_l, buildstats) |
593 | |||
594 | # Dump buildstats | ||
595 | if args.dump_buildstats: | ||
596 | notes_ref = 'buildstats/{}/{}/{}'.format(args.hostname, args.branch, | ||
597 | args.machine) | ||
598 | dump_buildstats(repo, 'oe-build-perf-buildstats', notes_ref, | ||
599 | [rev_l, rev_r]) | ||
600 | #revs_l.tags + revs_r.tags) | ||
601 | 645 | ||
602 | return 0 | 646 | return 0 |
603 | 647 | ||