support/scripts/graph-build-time: add support for timeline graphing

This commit adds support for a new type of graph, showing the timeline
of a build. It shows, with one line per package, when each of this
package steps started/ended, and therefore allows to see the
sequencing of the package builds.

For a fully serialized build like we have today, this is not super
useful (except to show that everything is serialized), but it becomes
much more useful in the context of top-level parallel build.

We chose to order the graph by the time-of-configure, as it is the
closest to the actual cascade-style of a true dependency graph, which is
tiny bit more complex to achieve properly. The actual result still looks
pretty good.

The graph-build make target is extended to also generate this new
timeline graph.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
[yann.morin.1998@free.fr:
  - sort by start-of-configure time
  - re-use existing colorsets (default or alternate)
  - fix python2isms
  - fix check-package
]
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
This commit is contained in:
Thomas Petazzoni 2022-02-09 21:30:26 +01:00 committed by Yann E. MORIN
parent 842ba7ecef
commit 5e8b01afd5
2 changed files with 65 additions and 1 deletions

View File

@ -871,6 +871,9 @@ graph-build: $(O)/build/build-time.log
--type=pie-$(t) --input=$(<) \ --type=pie-$(t) --input=$(<) \
--output=$(GRAPHS_DIR)/build.pie-$(t).$(BR_GRAPH_OUT) \ --output=$(GRAPHS_DIR)/build.pie-$(t).$(BR_GRAPH_OUT) \
$(if $(BR2_GRAPH_ALT),--alternate-colors)$(sep)) $(if $(BR2_GRAPH_ALT),--alternate-colors)$(sep))
./support/scripts/graph-build-time --type=timeline --input=$(<) \
--output=$(GRAPHS_DIR)/build.timeline.$(BR_GRAPH_OUT) \
$(if $(BR2_GRAPH_ALT),--alternate-colors)
.PHONY: graph-depends-requirements .PHONY: graph-depends-requirements
graph-depends-requirements: graph-depends-requirements:

View File

@ -241,6 +241,65 @@ def pkg_pie_time_per_step(data, output):
plt.savefig(output) plt.savefig(output)
def pkg_timeline(data, output):
start = 0
end = 0
# Find the first timestamp and the last timestamp
for p in data:
for k, v in p.steps_start.items():
if start == 0 or v < start:
start = v
if end < v:
end = v
# Readjust all timestamps so that 0 is the start of the build
# instead of being Epoch
for p in data:
for k, v in p.steps_start.items():
p.steps_start[k] = v - start
for k, v in p.steps_end.items():
p.steps_end[k] = v - start
plt.figure()
i = 0
labels_names = []
labels_coords = []
# put last packages that started to configure last; this does not
# give the proper dependency chain, but still provides a good-enough
# cascade graph.
for p in sorted(data, reverse=True, key=lambda x: x.steps_start['configure']):
durations = []
facecolors = []
for step in steps:
if step not in p.steps_start or step not in p.steps_end:
continue
durations.append((p.steps_start[step],
p.steps_end[step] - p.steps_start[step]))
facecolors.append(colors[steps.index(step)])
plt.broken_barh(durations, (i, 6), facecolors=facecolors)
labels_coords.append(i + 3)
labels_names.append(p.name)
i += 10
axes = plt.gcf().gca()
axes.set_ylim(0, i + 10)
axes.set_xlim(0, end - start)
axes.set_xlabel('seconds since start')
axes.set_yticks(labels_coords)
axes.set_yticklabels(labels_names)
axes.set_axisbelow(True)
axes.grid(True, linewidth=0.2, zorder=-1)
plt.gcf().subplots_adjust(left=0.2)
plt.tick_params(axis='y', which='both', labelsize=6)
plt.title('Timeline')
plt.savefig(output, dpi=300)
# Parses the csv file passed on standard input and returns a list of # Parses the csv file passed on standard input and returns a list of
# Package objects, filed with the duration of each step and the total # Package objects, filed with the duration of each step and the total
# duration of the package. # duration of the package.
@ -277,7 +336,7 @@ def read_data(input_file):
parser = argparse.ArgumentParser(description='Draw build time graphs') parser = argparse.ArgumentParser(description='Draw build time graphs')
parser.add_argument("--type", '-t', metavar="GRAPH_TYPE", parser.add_argument("--type", '-t', metavar="GRAPH_TYPE",
help="Type of graph (histogram, pie-packages, pie-steps)") help="Type of graph (histogram, pie-packages, pie-steps, timeline)")
parser.add_argument("--order", '-O', metavar="GRAPH_ORDER", parser.add_argument("--order", '-O', metavar="GRAPH_ORDER",
help="Ordering of packages: build or duration (for histogram only)") help="Ordering of packages: build or duration (for histogram only)")
parser.add_argument("--alternate-colors", '-c', action="store_true", parser.add_argument("--alternate-colors", '-c', action="store_true",
@ -307,6 +366,8 @@ elif args.type == "pie-packages":
pkg_pie_time_per_package(d, args.output) pkg_pie_time_per_package(d, args.output)
elif args.type == "pie-steps": elif args.type == "pie-steps":
pkg_pie_time_per_step(d, args.output) pkg_pie_time_per_step(d, args.output)
elif args.type == "timeline":
pkg_timeline(d, args.output)
else: else:
sys.stderr.write("Unknown type: %s\n" % args.type) sys.stderr.write("Unknown type: %s\n" % args.type)
exit(1) exit(1)