Skip to content

Commit

Permalink
Bug 1858807 - Track individual rust crate build times. r=firefox-buil…
Browse files Browse the repository at this point in the history
…d-system-reviewers,sergesanspaille

As of now, cargo only supports HTML timings output. There is an unstable
flag for a json output, but we can't use that because it requires a
nightly cargo. So we do our best effort to get the data we need off the
HTML, but since the exact details of the format of that file are not
set in stone, we also prevent any error from being unhandled. It's
better not to have the data than break the build.

Differential Revision: https://phabricator.services.mozilla.com/D190884
  • Loading branch information
glandium committed Oct 19, 2023
1 parent 15cde34 commit 94f304f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
2 changes: 1 addition & 1 deletion config/makefiles/rust.mk
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ endif
#
# $(call CARGO_BUILD)
define CARGO_BUILD
$(call RUN_CARGO,rustc)
$(call RUN_CARGO,rustc$(if $(BUILDSTATUS), --timings))
endef

cargo_host_linker_env_var := CARGO_TARGET_$(call varize,$(RUST_HOST_TARGET))_LINKER
Expand Down
53 changes: 52 additions & 1 deletion python/mozbuild/mozbuild/controller/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import sys
import time
from collections import Counter, OrderedDict, namedtuple
from itertools import dropwhile, islice, takewhile
from textwrap import TextWrapper

import six
Expand Down Expand Up @@ -179,6 +180,51 @@ def add_resource_fields_to_dict(self, d):
return d


def record_cargo_timings(resource_monitor, timings_path):
cargo_start = 0
try:
with open(timings_path) as fh:
# Extrace the UNIT_DATA list from the cargo timing HTML file.
unit_data = dropwhile(lambda l: l.rstrip() != "const UNIT_DATA = [", fh)
unit_data = islice(unit_data, 1, None)
lines = takewhile(lambda l: l.rstrip() != "];", unit_data)
entries = json.loads("[" + "".join(lines) + "]")
# Normalize the entries so that any change in data format would
# trigger the exception handler that skips this (we don't want the
# build to fail in that case)
data = [
(
"{} v{}{}".format(
entry["name"], entry["version"], entry.get("target", "")
),
entry["start"] or 0,
entry["duration"] or 0,
)
for entry in entries
]
starts = [
start
for marker, start in resource_monitor._active_markers.items()
if marker.startswith("Rust:")
]
# The build system is not supposed to be running more than one cargo
# at the same time, which thankfully makes it easier to find the start
# of the one we got the timings for.
if len(starts) != 1:
return
cargo_start = starts[0]
except Exception:
return

if not cargo_start:
return

for name, start, duration in data:
resource_monitor.record_marker(
"Rust", cargo_start + start, cargo_start + start + duration, name
)


class BuildMonitor(MozbuildObject):
"""Monitors the output of the build."""

Expand Down Expand Up @@ -261,7 +307,7 @@ def on_line(self, line):
# If the previous line was colored (eg. for a compiler warning), our
# line will start with the ansi reset sequence. Strip it to ensure it
# does not interfere with our parsing of the line.
plain_line = self._terminal.strip(line) if self._terminal else line
plain_line = self._terminal.strip(line) if self._terminal else line.strip()
if plain_line.startswith("BUILDSTATUS"):
args = plain_line.split()[1:]

Expand Down Expand Up @@ -298,6 +344,11 @@ def on_line(self, line):

return BuildOutputResult(None, update_needed, message)

elif plain_line.startswith("Timing report saved to "):
cargo_timings = plain_line[len("Timing report saved to ") :]
record_cargo_timings(self.resources, cargo_timings)
return BuildOutputResult(None, False, None)

warning = None

try:
Expand Down

0 comments on commit 94f304f

Please sign in to comment.