Skip to content

Commit b61c009

Browse files
committed
build: emit performance JSON file for each ng_module() (angular#41125)
A previous commit implemented a streamlined performance metric reporting system for the compiler-cli, controlled via the compiler option `tracePerformance`. This commit adds a custom Bazel flag rule //packages/compiler-cli:ng_perf to the repository, and wires it through to the `ng_module` implementation such that if the flag is set, `ng_module` will produce perf results as part of the build. The underlying mechanism of `//:ng_perf` is not exported from `@angular/bazel` as a public rule that consumers can use, so there is little risk of accidental dependency on the contents of these perf traces. An alias is added so that `--ng_perf` is a Bazel flag which works in our repository. PR Close angular#41125
1 parent 48fec08 commit b61c009

File tree

6 files changed

+83
-3
lines changed

6 files changed

+83
-3
lines changed

.bazelrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ build:remote --remote_executor=remotebuildexecution.googleapis.com
140140
# retry mechanism and we do not want to retry unnecessarily if Karma already tried multiple times.
141141
test:saucelabs --flaky_test_attempts=1
142142

143+
################
144+
# Flag Aliases #
145+
################
146+
147+
# --ng_perf will ask the Ivy compiler to produce performance results for each build.
148+
build --flag_alias=ng_perf=//packages/compiler-cli:ng_perf
149+
143150
####################################################
144151
# User bazel configuration
145152
# NOTE: This needs to be the *last* entry in the config.

packages/bazel/index.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ load("//packages/bazel/src:ng_module.bzl", _ng_module = "ng_module_macro")
1212

1313
ng_module = _ng_module
1414
ng_package = _ng_package
15+
1516
# DO NOT ADD PUBLIC API without including in the documentation generation
1617
# Run `yarn bazel build //packages/bazel/docs` to verify

packages/bazel/src/ng_module.bzl

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,19 @@ load(
2626
"tsc_wrapped_tsconfig",
2727
)
2828

29+
# enable_perf_logging controls whether Ivy's performance tracing system will be enabled for any
30+
# compilation which includes this provider.
31+
NgPerfInfo = provider(fields = ["enable_perf_logging"])
32+
2933
_FLAT_DTS_FILE_SUFFIX = ".bundle.d.ts"
3034
_R3_SYMBOLS_DTS_FILE = "src/r3_symbols.d.ts"
3135

36+
def is_perf_requested(ctx):
37+
enable_perf_logging = ctx.attr.perf_flag != None and ctx.attr.perf_flag[NgPerfInfo].enable_perf_logging == True
38+
if enable_perf_logging and not is_ivy_enabled(ctx):
39+
fail("Angular View Engine does not support performance tracing")
40+
return enable_perf_logging
41+
3242
def is_ivy_enabled(ctx):
3343
"""Determine if the ivy compiler should be used to by the ng_module.
3444
@@ -278,6 +288,15 @@ def _expected_outs(ctx):
278288
else:
279289
i18n_messages_files = []
280290

291+
dev_perf_files = []
292+
prod_perf_files = []
293+
294+
# In Ivy mode, dev and prod builds both produce a .json output containing performance metrics
295+
# from the compiler for that build.
296+
if is_perf_requested(ctx):
297+
dev_perf_files = [ctx.actions.declare_file(ctx.label.name + "_perf_dev.json")]
298+
prod_perf_files = [ctx.actions.declare_file(ctx.label.name + "_perf_prod.json")]
299+
281300
return struct(
282301
closure_js = closure_js_files,
283302
devmode_js = devmode_js_files,
@@ -288,6 +307,8 @@ def _expected_outs(ctx):
288307
dts_bundles = dts_bundles,
289308
bundle_index_typings = bundle_index_typings,
290309
i18n_messages = i18n_messages_files,
310+
dev_perf_files = dev_perf_files,
311+
prod_perf_files = prod_perf_files,
291312
)
292313

293314
# Determines if we need to generate View Engine shims (.ngfactory and .ngsummary files)
@@ -336,6 +357,15 @@ def _ngc_tsconfig(ctx, files, srcs, **kwargs):
336357
"_useManifestPathsAsModuleName": (not _is_bazel()),
337358
}
338359

360+
if is_perf_requested(ctx):
361+
# In Ivy mode, set the `tracePerformance` Angular compiler option to enable performance
362+
# metric output.
363+
if "devmode_manifest" in kwargs:
364+
perf_path = outs.dev_perf_files[0].path
365+
else:
366+
perf_path = outs.prod_perf_files[0].path
367+
angular_compiler_options["tracePerformance"] = perf_path
368+
339369
if _should_produce_flat_module_outs(ctx):
340370
angular_compiler_options["flatModuleId"] = ctx.attr.module_name
341371
angular_compiler_options["flatModuleOutFile"] = _flat_module_out_file(ctx)
@@ -519,6 +549,7 @@ def _compile_action(
519549
outputs,
520550
dts_bundles_out,
521551
messages_out,
552+
perf_out,
522553
tsconfig_file,
523554
node_opts,
524555
compile_mode):
@@ -563,12 +594,12 @@ def _compile_action(
563594

564595
def _prodmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
565596
outs = _expected_outs(ctx)
566-
return _compile_action(ctx, inputs, outputs + outs.closure_js, None, outs.i18n_messages, tsconfig_file, node_opts, "prodmode")
597+
return _compile_action(ctx, inputs, outputs + outs.closure_js + outs.prod_perf_files, None, outs.i18n_messages, outs.prod_perf_files, tsconfig_file, node_opts, "prodmode")
567598

568599
def _devmode_compile_action(ctx, inputs, outputs, tsconfig_file, node_opts):
569600
outs = _expected_outs(ctx)
570-
compile_action_outputs = outputs + outs.devmode_js + outs.declarations + outs.summaries + outs.metadata
571-
_compile_action(ctx, inputs, compile_action_outputs, outs.dts_bundles, None, tsconfig_file, node_opts, "devmode")
601+
compile_action_outputs = outputs + outs.devmode_js + outs.declarations + outs.summaries + outs.metadata + outs.dev_perf_files
602+
_compile_action(ctx, inputs, compile_action_outputs, outs.dts_bundles, None, outs.dev_perf_files, tsconfig_file, node_opts, "devmode")
572603

573604
def _ts_expected_outs(ctx, label, srcs_files = []):
574605
# rules_typescript expects a function with two or more arguments, but our
@@ -711,6 +742,16 @@ NG_MODULE_ATTRIBUTES = {
711742
executable = True,
712743
cfg = "host",
713744
),
745+
# In the angular/angular monorepo, //tools:defaults.bzl wraps the ng_module rule in a macro
746+
# which sets this attribute to the //packages/compiler-cli:ng_perf flag.
747+
# This is done to avoid exposing the flag to user projects, which would require:
748+
# * defining the flag within @angular/bazel and referencing it correctly here, and
749+
# * committing to the flag and its semantics (including the format of perf JSON files)
750+
# as something users can depend upon.
751+
"perf_flag": attr.label(
752+
providers = [NgPerfInfo],
753+
doc = "Private API to control production of performance metric JSON files",
754+
),
714755
"_supports_workers": attr.bool(default = True),
715756
}
716757

packages/bazel/src/ng_perf.bzl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright Google LLC All Rights Reserved.
2+
#
3+
# Use of this source code is governed by an MIT-style license that can be
4+
# found in the LICENSE file at https://angular.io/license
5+
6+
load(":ng_module.bzl", "NgPerfInfo")
7+
8+
def _ng_perf_flag_impl(ctx):
9+
return NgPerfInfo(enable_perf_logging = ctx.build_setting_value)
10+
11+
# `ng_perf_flag` is a special `build_setting` rule which ultimately enables a command-line boolean
12+
# flag to control whether the `ng_module` rule produces performance tracing JSON files (in Ivy mode)
13+
# as declared outputs.
14+
#
15+
# It does this via the `NgPerfInfo` provider and the `perf_flag` attriubute on `ng_module`. For more
16+
# details, see: https://docs.bazel.build/versions/master/skylark/config.html
17+
ng_perf_flag = rule(
18+
implementation = _ng_perf_flag_impl,
19+
build_setting = config.bool(flag = True),
20+
)

packages/compiler-cli/BUILD.bazel

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package(default_visibility = ["//visibility:public"])
22

33
load("//tools:defaults.bzl", "pkg_npm", "ts_api_guardian_test", "ts_config", "ts_library")
44

5+
# Load ng_perf_flag explicitly from ng_perf.bzl as it's private API, and not exposed to other
6+
# consumers of @angular/bazel.
7+
load("//packages/bazel/src:ng_perf.bzl", "ng_perf_flag")
8+
59
ts_config(
610
name = "tsconfig",
711
src = "tsconfig-build.json",
@@ -88,3 +92,9 @@ ts_api_guardian_test(
8892
],
8993
golden = "angular/goldens/public-api/compiler-cli/compiler_options.d.ts",
9094
)
95+
96+
# Controls whether the Ivy compiler produces performance traces as part of each build
97+
ng_perf_flag(
98+
name = "ng_perf",
99+
build_setting_default = False,
100+
)

tools/defaults.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ def ng_module(name, tsconfig = None, entry_point = None, testonly = False, deps
156156
api_extractor = _INTERNAL_NG_MODULE_API_EXTRACTOR,
157157
ng_xi18n = _INTERNAL_NG_MODULE_XI18N,
158158
module_name = module_name,
159+
perf_flag = "//packages/compiler-cli:ng_perf",
159160
**kwargs
160161
)
161162

0 commit comments

Comments
 (0)