-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ctexplain: first functional check-in
#11511 set up basic project structure. This PR adds minimum working functionality. Specifically, you can run it with a build command and it reports basic stats on the build's graph. Example: ``` $ bazel-bin/tools/ctexplain/ctexplain -b "//testapp:foo" Collecting configured targets for //testapp:foo... done in 0.62 s. Configurations: 3 Targets: 79 Configured targets: 92 (+16.5% vs. targets) Targets with multiple configs: 13 ``` Notes: * Changed import structure to prefer module imports over function, class imports (style guide recommendation) * Set up structure for injecting arbitrary analyses. Each analysis consumes the build's set of configured targets and can output whatever it wants. * Implemented one basic analysis * Structured code to make it easy to fork output formatters (e.g. for machine-readable output). But tried not to add speculative inheritance / boilerplate too soon Context: [Measuring Configuration Overhead](https://docs.google.com/document/d/10ZxO2wZdKJATnYBqAm22xT1k5r4Vp6QX96TkqSUIhs0/edit). Work towards #10613 Closes #11829. PiperOrigin-RevId: 328325094
- Loading branch information
1 parent
11f233f
commit c1d7087
Showing
10 changed files
with
573 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Lint as: python3 | ||
# Copyright 2020 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
"""Analysis that summarizes basic graph info.""" | ||
from typing import Tuple | ||
|
||
# Do not edit this line. Copybara replaces it with PY2 migration helper. | ||
from dataclasses import dataclass | ||
|
||
from tools.ctexplain.types import ConfiguredTarget | ||
# Do not edit this line. Copybara replaces it with PY2 migration helper..third_party.bazel.tools.ctexplain.util as util | ||
|
||
|
||
@dataclass(frozen=True) | ||
class _Summary(): | ||
"""Analysis result.""" | ||
# Number of configurations in the build's configured target graph. | ||
configurations: int | ||
# Number of unique target labels. | ||
targets: int | ||
# Number of configured targets. | ||
configured_targets: int | ||
# Number of targets that produce multiple configured targets. This is more | ||
# subtle than computing configured_targets - targets. For example, if | ||
# targets=2 and configured_targets=4, that could mean both targets are | ||
# configured twice. Or it could mean the first target is configured 3 times. | ||
repeated_targets: int | ||
|
||
|
||
def analyze(cts: Tuple[ConfiguredTarget, ...]) -> _Summary: | ||
"""Runs the analysis on a build's configured targets.""" | ||
configurations = set() | ||
targets = set() | ||
label_count = {} | ||
for ct in cts: | ||
configurations.add(ct.config_hash) | ||
targets.add(ct.label) | ||
label_count[ct.label] = label_count.setdefault(ct.label, 0) + 1 | ||
configured_targets = len(cts) | ||
repeated_targets = sum([1 for count in label_count.values() if count > 1]) | ||
|
||
return _Summary( | ||
len(configurations), len(targets), configured_targets, repeated_targets) | ||
|
||
|
||
def report(result: _Summary) -> None: | ||
"""Reports analysis results to the user. | ||
We intentionally make this its own function to make it easy to support other | ||
output formats (like machine-readable) if we ever want to do that. | ||
Args: | ||
result: the analysis result | ||
""" | ||
ct_surplus = util.percent_diff(result.targets, result.configured_targets) | ||
print(f""" | ||
Configurations: {result.configurations} | ||
Targets: {result.targets} | ||
Configured targets: {result.configured_targets} ({ct_surplus} vs. targets) | ||
Targets with multiple configs: {result.repeated_targets} | ||
""") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Lint as: python3 | ||
# Copyright 2020 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
"""Tests for summary.py.""" | ||
import unittest | ||
|
||
# Do not edit this line. Copybara replaces it with PY2 migration helper. | ||
from frozendict import frozendict | ||
|
||
# Do not edit this line. Copybara replaces it with PY2 migration helper..third_party.bazel.tools.ctexplain.analyses.summary as summary | ||
from tools.ctexplain.types import Configuration | ||
from tools.ctexplain.types import ConfiguredTarget | ||
from tools.ctexplain.types import NullConfiguration | ||
|
||
|
||
class SummaryTest(unittest.TestCase): | ||
|
||
def testAnalysis(self): | ||
config1 = Configuration(None, frozendict({'a': frozendict({'b': 'c'})})) | ||
config2 = Configuration(None, frozendict({'d': frozendict({'e': 'f'})})) | ||
|
||
ct1 = ConfiguredTarget('//foo', config1, 'hash1', None) | ||
ct2 = ConfiguredTarget('//foo', config2, 'hash2', None) | ||
ct3 = ConfiguredTarget('//foo', NullConfiguration(), 'null', None) | ||
ct4 = ConfiguredTarget('//bar', config1, 'hash1', None) | ||
|
||
res = summary.analyze((ct1, ct2, ct3, ct4)) | ||
self.assertEqual(3, res.configurations) | ||
self.assertEqual(2, res.targets) | ||
self.assertEqual(4, res.configured_targets) | ||
self.assertEqual(1, res.repeated_targets) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.