├── .bazelignore ├── .bazelrc ├── .bazelversion ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── feature-request.md │ └── feedback.md └── workflows │ └── ci.yml ├── .gitignore ├── BUILD ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── MODULE.bazel ├── MODULE.bazel.lock ├── README.md ├── analyzer ├── java │ └── com │ │ └── engflow │ │ └── bazel │ │ └── invocation │ │ └── analyzer │ │ ├── bazelprofile │ │ ├── BUILD │ │ ├── BazelEventsUtil.java │ │ ├── BazelProfile.java │ │ ├── BazelProfileConstants.java │ │ ├── BazelProfilePhase.java │ │ ├── ProfileThread.java │ │ └── ThreadId.java │ │ ├── core │ │ ├── BUILD │ │ ├── DataManager.java │ │ ├── DataProvider.java │ │ ├── Datum.java │ │ ├── DatumSupplier.java │ │ ├── DatumSupplierSpecification.java │ │ ├── DuplicateProviderException.java │ │ ├── InvalidProfileException.java │ │ ├── MissingInputException.java │ │ ├── NullDatumException.java │ │ └── SuggestionProvider.java │ │ ├── dataproviders │ │ ├── ActionStats.java │ │ ├── ActionStatsDataProvider.java │ │ ├── BUILD │ │ ├── BazelPhaseDescription.java │ │ ├── BazelPhaseDescriptions.java │ │ ├── BazelPhasesDataProvider.java │ │ ├── BazelVersion.java │ │ ├── BazelVersionDataProvider.java │ │ ├── Bottleneck.java │ │ ├── CachingAndExecutionMetrics.java │ │ ├── CachingAndExecutionMetricsDataProvider.java │ │ ├── CriticalPathDuration.java │ │ ├── CriticalPathDurationDataProvider.java │ │ ├── DataProviderUtil.java │ │ ├── EstimatedCores.java │ │ ├── EstimatedCoresAvailable.java │ │ ├── EstimatedCoresDataProvider.java │ │ ├── EstimatedCoresUsed.java │ │ ├── EstimatedJobsFlagValue.java │ │ ├── FlagValueDataProvider.java │ │ ├── FlagValueExperimentalProfileIncludeTargetLabel.java │ │ ├── GarbageCollectionStats.java │ │ ├── GarbageCollectionStatsDataProvider.java │ │ ├── LocalActions.java │ │ ├── LocalActionsDataProvider.java │ │ ├── MergedEventsPresent.java │ │ ├── MergedEventsPresentDataProvider.java │ │ ├── RemoteCacheMetrics.java │ │ ├── RemoteCacheMetricsDataProvider.java │ │ ├── SkymeldUsed.java │ │ ├── SkymeldUsedDataProvider.java │ │ ├── TotalDuration.java │ │ └── remoteexecution │ │ │ ├── BUILD │ │ │ ├── CriticalPathQueuingDuration.java │ │ │ ├── CriticalPathQueuingDurationDataProvider.java │ │ │ ├── QueuingObserved.java │ │ │ ├── QueuingObservedDataProvider.java │ │ │ ├── RemoteCachingUsed.java │ │ │ ├── RemoteCachingUsedDataProvider.java │ │ │ ├── RemoteExecutionUsed.java │ │ │ ├── RemoteExecutionUsedDataProvider.java │ │ │ ├── RemoteLatency.java │ │ │ ├── RemoteLatencyDataProvider.java │ │ │ ├── TotalQueuingDuration.java │ │ │ └── TotalQueuingDurationDataProvider.java │ │ ├── suggestionproviders │ │ ├── BUILD │ │ ├── BottleneckSuggestionProvider.java │ │ ├── BuildWithoutTheBytesSuggestionProvider.java │ │ ├── CriticalPathNotDominantSuggestionProvider.java │ │ ├── GarbageCollectionSuggestionProvider.java │ │ ├── IncompleteProfileSuggestionProvider.java │ │ ├── InvestigateRemoteCacheMissesSuggestionProvider.java │ │ ├── JobsSuggestionProvider.java │ │ ├── LocalActionsWithRemoteExecutionSuggestionProvider.java │ │ ├── MergedEventsSuggestionProvider.java │ │ ├── NegligiblePhaseSuggestionProvider.java │ │ ├── NoCacheActionsSuggestionProvider.java │ │ ├── QueuingSuggestionProvider.java │ │ ├── SuggestionProviderBase.java │ │ ├── SuggestionProviderUtil.java │ │ ├── UseRemoteCachingSuggestionProvider.java │ │ └── UseSkymeldSuggestionProvider.java │ │ ├── time │ │ ├── BUILD │ │ ├── DurationUtil.java │ │ ├── Range.java │ │ ├── TimeUtil.java │ │ └── Timestamp.java │ │ └── traceeventformat │ │ ├── BUILD │ │ ├── CompleteEvent.java │ │ ├── CounterEvent.java │ │ ├── InstantEvent.java │ │ ├── PartialCompleteEvent.java │ │ └── TraceEventFormatConstants.java └── javatests │ └── com │ └── engflow │ └── bazel │ └── invocation │ └── analyzer │ ├── BUILD │ ├── EventThreadBuilder.java │ ├── ProfileTestBase.java │ ├── UnitTestBase.java │ ├── WriteBazelProfile.java │ ├── bazelprofile │ ├── BUILD │ ├── BazelEventsUtilTest.java │ ├── BazelProfileTest.java │ └── BazelProfileTestSuite.java │ ├── core │ ├── BUILD │ ├── CoreTestSuite.java │ ├── DataManagerTest.java │ ├── DatumSupplierTest.java │ └── TestDatum.java │ ├── dataproviders │ ├── ActionStatsDataProviderTest.java │ ├── BUILD │ ├── BazelPhaseDescriptionsTest.java │ ├── BazelPhasesDataProviderTest.java │ ├── BazelProfilePhaseTest.java │ ├── BazelVersionDataProviderTest.java │ ├── BazelVersionTest.java │ ├── CachingAndExecutionMetricsDataProviderTest.java │ ├── CriticalPathDurationDataProviderTest.java │ ├── DataProviderUnitTestBase.java │ ├── DataProvidersTestSuite.java │ ├── EstimatedCoresDataProviderTest.java │ ├── FlagValueDataProviderTest.java │ ├── GarbageCollectionStatsDataProviderTest.java │ ├── LocalActionsDataProviderTest.java │ ├── LocalActionsTest.java │ ├── MergedEventsPresentDataProviderTest.java │ ├── RemoteCacheMetricsDataProviderTest.java │ ├── SkymeldUsedDataProviderTest.java │ └── remoteexecution │ │ ├── BUILD │ │ ├── CriticalPathQueuingDurationDataProviderTest.java │ │ ├── QueuingObservedDataProviderTest.java │ │ ├── RemoteCachingUsedDataProviderTest.java │ │ ├── RemoteExecutionDataProviderSuite.java │ │ ├── RemoteExecutionUsedDataProviderTest.java │ │ ├── RemoteLatencyDataProviderTest.java │ │ └── TotalQueuingDurationDataProviderTest.java │ ├── integrationtests │ ├── BUILD │ ├── IntegerationTestBase.java │ ├── IntegrationTestSuite.java │ ├── JobsSuggestionProviderIntegrationTest.java │ └── NegligiblePhaseSuggestionProviderIntegrationTest.java │ ├── profiles │ ├── bazel-profile-Long-Phase-Test.json │ ├── bazel-profile-with_queuing.json.gz │ ├── local-jobs-100.json.gz │ ├── local-jobs-4.json.gz │ ├── local-jobs-none.json.gz │ └── tiny.json.gz │ ├── suggestionproviders │ ├── BUILD │ ├── BottleneckSuggestionProviderTest.java │ ├── BuildWithoutTheBytesSuggestionProviderTest.java │ ├── CriticalPathNotDominantSuggestionProviderTest.java │ ├── GarbageCollectionSuggestionProviderTest.java │ ├── IncompleteProfileSuggestionProviderTest.java │ ├── InvestigateRemoteCacheMissesSuggestionProviderTest.java │ ├── JobsSuggestionProviderTest.java │ ├── LocalActionsWithRemoteExecutionSuggestionProviderTest.java │ ├── MergedEventsSuggestionProviderTest.java │ ├── NegligiblePhaseSuggestionProviderTest.java │ ├── NoCacheActionsSuggestionProviderTest.java │ ├── QueuingSuggestionProviderTest.java │ ├── SuggestionProviderUnitTestBase.java │ ├── SuggestionProvidersTestSuite.java │ ├── UseRemoteCachingSuggestionProviderTest.java │ └── UseSkymeldSuggestionProviderTest.java │ ├── time │ ├── BUILD │ ├── DurationUtilTest.java │ ├── TimeTestSuite.java │ ├── TimeUtilTest.java │ └── TimestampTest.java │ └── traceeventformat │ ├── BUILD │ ├── CompleteEventTest.java │ ├── CounterEventTest.java │ ├── InstantEventTest.java │ └── TraceEventFormatTestSuite.java ├── cli ├── BUILD ├── java │ └── com │ │ └── engflow │ │ └── bazel │ │ └── invocation │ │ └── analyzer │ │ ├── BUILD │ │ ├── Main.java │ │ ├── consoleoutput │ │ ├── BUILD │ │ ├── ConsoleOutput.java │ │ └── ConsoleOutputStyle.java │ │ └── options │ │ ├── BUILD │ │ ├── IaOption.java │ │ ├── IaOptions.java │ │ └── Mode.java └── javatests │ └── com │ └── engflow │ └── bazel │ └── invocation │ └── analyzer │ └── consoleoutput │ ├── BUILD │ ├── ConsoleOutputSuite.java │ └── ConsoleOutputTest.java ├── conditions └── BUILD ├── docs ├── adding-suggestions.md ├── assets │ ├── gc-profile-in-chrome-tracing.png │ ├── gc-suggestion-output.png │ └── library-architecture.svg └── library-architecture.md ├── infra ├── BUILD ├── git │ └── hooks │ │ └── pre-commit ├── lint.sh └── setup.sh ├── maven_install.json ├── proto ├── BUILD └── bazel_invocation_analyzer.proto ├── renovate.json └── third_party ├── buildifier └── BUILD ├── commons-cli └── BUILD ├── google-java-format └── BUILD ├── gson └── BUILD ├── guava └── BUILD ├── jsr305 └── BUILD ├── junit └── BUILD ├── mockito └── BUILD └── truth └── BUILD /.bazelignore: -------------------------------------------------------------------------------- 1 | engflow 2 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | # Required for Bazel versions <7, where bzlmod is not enabled by default 2 | common --enable_bzlmod 3 | build --incompatible_sandbox_hermetic_tmp 4 | build --lockfile_mode=update 5 | 6 | common --enable_platform_specific_config 7 | common --experimental_announce_profile_path 8 | 9 | coverage --combined_report=lcov 10 | # These are required to make coverage work. 11 | coverage --experimental_fetch_all_coverage_outputs 12 | coverage --experimental_split_coverage_postprocessing 13 | # The Coverage report generator can't run remotely because it's missing some 14 | # RE platform options (especially containerImage). 15 | coverage --strategy=CoverageReport=local 16 | 17 | build --explicit_java_test_deps 18 | build --nostamp 19 | build --incompatible_strict_action_env 20 | build --verbose_failures 21 | 22 | # Java Options 23 | build --java_language_version=17 24 | build --java_runtime_version=remotejdk_17 25 | build --tool_java_language_version=17 26 | build --tool_java_runtime_version=remotejdk_17 27 | build --javacopt=-Xep:FutureReturnValueIgnored:ERROR 28 | 29 | test --test_summary=testcase 30 | test --test_output=errors 31 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 7.4.1 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Report a bug. 4 | title: "{short headline describing the bug, not the fix}" 5 | labels: 6 | - type/bug 7 | --- 8 | 9 | ## Description 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | ### Observed behavior 14 | 15 | A clear and concise description of the observed behavior. 16 | 17 | ### Expected behavior 18 | 19 | A clear and concise description of what the behavior should be. 20 | 21 | ### Step-by-step guide on how to reproduce the bug 22 | 23 | 1. Use numbered steps for easier later reference. 24 | 1. If you used the CLI, include the command you ran: 25 | ```bash 26 | the command run 27 | ``` 28 | 29 | ## Additional context 30 | 31 | Supplemental data helps debug issues more quickly and reliably. 32 | 33 | Provide as many details as you feel comfortable sharing publicly. 34 | Alternatively, email data to while referencing the 35 | created issue, or opt to send the bug report entirely by email. 36 | 37 | ### Environment 38 | 39 | Details about the environment this bug was observed in. 40 | 41 | - Bazel Invocation Analyzer: [version number or commit id] 42 | - Browser: [e.g. Chrome, Safari] 43 | - Operating System: [e.g. Linux, macOS, Windows including version] 44 | - Other: 45 | 46 | ### Output 47 | 48 | Optionally include the tool's output. You can add a screenshot, or copy and paste the text output 49 | either in its entirety or only the relevant section(s). Inline the output as a code block here or 50 | attach a text file. 51 | 52 | ``` 53 | example output 54 | ``` 55 | 56 | ### File(s) scanned 57 | 58 | Optionally provide file(s) that demonstrate the bug when running the tool. 59 | 60 | Ideally, do not attach files directly. Bazel profiles can include sensitive data, such as exposing 61 | which dependencies your project includes. 62 | 63 | Instead, upload files to the cloud storage provider of your choice and grant appropriate access. 64 | This allows you to adjust who can access them now and in the future. For example, you may want to 65 | remove access to the files once the issue has been resolved. 66 | 67 | ### Further details 68 | 69 | Provide other data related to this issue that may prove helpful. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ✨ Feature Request 3 | about: Request a feature. 4 | title: "{short headline describing the requested feature}" 5 | labels: 6 | - type/feat 7 | --- 8 | 9 | ## Problem 10 | 11 | A clear and concise description of the problem observed. 12 | 13 | ## (Optional) Preferred solution 14 | 15 | A clear and concise description of how the problem might be solved. 16 | 17 | This may include 18 | 19 | - Implementation details 20 | - Tradeoffs 21 | - Caveats and considerations for future work 22 | 23 | ## (Optional) Alternative solution 24 | 25 | If proposing different solutions, present each one separately. 26 | 27 | ## Additional information 28 | 29 | Supplemental data helps evaluate and implement feature requests more quickly and reliably. 30 | 31 | Provide as many details as you feel comfortable sharing publicly. 32 | Alternatively, email data to while referencing the 33 | created issue, or opt to send the feature request entirely by email. 34 | 35 | For example, you may want to include example files, reference other issues, etc. 36 | 37 | Ideally, do not attach files directly. Bazel profiles can include sensitive data, such as exposing 38 | which dependencies your project includes. 39 | 40 | Instead, upload files to the cloud storage provider of your choice and grant appropriate access. 41 | This allows you to adjust who can access them now and in the future. For example, you may want to 42 | remove access to the files once the issue has been resolved. 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feedback.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💬 Feedback 3 | about: Provide feedback on Bazel Invocation Analyzer 4 | title: "{😀/😐/🙁 short headline describing the feedback}" 5 | labels: 6 | - type/feedback 7 | --- 8 | 9 | ## Feedback 10 | 11 | Leave your feedback here. 12 | 13 | ## Details 14 | 15 | Supplemental data gives context for the feedback and makes it easier to act on, where appropriate. 16 | 17 | Provide as many details as you feel comfortable sharing publicly. 18 | Alternatively, email data to while referencing the 19 | created issue, or opt to send the feedback entirely by email. 20 | 21 | ### Output 22 | 23 | Optionally include the tool's output. You can add a screenshot, or copy and paste the text output 24 | either in its entirety or only the relevant section(s). Inline the output as a code block here or 25 | attach a text file. 26 | 27 | ``` 28 | example output 29 | ``` 30 | 31 | ### File(s) scanned 32 | 33 | Optionally attach the Bazel profile(s) that were analyzed by the Bazel Invocation Analyzer. 34 | 35 | Ideally, do not attach files directly. Bazel profiles can include sensitive data, such as exposing 36 | which dependencies your project includes. 37 | 38 | Instead, upload files to the cloud storage provider of your choice and grant appropriate access. 39 | This allows you to adjust who can access them now and in the future. For example, you may want to 40 | remove access to the files once the issue has been resolved. 41 | 42 | ### Further details 43 | 44 | Provide other data related to this issue that may prove helpful. -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: {} 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | timeout-minutes: 5 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Build 14 | run: | 15 | bazel build //... 16 | - name: Test 17 | run: | 18 | bazel test //... 19 | lint: 20 | runs-on: ubuntu-latest 21 | timeout-minutes: 5 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Lint 26 | run: | 27 | bazel run //infra:lint -- "$(pwd)" 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bazel-* 2 | /.ijwb 3 | /.clwb 4 | /.project 5 | /.classes 6 | /.coverage 7 | *.swp 8 | /.bazelrc.user 9 | 10 | # macOS-specific excludes 11 | .DS_Store 12 | 13 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/BUILD -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @laszlocsomor @saraadams @WillEngFlow 2 | -------------------------------------------------------------------------------- /MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "com_engflow_bazel_invocation_analyzer", 3 | ) 4 | 5 | """Bazel build and test dependencies.""" 6 | 7 | # ========================================= 8 | # Bazel module dependencies 9 | # ========================================= 10 | 11 | bazel_dep(name = "bazel_skylib", version = "1.7.1") 12 | bazel_dep(name = "buildifier_prebuilt", version = "6.4.0") 13 | bazel_dep(name = "platforms", version = "0.0.10") 14 | bazel_dep(name = "rules_java", version = "8.7.1") 15 | bazel_dep(name = "rules_jvm_external", version = "6.3") 16 | bazel_dep(name = "protobuf", version = "29.1") 17 | 18 | # ========================================= 19 | # Java dependencies 20 | # ========================================= 21 | maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") 22 | maven.install( 23 | artifacts = [ 24 | "com.google.code.findbugs:jsr305:3.0.2", 25 | "com.google.code.gson:gson:2.11.0", 26 | "com.google.guava:failureaccess:1.0.2", 27 | "com.google.guava:guava:33.2.1-jre", 28 | "commons-cli:commons-cli:1.8.0", 29 | 30 | # For Tests 31 | "com.google.googlejavaformat:google-java-format:1.22.0", 32 | "com.google.truth:truth:1.4.3", 33 | "com.google.truth.extensions:truth-java8-extension:1.4.3", 34 | "junit:junit:4.13.2", 35 | "org.mockito:mockito-core:5.12.0", 36 | ], 37 | # When updating versions, run `REPIN=1 bazel run @maven//:pin` 38 | fail_if_repin_required = True, 39 | lock_file = "//:maven_install.json", 40 | repositories = [ 41 | "https://repo1.maven.org/maven2", 42 | ], 43 | ) 44 | use_repo(maven, "maven") 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bazel Invocation Analyzer 2 | 3 | The Bazel Invocation Analyzer is a library and terminal tool developed by EngFlow. It analyzes an invocation's Bazel profile and provides suggestions on how to speed up that invocation. 4 | 5 | ## Contact 6 | 7 | You can get in touch with us 8 | 9 | - by sending an email to 10 | - by [creating an issue on GitHub](https://github.com/EngFlow/bazel_invocation_analyzer/issues) 11 | 12 | ## Documentation 13 | 14 | - [Bazel Invocation Analyzer Architecture](docs/library-architecture.md) 15 | - [Adding Suggestions to the Bazel Invocation Analyzer](docs/adding-suggestions.md) walk-through 16 | 17 | You can also view this tool's documentation on . 18 | 19 | ## Dependencies 20 | 21 | [Bazel](https://bazel.build/) version 6.3+ 22 | 23 | We recommend using [Bazelisk](https://bazel.build/install/bazelisk). 24 | 25 | ## CLI 26 | 27 | The Bazel Invocation Analyzer can be run in a terminal. In this mode it will print out the analysis results directly to the console. 28 | 29 | ### Usage 30 | 31 | Pass in the path of a Bazel profile on your filesystem as the first argument. Use `-h` or `--help` to show all the available options. 32 | 33 | ```bash 34 | bazel run //cli -- /path/to/bazel_profile.json.gz 35 | ``` 36 | 37 | ## Integrations 38 | The Bazel Invocation Analyzer can be integrated into other environments. 39 | 40 | ### Public Web UIs 41 | 42 | On you can upload a Bazel profile to receive a rendered version of the library's output. 43 | 44 | ## Contributing 45 | 46 | We welcome contributions from the community. Read our [guide to contributing](https://github.com/EngFlow/bazel_invocation_analyzer/blob/main/CONTRIBUTING.md) for details. 47 | 48 | ## References 49 | 50 | - [Generating a Bazel 51 | profile](https://docs.engflow.com/re/faq.html#how-do-i-capture-a-bazel-profile) 52 | - [Interpreting a Bazel profile](https://bazel.build/rules/performance#performance-profiling) 53 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | TYPES = [ 4 | "BazelProfileConstants.java", 5 | "BazelProfilePhase.java", 6 | "ThreadId.java", 7 | ] 8 | 9 | java_library( 10 | name = "bazelprofile", 11 | srcs = glob( 12 | ["*.java"], 13 | exclude = TYPES + ["BazelEventsUtil.java"], 14 | ), 15 | visibility = ["//visibility:public"], 16 | deps = [ 17 | ":types", 18 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 19 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:types", 20 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 21 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 22 | "//third_party/gson", 23 | "//third_party/guava", 24 | "//third_party/jsr305", 25 | ], 26 | ) 27 | 28 | java_library( 29 | name = "types", 30 | srcs = TYPES, 31 | visibility = ["//visibility:public"], 32 | deps = [ 33 | "//third_party/guava", 34 | ], 35 | ) 36 | 37 | java_library( 38 | name = "util", 39 | srcs = ["BazelEventsUtil.java"], 40 | visibility = ["//visibility:public"], 41 | deps = [ 42 | ":types", 43 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 44 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 45 | "//third_party/guava", 46 | ], 47 | ) 48 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile/BazelProfilePhase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.bazelprofile; 16 | 17 | public enum BazelProfilePhase { 18 | // The order of these is important, it reflects in which order we expect the timestamps of the 19 | // phases markers in the Bazel profile to be. 20 | // Names taken from 21 | // https://github.com/bazelbuild/bazel/blob/febfa54dbe62d719ad6dbbfdd12bd6f8c0923b7a/src/main/java/com/google/devtools/build/lib/profiler/ProfilePhase.java#L20-L32 22 | LAUNCH("Launch Blaze"), 23 | INIT("Initialize command"), 24 | TARGET_PATTERN_EVAL("Evaluate target patterns"), 25 | ANALYZE("Load and analyze dependencies"), 26 | ANALYZE_AND_EXECUTE("Load, analyze dependencies and build artifacts"), 27 | LICENSE("Analyze licenses"), 28 | PREPARE("Prepare for build"), 29 | EXECUTE("Build artifacts"), 30 | FINISH("Complete build"); 31 | 32 | public final String name; 33 | 34 | BazelProfilePhase(String name) { 35 | this.name = name; 36 | } 37 | 38 | /** 39 | * Returns the previous Bazel phase. 40 | * 41 | * @throws UnsupportedOperationException for the first phase 42 | */ 43 | public BazelProfilePhase getPrevious() throws UnsupportedOperationException { 44 | if (this.ordinal() == 0) { 45 | throw new UnsupportedOperationException(); 46 | } 47 | return values()[this.ordinal() - 1]; 48 | } 49 | 50 | /** 51 | * Returns the next Bazel phase. 52 | * 53 | * @throws UnsupportedOperationException for the last phase 54 | */ 55 | public BazelProfilePhase getNext() throws UnsupportedOperationException { 56 | if (this.ordinal() == values().length - 1) { 57 | throw new UnsupportedOperationException(); 58 | } 59 | return values()[this.ordinal() + 1]; 60 | } 61 | 62 | public static BazelProfilePhase parse(String name) { 63 | for (BazelProfilePhase phase : values()) { 64 | if (phase.name.equals(name)) { 65 | return phase; 66 | } 67 | } 68 | return null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile/ThreadId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.bazelprofile; 16 | 17 | import java.util.Objects; 18 | 19 | public class ThreadId { 20 | private final int processId; 21 | private final int threadId; 22 | 23 | public ThreadId(int processId, int threadId) { 24 | this.processId = processId; 25 | this.threadId = threadId; 26 | } 27 | 28 | public int getThreadId() { 29 | return threadId; 30 | } 31 | 32 | public int getProcessId() { 33 | return processId; 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) { 39 | return true; 40 | } 41 | if (o == null || getClass() != o.getClass()) { 42 | return false; 43 | } 44 | ThreadId other = (ThreadId) o; 45 | return processId == other.processId && threadId == other.threadId; 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Objects.hash(processId, threadId); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return String.format("processId: %d, threadId: %d", processId, threadId); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "core", 5 | srcs = glob(["*.java"]), 6 | visibility = ["//visibility:public"], 7 | deps = [ 8 | "//proto:bazel_invocation_analyzer_java_proto", 9 | "//third_party/jsr305", 10 | ], 11 | ) 12 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/DataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | import java.util.List; 18 | import javax.annotation.Nullable; 19 | 20 | /** 21 | * Provides groupings of analysis data to the {@link DataManager} that are more efficient to 22 | * calculate together. {@link DataProvider}s may consume other pieces of data from the DataManager 23 | * and perform calculation on them. 24 | */ 25 | public abstract class DataProvider { 26 | @Nullable private DataManager dataManager; 27 | 28 | /** 29 | * Registers the {@link DataProvider} with the supplied {@link DataManager} and saves it for use 30 | * by the {@link DatumSupplier}s. 31 | * 32 | * @param dataManager The DataManager that tracks this DataProvider and provides data from other 33 | * DataProviders. 34 | * @throws DuplicateProviderException If a DataProvider that supplies the same data types is 35 | * already registered with the {@link DataManager}. 36 | */ 37 | public void register(DataManager dataManager) throws DuplicateProviderException { 38 | this.dataManager = dataManager; 39 | this.dataManager.registerProvider(this); 40 | } 41 | 42 | /** 43 | * Retrieve the {@link DataManager} this DataProvider is registered with. 44 | * 45 | * @return {@link DataManager} this DataProvider is registered with. 46 | * @throws IllegalStateException if called before {@link #register(DataManager) register} is 47 | * called. 48 | */ 49 | protected DataManager getDataManager() { 50 | if (dataManager == null) { 51 | throw new IllegalStateException( 52 | String.format( 53 | "%s tried to access DataManager before it was registered.", 54 | this.getClass().getName())); 55 | } 56 | return dataManager; 57 | } 58 | 59 | /** 60 | * Returns the specification of all the datum suppliers provided by this DataProvider. 61 | * 62 | * @return The list of supplier specifications that are calculated and provided by this 63 | * DataProvider. 64 | */ 65 | public abstract List> getSuppliers(); 66 | } 67 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/Datum.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | /** Base class for all datum elements returned by {@link DataProvider}s */ 18 | public interface Datum { 19 | 20 | /** 21 | * Check whether this datum includes any data. It may be that the input sources do not include the 22 | * data required for providing information. 23 | * 24 | * @return Whether the datum includes no data. 25 | */ 26 | boolean isEmpty(); 27 | 28 | /** 29 | * If the datum {@link #isEmpty}, retrieve a reason explaining why it is empty. 30 | * 31 | * @return The reason why the datum is empty, or null if non-empty. 32 | */ 33 | String getEmptyReason(); 34 | 35 | /** 36 | * Get a description of the kind of data this datum provides. This description should be 37 | * independent of the data, i.e. static. 38 | * 39 | * @return A description of this datum for display to the user. 40 | */ 41 | String getDescription(); 42 | 43 | /** 44 | * Get a summary of the actual data this datum provides. May return null if the datum is empty. 45 | * 46 | * @return A summary of this datum for display to the user, or null. 47 | */ 48 | String getSummary(); 49 | } 50 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/DatumSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | import javax.annotation.Nullable; 18 | 19 | /** 20 | * A Function that produces a specific type of data. 21 | * 22 | *

This is distinct form the {@link java.util.function.Supplier} interface as it must throw an 23 | * exception. 24 | * 25 | * @param The type of the data returned. 26 | */ 27 | @FunctionalInterface 28 | public interface DatumSupplier { 29 | /** 30 | * Calculates and returns a type of data. 31 | * 32 | *

Note: This method MUST be thread-safe. Consider using `synchronized`. 33 | * 34 | * @return The calculated data. 35 | * @throws MissingInputException If the required input data cannot be fetched from the {@link 36 | * DataManager}. 37 | * @throws InvalidProfileException If the required input data cannot be parsed from the Bazel 38 | * profile. 39 | */ 40 | DatumType supply() throws InvalidProfileException, MissingInputException, NullDatumException; 41 | 42 | /** 43 | * Returns a memoized version of a {@link DatumSupplier}. 44 | * 45 | *

The supplier will only ever be called once and a cached value will be returned for every 46 | * call after the first. 47 | * 48 | * @param supplier The supplier that performs a calculation and returns the result. 49 | * @param The return type of the supplier. 50 | * @return A DatumSupplier of the same signature as the input supplier that memoizes the internal 51 | * supplier. 52 | */ 53 | static DatumSupplier memoized(DatumSupplier supplier) { 54 | return new DatumSupplier<>() { 55 | @Nullable private T cachedOutput; 56 | 57 | @Override 58 | public T supply() throws InvalidProfileException, MissingInputException, NullDatumException { 59 | // If we already have the value return early. 60 | if (cachedOutput != null) { 61 | return cachedOutput; 62 | } else { 63 | synchronized (supplier) { 64 | // Need to check again to make sure someone didn't set it while we were waiting on the 65 | // `supplier` lock. 66 | if (cachedOutput == null) { 67 | cachedOutput = supplier.supply(); 68 | } 69 | return cachedOutput; 70 | } 71 | } 72 | } 73 | }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/DatumSupplierSpecification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | /** 18 | * Describes a supplier of a single class of data. 19 | * 20 | *

The main function of this class is to safely couple the Java class object to the supplier 21 | * function that produces the same class type. This is necessary because suppliers are keyed based 22 | * off of their class types at runtime. Due to Java type erasure these types are not retained at 23 | * runtime so they must be explicitly set in the code. 24 | * 25 | * @param The type of datum supplied. 26 | */ 27 | public class DatumSupplierSpecification { 28 | private final Class clazz; 29 | private final DatumSupplier datumSupplier; 30 | 31 | /** 32 | * Creates a new specification. 33 | * 34 | * @param clazz The return class of the datumSupplier. 35 | * @param datumSupplier A supplier that calculates and returns a piece of data. 36 | * @param The type supplied by datumSupplier. 37 | * @return A new {@link DatumSupplierSpecification} with a type-safe class object and supplier 38 | * function. 39 | */ 40 | public static DatumSupplierSpecification of( 41 | Class clazz, DatumSupplier datumSupplier) { 42 | return new DatumSupplierSpecification<>(clazz, datumSupplier); 43 | } 44 | 45 | private DatumSupplierSpecification( 46 | Class clazz, DatumSupplier datumSupplier) { 47 | this.clazz = clazz; 48 | this.datumSupplier = datumSupplier; 49 | } 50 | 51 | public Class getSupplierOutputClass() { 52 | return clazz; 53 | } 54 | 55 | public DatumSupplier getDatumSupplier() { 56 | return datumSupplier; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/DuplicateProviderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | /** 18 | * Thrown when a {@link DataProvider} that provides a specific type of datum is registered to a 19 | * {@link DataManager} that already has a DataProvider registered that provides the same type of 20 | * datum. 21 | */ 22 | public class DuplicateProviderException extends Exception { 23 | private static final long serialVersionUID = 1L; 24 | 25 | private final Class datumType; 26 | private final Class existing; 27 | private final Class duplicate; 28 | 29 | public DuplicateProviderException( 30 | Class datumType, 31 | Class existing, 32 | Class duplicate) { 33 | this.datumType = datumType; 34 | this.existing = existing; 35 | this.duplicate = duplicate; 36 | } 37 | 38 | @Override 39 | public String getMessage() { 40 | return String.format( 41 | "Duplicate providers found for type \"%s\": \"%s\" already registered and trying to add" 42 | + " \"%s\"!", 43 | datumType.getName(), existing.getName(), duplicate.getName()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/InvalidProfileException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | /** Thrown when a data expected to be in a Bazel profile is missing or in an unexpected format. */ 18 | public class InvalidProfileException extends Exception { 19 | private static final long serialVersionUID = 1L; 20 | 21 | /** 22 | * Constructor with exception 23 | * 24 | * @param errorMessage Message detailing what was found to be missing or invalid 25 | * @param err Error encountered while parsing 26 | */ 27 | public InvalidProfileException(String errorMessage, Throwable err) { 28 | super("This does not appear to be a valid Bazel profile. " + errorMessage, err); 29 | } 30 | 31 | /** 32 | * Constructor with no exception 33 | * 34 | * @param errorMessage Message detailing what was found to be missing or invalid 35 | */ 36 | public InvalidProfileException(String errorMessage) { 37 | super("This does not appear to be a valid Bazel profile. " + errorMessage); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/MissingInputException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | /** 18 | * Thrown when an entity requests a type of datum from a {@link DataManager} that has no registered 19 | * {@link DataProvider}s that supply such data. 20 | */ 21 | public class MissingInputException extends Exception { 22 | private static final long serialVersionUID = 1L; 23 | 24 | private final Class missingInputClass; 25 | 26 | public MissingInputException(Class missingInputClass) { 27 | this.missingInputClass = missingInputClass; 28 | } 29 | 30 | @Override 31 | public String getMessage() { 32 | return String.format( 33 | "Missing data provider for class \"%s\". Please register a DataProvider that supplies this" 34 | + " type with the DataManager.", 35 | missingInputClass.getName()); 36 | } 37 | 38 | public Class getMissingInputClass() { 39 | return missingInputClass; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/NullDatumException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | /** 18 | * Thrown when an entity requests a type of {@link Datum} from a {@link DataManager} and null is 19 | * supplied by the registered {@link DataProvider}. 20 | */ 21 | public class NullDatumException extends Exception { 22 | private static final long serialVersionUID = 1L; 23 | 24 | private final Class dataProviderClass; 25 | private final Class datumClass; 26 | 27 | public NullDatumException( 28 | Class dataProviderClass, Class datumClass) { 29 | this.dataProviderClass = dataProviderClass; 30 | this.datumClass = datumClass; 31 | } 32 | 33 | @Override 34 | public String getMessage() { 35 | return String.format( 36 | "The DataProvider \"%s\" for supplying \"%s\" supplied null.", 37 | dataProviderClass.getName(), datumClass.getName()); 38 | } 39 | 40 | public Class getDatumClass() { 41 | return datumClass; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/core/SuggestionProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | import com.engflow.bazel.invocation.analyzer.SuggestionOutput; 18 | 19 | /** 20 | * {@link SuggestionProvider}s use data from a {@link DataManager} and attempt to produce one or 21 | * more suggestions based on the data. They should not perform any complex calculation and should 22 | * instead rely on {@link DataProvider}s to perform calculations whose results can be shared among 23 | * suggestion providers. 24 | */ 25 | @FunctionalInterface 26 | public interface SuggestionProvider { 27 | /** 28 | * Takes in a {@link DataManager} and produces suggestions. 29 | * 30 | * @param dataManager The DataManager that houses all the data that may be used to generate 31 | * suggestions. 32 | * @return An output containing zero or more applicable suggestions and any exceptions that 33 | * occurred while trying to analyze the data to create suggestions. 34 | */ 35 | SuggestionOutput getSuggestions(DataManager dataManager); 36 | } 37 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/ActionStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import com.google.common.base.Strings; 21 | import java.time.Duration; 22 | import java.util.List; 23 | import java.util.Optional; 24 | import javax.annotation.Nullable; 25 | 26 | /** 27 | * This class collects all high-level aggregations of action level metrics: 28 | *

  • Bottlenecks: defined as intervals of a build during which the action count is constantly 29 | * lower than the core count, which is theoretically the highest possible action count as well 30 | * as the optimal one the build should always be running at. 31 | */ 32 | public class ActionStats implements Datum { 33 | private final Optional> bottlenecks; 34 | @Nullable private final String emptyReason; 35 | 36 | public ActionStats(String emptyReason) { 37 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 38 | this.bottlenecks = Optional.empty(); 39 | this.emptyReason = emptyReason; 40 | } 41 | 42 | public ActionStats(List bottlenecks) { 43 | Preconditions.checkNotNull(bottlenecks); 44 | this.bottlenecks = Optional.of(bottlenecks); 45 | this.emptyReason = null; 46 | } 47 | 48 | @Override 49 | public boolean isEmpty() { 50 | return bottlenecks.isEmpty(); 51 | } 52 | 53 | @Override 54 | public String getEmptyReason() { 55 | return emptyReason; 56 | } 57 | 58 | public Optional> getBottlenecks() { 59 | return bottlenecks; 60 | } 61 | 62 | @Override 63 | public String getDescription() { 64 | return "A list of bottlenecks, each of which include timing information and a list of actions" 65 | + " that prevent more parallelization. Extracted from the Bazel profile."; 66 | } 67 | 68 | @Override 69 | public String getSummary() { 70 | if (isEmpty()) { 71 | return null; 72 | } 73 | var duration = 74 | bottlenecks.get().stream().map(b -> b.getDuration()).reduce(Duration.ZERO, Duration::plus); 75 | return String.format( 76 | "%d %s found for a total duration of %s.", 77 | bottlenecks.get().size(), 78 | bottlenecks.get().size() == 1 ? "bottleneck" : "bottlenecks", 79 | DurationUtil.formatDuration(duration)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | TYPES = [ 4 | "ActionStats.java", 5 | "BazelPhaseDescription.java", 6 | "BazelPhaseDescriptions.java", 7 | "BazelVersion.java", 8 | "Bottleneck.java", 9 | "CriticalPathDuration.java", 10 | "EstimatedCores.java", 11 | "EstimatedCoresAvailable.java", 12 | "EstimatedCoresUsed.java", 13 | "EstimatedJobsFlagValue.java", 14 | "FlagValueExperimentalProfileIncludeTargetLabel.java", 15 | "GarbageCollectionStats.java", 16 | "LocalActions.java", 17 | "MergedEventsPresent.java", 18 | "SkymeldUsed.java", 19 | "TotalDuration.java", 20 | ] 21 | 22 | UTIL = [ 23 | "DataProviderUtil.java", 24 | ] 25 | 26 | java_library( 27 | name = "dataproviders", 28 | srcs = glob( 29 | ["*.java"], 30 | exclude = TYPES + UTIL, 31 | ), 32 | visibility = ["//visibility:public"], 33 | deps = [ 34 | ":types", 35 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 36 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 37 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:util", 38 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 39 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 40 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 41 | "//third_party/guava", 42 | "//third_party/jsr305", 43 | ], 44 | ) 45 | 46 | java_library( 47 | name = "util", 48 | srcs = UTIL, 49 | visibility = ["//visibility:public"], 50 | deps = [ 51 | ":dataproviders", 52 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 53 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution", 54 | ], 55 | ) 56 | 57 | java_library( 58 | name = "types", 59 | srcs = TYPES, 60 | visibility = ["//visibility:public"], 61 | deps = [ 62 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 63 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:util", 64 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 65 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 66 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 67 | "//third_party/guava", 68 | "//third_party/jsr305", 69 | ], 70 | ) 71 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/BazelPhaseDescription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfilePhase; 18 | import com.engflow.bazel.invocation.analyzer.time.TimeUtil; 19 | import com.engflow.bazel.invocation.analyzer.time.Timestamp; 20 | import com.google.common.annotations.VisibleForTesting; 21 | import java.time.Duration; 22 | import java.util.Objects; 23 | 24 | /** Metadata about a {@link BazelProfilePhase} */ 25 | public class BazelPhaseDescription { 26 | private final Timestamp start; 27 | private final Duration duration; 28 | 29 | public BazelPhaseDescription(Timestamp start, Timestamp end) { 30 | this(start, TimeUtil.getDurationBetween(start, end)); 31 | } 32 | 33 | @VisibleForTesting 34 | BazelPhaseDescription(Timestamp start, Duration duration) { 35 | this.start = start; 36 | this.duration = duration; 37 | } 38 | 39 | public Duration getDuration() { 40 | return duration; 41 | } 42 | 43 | public Timestamp getEnd() { 44 | return start.plus(duration); 45 | } 46 | 47 | public Timestamp getStart() { 48 | return start; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) { 54 | return true; 55 | } 56 | if (o == null || getClass() != o.getClass()) { 57 | return false; 58 | } 59 | BazelPhaseDescription that = (BazelPhaseDescription) o; 60 | return start.equals(that.start) && duration.equals(that.duration); 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return Objects.hash(start, duration); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/BazelVersionDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.engflow.bazel.invocation.analyzer.core.DatumSupplier.memoized; 18 | 19 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 20 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import java.util.List; 26 | 27 | /** 28 | * A {@link DataProvider} that supplies data on the Bazel version used when the Bazel profile was 29 | * generated. 30 | */ 31 | public class BazelVersionDataProvider extends DataProvider { 32 | @Override 33 | public List> getSuppliers() { 34 | return List.of( 35 | DatumSupplierSpecification.of(BazelVersion.class, memoized(this::getBazelVersion))); 36 | } 37 | 38 | public BazelVersion getBazelVersion() 39 | throws InvalidProfileException, MissingInputException, NullDatumException { 40 | return getDataManager().getDatum(BazelProfile.class).getBazelVersion(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/CriticalPathDuration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import com.google.common.base.Strings; 21 | import java.time.Duration; 22 | import java.util.Optional; 23 | import javax.annotation.Nullable; 24 | 25 | /** The duration of the critical path */ 26 | public class CriticalPathDuration implements Datum { 27 | private final Optional criticalPathDuration; 28 | @Nullable private final String emptyReason; 29 | 30 | public CriticalPathDuration(String emptyReason) { 31 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 32 | this.criticalPathDuration = Optional.empty(); 33 | this.emptyReason = emptyReason; 34 | } 35 | 36 | public CriticalPathDuration(Duration criticalPathDuration) { 37 | Preconditions.checkNotNull(criticalPathDuration); 38 | this.criticalPathDuration = Optional.of(criticalPathDuration); 39 | this.emptyReason = null; 40 | } 41 | 42 | public Optional getCriticalPathDuration() { 43 | return criticalPathDuration; 44 | } 45 | 46 | @Override 47 | public boolean isEmpty() { 48 | return criticalPathDuration.isEmpty(); 49 | } 50 | 51 | @Override 52 | public String getEmptyReason() { 53 | return emptyReason; 54 | } 55 | 56 | @Override 57 | public String getDescription() { 58 | return "The duration of the Bazel profile's critical path."; 59 | } 60 | 61 | @Override 62 | public String getSummary() { 63 | return isEmpty() ? null : DurationUtil.formatDuration(criticalPathDuration.get()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/CriticalPathDurationDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.ProfileThread; 19 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 20 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import com.google.common.annotations.VisibleForTesting; 26 | import java.time.Duration; 27 | import java.util.List; 28 | 29 | /** 30 | * A {@link DataProvider} that supplies the total duration of the critical path. For this, the sum 31 | * of the durations of all actions that are part of the critical path is calculated. 32 | */ 33 | public class CriticalPathDurationDataProvider extends DataProvider { 34 | public static final String EMPTY_REASON_CRITICAL_PATH_MISSING = 35 | "The Bazel profile does not include a critical path, which is required for determining its" 36 | + " duration. Try analyzing a profile that processes actions, for example a build or" 37 | + " test."; 38 | public static final String EMPTY_REASON_CRITICAL_PATH_EMPTY = 39 | "The Bazel profile's critical path includes no events, which suggests that the Bazel" 40 | + " invocation did not process any actions. Try analyzing a profile that processes" 41 | + " actions, for example a build or test."; 42 | 43 | @Override 44 | public List> getSuppliers() { 45 | return List.of( 46 | DatumSupplierSpecification.of( 47 | CriticalPathDuration.class, DatumSupplier.memoized(this::getCriticalPathDuration))); 48 | } 49 | 50 | @VisibleForTesting 51 | CriticalPathDuration getCriticalPathDuration() 52 | throws InvalidProfileException, MissingInputException, NullDatumException { 53 | BazelProfile bazelProfile = getDataManager().getDatum(BazelProfile.class); 54 | if (bazelProfile.getCriticalPath().isEmpty()) { 55 | return new CriticalPathDuration(EMPTY_REASON_CRITICAL_PATH_MISSING); 56 | } 57 | ProfileThread criticalPath = bazelProfile.getCriticalPath().get(); 58 | if (criticalPath.getCompleteEvents().isEmpty()) { 59 | return new CriticalPathDuration(EMPTY_REASON_CRITICAL_PATH_EMPTY); 60 | } 61 | Duration duration = 62 | criticalPath.getCompleteEvents().stream() 63 | .map((event) -> event.duration) 64 | .reduce(Duration.ZERO, Duration::plus); 65 | return new CriticalPathDuration(duration); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/DataProviderUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 18 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.CriticalPathQueuingDurationDataProvider; 19 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.QueuingObservedDataProvider; 20 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.RemoteCachingUsedDataProvider; 21 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.RemoteExecutionUsedDataProvider; 22 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.TotalQueuingDurationDataProvider; 23 | import java.util.List; 24 | 25 | public class DataProviderUtil { 26 | /** 27 | * Convenience method for retrieving all available {@link DataProvider}s. When adding a new 28 | * DataProvider, also add it to the list returned by this method. 29 | * 30 | * @return The list of all available {@link DataProvider}s. 31 | */ 32 | public static List getAllDataProviders() { 33 | return List.of( 34 | new ActionStatsDataProvider(), 35 | new BazelPhasesDataProvider(), 36 | new BazelVersionDataProvider(), 37 | new CachingAndExecutionMetricsDataProvider(), 38 | new CriticalPathDurationDataProvider(), 39 | new EstimatedCoresDataProvider(), 40 | new FlagValueDataProvider(), 41 | new GarbageCollectionStatsDataProvider(), 42 | new LocalActionsDataProvider(), 43 | new MergedEventsPresentDataProvider(), 44 | new SkymeldUsedDataProvider(), 45 | 46 | // RemoteExecution 47 | new CriticalPathQueuingDurationDataProvider(), 48 | new QueuingObservedDataProvider(), 49 | new RemoteCachingUsedDataProvider(), 50 | new RemoteExecutionUsedDataProvider(), 51 | new TotalQueuingDurationDataProvider(), 52 | 53 | // RemoteCache 54 | new RemoteCacheMetricsDataProvider()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/EstimatedCores.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.google.common.base.Preconditions; 19 | import com.google.common.base.Strings; 20 | import java.util.Optional; 21 | import javax.annotation.Nullable; 22 | 23 | /** Estimate of the number of cores used or available. */ 24 | public abstract class EstimatedCores implements Datum { 25 | private final Optional estimatedCores; 26 | private final Optional gaps; 27 | @Nullable private final String emptyReason; 28 | 29 | EstimatedCores(Integer estimatedCores, Integer gaps) { 30 | Preconditions.checkNotNull(estimatedCores); 31 | Preconditions.checkNotNull(gaps); 32 | this.estimatedCores = Optional.of(estimatedCores); 33 | this.gaps = Optional.of(gaps); 34 | this.emptyReason = null; 35 | } 36 | 37 | EstimatedCores(String emptyReason) { 38 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 39 | this.estimatedCores = Optional.empty(); 40 | this.gaps = Optional.empty(); 41 | this.emptyReason = emptyReason; 42 | } 43 | 44 | @Override 45 | public boolean isEmpty() { 46 | return estimatedCores.isEmpty() && gaps.isEmpty(); 47 | } 48 | 49 | @Override 50 | public String getEmptyReason() { 51 | return emptyReason; 52 | } 53 | 54 | public Optional getEstimatedCores() { 55 | return estimatedCores; 56 | } 57 | 58 | public boolean hasGaps() { 59 | return gaps.isPresent() && gaps.get() > 0; 60 | } 61 | 62 | /** 63 | * The estimated cores are based on skyframe-evaluators listed in the Bazel profile. These are 64 | * numbered starting with 0 up to the determined maximum allowed. However, if they are not used at 65 | * all, they may be dropped from the profile, which leads to gaps in the list of numbered 66 | * skyframe-evaluators.
    67 | * This method returns how many such numbered skyframe-evaluators are not present in the profile, 68 | * compared to all numbers from 0 up to the maximum found in the profile.
    69 | * Dropped evaluators with a number above the maximum found are not detected. In that, the maximum 70 | * found only represent a lower bound for the maximum allowed. 71 | */ 72 | public Optional getGaps() { 73 | return gaps; 74 | } 75 | 76 | @Override 77 | public String getSummary() { 78 | return isEmpty() 79 | ? null 80 | : String.format("%d cores (with %d gaps)", estimatedCores.get(), gaps.get()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/EstimatedCoresAvailable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | /** 18 | * Estimate of the number of cores available, irrespective of restrictions imposed by setting the 19 | * flag `--jobs`. This value may both be higher or lower than {@link EstimatedCoresUsed}. 20 | */ 21 | public class EstimatedCoresAvailable extends EstimatedCores { 22 | public EstimatedCoresAvailable(String emptyReason) { 23 | super(emptyReason); 24 | } 25 | 26 | public EstimatedCoresAvailable(Integer estimatedCoresAvailable, Integer gaps) { 27 | super(estimatedCoresAvailable, gaps); 28 | } 29 | 30 | @Override 31 | public String getDescription() { 32 | return "The estimated number of cores available on the machine that ran the Bazel client, as" 33 | + " well as how many numbers were skipped when naming skyframe-evaluators. Extracted" 34 | + " from the Bazel profile."; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/EstimatedCoresUsed.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | /** 18 | * Estimate of the number of cores used, as configured via the flag `--jobs`. If this flag is not 19 | * set, this should match with {@link EstimatedCoresAvailable}. 20 | */ 21 | public class EstimatedCoresUsed extends EstimatedCores { 22 | public EstimatedCoresUsed(String emptyReason) { 23 | super(emptyReason); 24 | } 25 | 26 | public EstimatedCoresUsed(Integer estimatedCoresUsed, Integer gaps) { 27 | super(estimatedCoresUsed, gaps); 28 | } 29 | 30 | @Override 31 | public String getDescription() { 32 | return "The estimated number of cores used during execution, as well as how many numbers were" 33 | + " skipped when naming skyframe-evaluators. Extracted from the Bazel profile."; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/EstimatedJobsFlagValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.google.common.base.Preconditions; 19 | import com.google.common.base.Strings; 20 | import java.util.Optional; 21 | import javax.annotation.Nullable; 22 | 23 | /** 24 | * Estimated value of the Bazel flag `--jobs`. The Bazel profile includes information from which we 25 | * can infer a lower bound for the value of this flag. If the flag is not set, Bazel usually 26 | * defaults to the number of available cores. So if the value does not match the estimated available 27 | * cores, more likely than not the flag `--jobs` was set. 28 | */ 29 | public class EstimatedJobsFlagValue implements Datum { 30 | private final Optional lowerBound; 31 | private final boolean likelySet; 32 | @Nullable private final String emptyReason; 33 | 34 | public EstimatedJobsFlagValue(String emptyReason) { 35 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 36 | this.lowerBound = Optional.empty(); 37 | this.likelySet = false; 38 | this.emptyReason = emptyReason; 39 | } 40 | 41 | public EstimatedJobsFlagValue(Integer lowerBound, boolean likelySet) { 42 | Preconditions.checkNotNull(lowerBound); 43 | this.lowerBound = Optional.ofNullable(lowerBound); 44 | this.likelySet = likelySet; 45 | this.emptyReason = null; 46 | } 47 | 48 | public Optional getLowerBound() { 49 | return lowerBound; 50 | } 51 | 52 | public boolean isLikelySet() { 53 | return likelySet; 54 | } 55 | 56 | @Override 57 | public boolean isEmpty() { 58 | return lowerBound.isEmpty(); 59 | } 60 | 61 | @Override 62 | public String getEmptyReason() { 63 | return emptyReason; 64 | } 65 | 66 | @Override 67 | public String getDescription() { 68 | return "Based on the Bazel profile, the estimated value that the Bazel flag `--jobs` was set" 69 | + " to."; 70 | } 71 | 72 | @Override 73 | public String getSummary() { 74 | return isEmpty() 75 | ? null 76 | : String.format( 77 | "Lower bound of %d; --jobs flag is likely %s", 78 | lowerBound.get(), likelySet ? "set" : "not set"); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/FlagValueDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.engflow.bazel.invocation.analyzer.core.DatumSupplier.memoized; 18 | 19 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 20 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 21 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 22 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 23 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 24 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 25 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 26 | import com.google.common.collect.ImmutableList; 27 | import java.util.List; 28 | 29 | /** 30 | * A {@link DataProvider} that supplies data on whether specific Bazel flags were used when the 31 | * Bazel profile was generated. 32 | */ 33 | public class FlagValueDataProvider extends DataProvider { 34 | @Override 35 | public List> getSuppliers() { 36 | return ImmutableList.of( 37 | DatumSupplierSpecification.of( 38 | FlagValueExperimentalProfileIncludeTargetLabel.class, 39 | memoized(this::getExperimentalProfileIncludeTargetLabel))); 40 | } 41 | 42 | public FlagValueExperimentalProfileIncludeTargetLabel getExperimentalProfileIncludeTargetLabel() 43 | throws InvalidProfileException, MissingInputException, NullDatumException { 44 | BazelProfile bazelProfile = getDataManager().getDatum(BazelProfile.class); 45 | // See 46 | // https://github.com/bazelbuild/bazel/blob/7d10999fc0357596824f2b6022bbbd895f245a3c/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java#L395 47 | // https://github.com/bazelbuild/bazel/blob/7d10999fc0357596824f2b6022bbbd895f245a3c/src/main/java/com/google/devtools/build/lib/profiler/Profiler.java#L818 48 | // https://github.com/bazelbuild/bazel/blob/7d10999fc0357596824f2b6022bbbd895f245a3c/src/main/java/com/google/devtools/build/lib/profiler/Profiler.java#L206-L208 49 | var hasTarget = 50 | bazelProfile 51 | .getThreads() 52 | .flatMap(profileThread -> profileThread.getCompleteEvents().stream()) 53 | .anyMatch( 54 | event -> 55 | BazelProfileConstants.CAT_ACTION_PROCESSING.equals(event.category) 56 | && event.args.containsKey( 57 | BazelProfileConstants.ARGS_CAT_ACTION_PROCESSING_TARGET)); 58 | return new FlagValueExperimentalProfileIncludeTargetLabel(hasTarget); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/GarbageCollectionStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import com.google.common.base.Strings; 21 | import java.time.Duration; 22 | import java.util.Optional; 23 | import javax.annotation.Nullable; 24 | 25 | /** 26 | * Data on the garbage collection performed during the invocation. Major garbage collection suspends 27 | * all other threads, whereas minor garbage collection does not, or is sufficiently short to be 28 | * negligible. In that, major garbage collection occurrences have a much more significant impact on 29 | * an invocation's performance. 30 | */ 31 | public class GarbageCollectionStats implements Datum { 32 | private final Optional majorGarbageCollectionDuration; 33 | @Nullable private final String emptyReason; 34 | 35 | public GarbageCollectionStats(Duration majorGarbageCollectionDuration) { 36 | this.majorGarbageCollectionDuration = Optional.of(majorGarbageCollectionDuration); 37 | this.emptyReason = null; 38 | } 39 | 40 | public GarbageCollectionStats(String emptyReason) { 41 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 42 | this.majorGarbageCollectionDuration = Optional.empty(); 43 | this.emptyReason = emptyReason; 44 | } 45 | 46 | public boolean hasMajorGarbageCollection() { 47 | return !isEmpty() && !majorGarbageCollectionDuration.get().isZero(); 48 | } 49 | 50 | public Optional getMajorGarbageCollectionDuration() { 51 | return majorGarbageCollectionDuration; 52 | } 53 | 54 | @Override 55 | public boolean isEmpty() { 56 | return majorGarbageCollectionDuration.isEmpty(); 57 | } 58 | 59 | @Override 60 | public String getEmptyReason() { 61 | return emptyReason; 62 | } 63 | 64 | @Override 65 | public String getDescription() { 66 | return "The total duration of major garbage collection as extracted from the Bazel profile."; 67 | } 68 | 69 | @Override 70 | public String getSummary() { 71 | if (isEmpty()) { 72 | return null; 73 | } 74 | return hasMajorGarbageCollection() 75 | ? String.format( 76 | "Major GC duration of %s", 77 | DurationUtil.formatDuration(majorGarbageCollectionDuration.get())) 78 | : "No major GC occurred"; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/GarbageCollectionStatsDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.engflow.bazel.invocation.analyzer.core.DatumSupplier.memoized; 18 | 19 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 20 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 21 | import com.engflow.bazel.invocation.analyzer.bazelprofile.ProfileThread; 22 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 23 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 24 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 25 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 26 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 27 | import java.time.Duration; 28 | import java.util.List; 29 | import java.util.Optional; 30 | 31 | /** A {@link DataProvider} that supplies data on Bazel's garbage collection. */ 32 | public class GarbageCollectionStatsDataProvider extends DataProvider { 33 | @Override 34 | public List> getSuppliers() { 35 | return List.of( 36 | DatumSupplierSpecification.of( 37 | GarbageCollectionStats.class, memoized(this::getGarbageCollectionStats))); 38 | } 39 | 40 | public GarbageCollectionStats getGarbageCollectionStats() 41 | throws InvalidProfileException, MissingInputException, NullDatumException { 42 | BazelProfile bazelProfile = getDataManager().getDatum(BazelProfile.class); 43 | Optional garbageCollectorThread = bazelProfile.getGarbageCollectorThread(); 44 | if (garbageCollectorThread.isEmpty()) { 45 | return new GarbageCollectionStats( 46 | "Failed to find a garbage collector thread in the Bazel profile."); 47 | } 48 | Duration majorGarbageCollection = 49 | garbageCollectorThread.get().getCompleteEvents().stream() 50 | .filter( 51 | event -> 52 | BazelProfileConstants.COMPLETE_MAJOR_GARBAGE_COLLECTION.equals(event.name) 53 | && BazelProfileConstants.CAT_GARBAGE_COLLECTION.equals(event.category)) 54 | .map(event -> event.duration) 55 | .reduce(Duration.ZERO, Duration::plus); 56 | return new GarbageCollectionStats(majorGarbageCollection); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/MergedEventsPresent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | 19 | /** Whether evidence of merged Bazel profile events was found */ 20 | public class MergedEventsPresent implements Datum { 21 | private final boolean hasMergedEvents; 22 | 23 | public MergedEventsPresent(boolean hasMergedEvents) { 24 | this.hasMergedEvents = hasMergedEvents; 25 | } 26 | 27 | public boolean hasMergedEvents() { 28 | return hasMergedEvents; 29 | } 30 | 31 | @Override 32 | public boolean isEmpty() { 33 | return false; 34 | } 35 | 36 | @Override 37 | public String getEmptyReason() { 38 | return null; 39 | } 40 | 41 | @Override 42 | public String getDescription() { 43 | return "Whether the Bazel profile includes merged events."; 44 | } 45 | 46 | @Override 47 | public String getSummary() { 48 | return String.valueOf(hasMergedEvents); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/MergedEventsPresentDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 19 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 20 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 21 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 22 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 23 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 24 | import com.google.common.annotations.VisibleForTesting; 25 | import java.util.List; 26 | import java.util.regex.Pattern; 27 | 28 | /** A {@link DataProvider} that supplies whether the Bazel profile includes merged events. */ 29 | public class MergedEventsPresentDataProvider extends DataProvider { 30 | private static final Pattern MERGED_EVENTS_PATTERN = Pattern.compile("^merged\\s\\d+\\sevents$"); 31 | 32 | @Override 33 | public List> getSuppliers() { 34 | return List.of( 35 | DatumSupplierSpecification.of( 36 | MergedEventsPresent.class, DatumSupplier.memoized(this::getMergedEventsPresent))); 37 | } 38 | 39 | @VisibleForTesting 40 | MergedEventsPresent getMergedEventsPresent() 41 | throws InvalidProfileException, MissingInputException, NullDatumException { 42 | BazelProfile profile = getDataManager().getDatum(BazelProfile.class); 43 | return new MergedEventsPresent( 44 | profile 45 | .getThreads() 46 | .flatMap((thread) -> thread.getCompleteEvents().stream()) 47 | .anyMatch((event) -> MERGED_EVENTS_PATTERN.matcher(event.name).matches())); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/SkymeldUsed.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.Timestamp; 19 | import com.google.common.base.Preconditions; 20 | import java.util.Optional; 21 | 22 | /** 23 | * Whether evidence was found that Skymeld was used. 24 | * 25 | * @see Project Skymeld GitHub issue 26 | */ 27 | public class SkymeldUsed implements Datum { 28 | private final boolean skymeldUsed; 29 | private final Optional analysisAndExecutionPhase; 30 | private final Optional executionPhase; 31 | 32 | public SkymeldUsed() { 33 | this(false, Optional.empty(), Optional.empty()); 34 | } 35 | 36 | public SkymeldUsed( 37 | BazelPhaseDescription analysisAndExecutionPhase, Optional executionStart) { 38 | this(true, Optional.of(analysisAndExecutionPhase), executionStart); 39 | } 40 | 41 | private SkymeldUsed( 42 | boolean skymeldUsed, 43 | Optional analysisAndExecutionPhase, 44 | Optional executionStart) { 45 | this.skymeldUsed = skymeldUsed; 46 | this.analysisAndExecutionPhase = Preconditions.checkNotNull(analysisAndExecutionPhase); 47 | Preconditions.checkNotNull(executionStart); 48 | if (skymeldUsed && executionStart.isPresent()) { 49 | Preconditions.checkArgument(analysisAndExecutionPhase.isPresent()); 50 | this.executionPhase = 51 | Optional.of( 52 | new BazelPhaseDescription( 53 | executionStart.get(), analysisAndExecutionPhase.get().getEnd())); 54 | } else { 55 | this.executionPhase = Optional.empty(); 56 | } 57 | } 58 | 59 | public boolean isSkymeldUsed() { 60 | return skymeldUsed; 61 | } 62 | 63 | public Optional getAnalysisAndExecutionPhase() { 64 | return analysisAndExecutionPhase; 65 | } 66 | 67 | public Optional getExecutionPhase() { 68 | return executionPhase; 69 | } 70 | 71 | @Override 72 | public boolean isEmpty() { 73 | return false; 74 | } 75 | 76 | @Override 77 | public String getEmptyReason() { 78 | return null; 79 | } 80 | 81 | @Override 82 | public String getDescription() { 83 | return "Whether the Bazel Profile includes events indicating that Skymeld was used."; 84 | } 85 | 86 | @Override 87 | public String getSummary() { 88 | if (skymeldUsed) { 89 | return String.format( 90 | "%b (analysis started: %s, execution started: %s)", 91 | true, 92 | analysisAndExecutionPhase.get().getStart(), 93 | executionPhase.isPresent() ? executionPhase.get().getStart() : "n/a"); 94 | } 95 | return String.valueOf(false); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/SkymeldUsedDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 19 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfilePhase; 20 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 22 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 23 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 24 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 25 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 26 | import com.engflow.bazel.invocation.analyzer.time.Timestamp; 27 | import com.google.common.annotations.VisibleForTesting; 28 | import java.util.List; 29 | 30 | /** 31 | * A {@link DataProvider} that returns whether the profile looks like it was generated while using 32 | * Skymeld. 33 | * 34 | * @see Project Skymeld GitHub issue 35 | */ 36 | public class SkymeldUsedDataProvider extends DataProvider { 37 | @Override 38 | public List> getSuppliers() { 39 | return List.of( 40 | DatumSupplierSpecification.of( 41 | SkymeldUsed.class, DatumSupplier.memoized(this::getSkymeldUsed))); 42 | } 43 | 44 | @VisibleForTesting 45 | SkymeldUsed getSkymeldUsed() 46 | throws InvalidProfileException, MissingInputException, NullDatumException { 47 | BazelPhaseDescriptions bazelPhaseDescriptions = 48 | getDataManager().getDatum(BazelPhaseDescriptions.class); 49 | var interleavedAnalysisAndExecutionPhase = 50 | bazelPhaseDescriptions.get(BazelProfilePhase.ANALYZE_AND_EXECUTE); 51 | if (!interleavedAnalysisAndExecutionPhase.isPresent()) { 52 | return new SkymeldUsed(); 53 | } 54 | BazelProfile bazelProfile = getDataManager().getDatum(BazelProfile.class); 55 | var firstActionProcessing = 56 | bazelProfile 57 | .getThreads() 58 | // Find the first action processing event. 59 | .flatMap(thread -> thread.getCompleteEvents().stream()) 60 | .filter(event -> BazelProfileConstants.CAT_ACTION_PROCESSING.equals(event.category)) 61 | .map(event -> event.start) 62 | .min(Timestamp::compareTo); 63 | return new SkymeldUsed(interleavedAnalysisAndExecutionPhase.get(), firstActionProcessing); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/TotalDuration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import com.google.common.base.Strings; 21 | import java.time.Duration; 22 | import java.util.Optional; 23 | import javax.annotation.Nullable; 24 | 25 | /** The total duration of the invocation */ 26 | public class TotalDuration implements Datum { 27 | private final Optional totalDuration; 28 | @Nullable private final String emptyReason; 29 | 30 | public TotalDuration(String emptyReason) { 31 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 32 | this.totalDuration = Optional.empty(); 33 | this.emptyReason = emptyReason; 34 | } 35 | 36 | public TotalDuration(Duration totalDuration) { 37 | Preconditions.checkNotNull(totalDuration); 38 | this.totalDuration = Optional.of(totalDuration); 39 | this.emptyReason = null; 40 | } 41 | 42 | public Optional getTotalDuration() { 43 | return totalDuration; 44 | } 45 | 46 | @Override 47 | public boolean isEmpty() { 48 | return totalDuration.isEmpty(); 49 | } 50 | 51 | @Override 52 | public String getEmptyReason() { 53 | return emptyReason; 54 | } 55 | 56 | @Override 57 | public String getDescription() { 58 | return "The duration of the invocation as extracted from the Bazel profile."; 59 | } 60 | 61 | @Override 62 | public String getSummary() { 63 | return isEmpty() ? null : DurationUtil.formatDuration(totalDuration.get()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | TYPES = [ 4 | "CriticalPathQueuingDuration.java", 5 | "QueuingObserved.java", 6 | "RemoteCachingUsed.java", 7 | "RemoteExecutionUsed.java", 8 | "RemoteLatency.java", 9 | "TotalQueuingDuration.java", 10 | ] 11 | 12 | java_library( 13 | name = "remoteexecution", 14 | srcs = glob( 15 | ["*.java"], 16 | exclude = TYPES, 17 | ), 18 | visibility = ["//visibility:public"], 19 | deps = [ 20 | ":types", 21 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 22 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 23 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 24 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 25 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 26 | "//third_party/guava", 27 | ], 28 | ) 29 | 30 | java_library( 31 | name = "types", 32 | srcs = TYPES, 33 | visibility = ["//visibility:public"], 34 | deps = [ 35 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 36 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 37 | "//third_party/guava", 38 | "//third_party/jsr305", 39 | ], 40 | ) 41 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/CriticalPathQueuingDuration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import com.google.common.base.Strings; 21 | import java.time.Duration; 22 | import java.util.Optional; 23 | import javax.annotation.Nullable; 24 | 25 | /** The total time spent queued on the critical path */ 26 | public class CriticalPathQueuingDuration implements Datum { 27 | private final Optional criticalPathQueuingDuration; 28 | @Nullable private final String emptyReason; 29 | 30 | public CriticalPathQueuingDuration(String emptyReason) { 31 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 32 | this.criticalPathQueuingDuration = Optional.empty(); 33 | this.emptyReason = emptyReason; 34 | } 35 | 36 | public CriticalPathQueuingDuration(Duration criticalPathQueuingDuration) { 37 | Preconditions.checkNotNull(criticalPathQueuingDuration); 38 | this.criticalPathQueuingDuration = Optional.of(criticalPathQueuingDuration); 39 | this.emptyReason = null; 40 | } 41 | 42 | public Optional getCriticalPathQueuingDuration() { 43 | return criticalPathQueuingDuration; 44 | } 45 | 46 | @Override 47 | public boolean isEmpty() { 48 | return criticalPathQueuingDuration.isEmpty(); 49 | } 50 | 51 | @Override 52 | public String getEmptyReason() { 53 | return emptyReason; 54 | } 55 | 56 | @Override 57 | public String getDescription() { 58 | return "The duration of queuing within the Bazel profile's critical path."; 59 | } 60 | 61 | @Override 62 | public String getSummary() { 63 | return isEmpty() ? null : DurationUtil.formatDuration(criticalPathQueuingDuration.get()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/QueuingObserved.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | 19 | /** Whether queuing was observed for the invocation */ 20 | public class QueuingObserved implements Datum { 21 | private final boolean queuingObserved; 22 | 23 | public QueuingObserved(boolean queuingObserved) { 24 | this.queuingObserved = queuingObserved; 25 | } 26 | 27 | public boolean isQueuingObserved() { 28 | return queuingObserved; 29 | } 30 | 31 | @Override 32 | public boolean isEmpty() { 33 | return false; 34 | } 35 | 36 | @Override 37 | public String getEmptyReason() { 38 | return null; 39 | } 40 | 41 | @Override 42 | public String getDescription() { 43 | return "Whether the Bazel profile includes queuing."; 44 | } 45 | 46 | @Override 47 | public String getSummary() { 48 | return String.valueOf(queuingObserved); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/QueuingObservedDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 19 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 20 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import com.google.common.annotations.VisibleForTesting; 26 | import java.util.List; 27 | 28 | /** A {@link DataProvider} that supplies whether any remote execution queuing is included. */ 29 | public class QueuingObservedDataProvider extends DataProvider { 30 | 31 | @Override 32 | public List> getSuppliers() { 33 | return List.of( 34 | DatumSupplierSpecification.of( 35 | QueuingObserved.class, DatumSupplier.memoized(this::getQueuingObserved))); 36 | } 37 | 38 | @VisibleForTesting 39 | QueuingObserved getQueuingObserved() 40 | throws InvalidProfileException, MissingInputException, NullDatumException { 41 | BazelProfile profile = getDataManager().getDatum(BazelProfile.class); 42 | return new QueuingObserved( 43 | profile 44 | .getThreads() 45 | .flatMap((thread) -> thread.getCompleteEvents().stream()) 46 | .anyMatch( 47 | (event) -> 48 | BazelProfileConstants.CAT_REMOTE_EXECUTION_QUEUING_TIME.equals( 49 | event.category))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/RemoteCachingUsed.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | 19 | /** Whether remote caching was used for the invocation */ 20 | public class RemoteCachingUsed implements Datum { 21 | private final boolean remoteCachingUsed; 22 | 23 | public RemoteCachingUsed(boolean remoteCachingUsed) { 24 | this.remoteCachingUsed = remoteCachingUsed; 25 | } 26 | 27 | public boolean isRemoteCachingUsed() { 28 | return remoteCachingUsed; 29 | } 30 | 31 | @Override 32 | public boolean isEmpty() { 33 | return false; 34 | } 35 | 36 | @Override 37 | public String getEmptyReason() { 38 | return null; 39 | } 40 | 41 | @Override 42 | public String getDescription() { 43 | return "Whether the Bazel Profile includes events indicating that remote caching was used."; 44 | } 45 | 46 | @Override 47 | public String getSummary() { 48 | return String.valueOf(remoteCachingUsed); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/RemoteCachingUsedDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 19 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 20 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import com.google.common.annotations.VisibleForTesting; 26 | import java.util.List; 27 | 28 | /** 29 | * A {@link DataProvider} that extracts from the Bazel profile whether it is likely that remote 30 | * caching was enabled when running the invocation. 31 | */ 32 | public class RemoteCachingUsedDataProvider extends DataProvider { 33 | 34 | @Override 35 | public List> getSuppliers() { 36 | return List.of( 37 | DatumSupplierSpecification.of( 38 | RemoteCachingUsed.class, DatumSupplier.memoized(this::getRemoteCachingUsed))); 39 | } 40 | 41 | @VisibleForTesting 42 | RemoteCachingUsed getRemoteCachingUsed() 43 | throws InvalidProfileException, MissingInputException, NullDatumException { 44 | RemoteExecutionUsed remoteExecutionUsed = getDataManager().getDatum(RemoteExecutionUsed.class); 45 | if (remoteExecutionUsed.isRemoteExecutionUsed()) { 46 | // While in principle it is possible to use remote execution without remote caching, this is 47 | // a highly unusual setup. Return `true` here to avoid false negatives. 48 | // For example, if RE is enabled and only targets with tag `no-remote-cache` or `no-cache` 49 | // were built, the code farther down may not correctly detect that RC was used. 50 | return new RemoteCachingUsed(true); 51 | } 52 | BazelProfile profile = getDataManager().getDatum(BazelProfile.class); 53 | return new RemoteCachingUsed( 54 | profile 55 | .getThreads() 56 | .flatMap((thread) -> thread.getCompleteEvents().stream()) 57 | .anyMatch( 58 | (event) -> 59 | BazelProfileConstants.CAT_REMOTE_ACTION_CACHE_CHECK.equals(event.category))); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/RemoteExecutionUsed.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | 19 | /** Whether evidence was found of remote execution being used */ 20 | public class RemoteExecutionUsed implements Datum { 21 | private final boolean remoteExecutionUsed; 22 | 23 | public RemoteExecutionUsed(boolean remoteExecutionUsed) { 24 | this.remoteExecutionUsed = remoteExecutionUsed; 25 | } 26 | 27 | public boolean isRemoteExecutionUsed() { 28 | return remoteExecutionUsed; 29 | } 30 | 31 | @Override 32 | public boolean isEmpty() { 33 | return false; 34 | } 35 | 36 | @Override 37 | public String getEmptyReason() { 38 | return null; 39 | } 40 | 41 | @Override 42 | public String getDescription() { 43 | return "Whether the Bazel Profile includes events indicating that remote execution was used."; 44 | } 45 | 46 | @Override 47 | public String getSummary() { 48 | return String.valueOf(remoteExecutionUsed); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/RemoteExecutionUsedDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 19 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 20 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import com.google.common.annotations.VisibleForTesting; 26 | import java.util.List; 27 | 28 | public class RemoteExecutionUsedDataProvider extends DataProvider { 29 | 30 | @Override 31 | public List> getSuppliers() { 32 | return List.of( 33 | DatumSupplierSpecification.of( 34 | RemoteExecutionUsed.class, DatumSupplier.memoized(this::getRemoteExecutionUsed))); 35 | } 36 | 37 | /** 38 | * Extracts from the Bazel profile whether it is likely that remote execution was enabled when 39 | * running the invocation. 40 | */ 41 | @VisibleForTesting 42 | RemoteExecutionUsed getRemoteExecutionUsed() 43 | throws InvalidProfileException, MissingInputException, NullDatumException { 44 | BazelProfile profile = getDataManager().getDatum(BazelProfile.class); 45 | return new RemoteExecutionUsed( 46 | profile 47 | .getThreads() 48 | .flatMap((thread) -> thread.getCompleteEvents().stream()) 49 | .anyMatch( 50 | (event) -> 51 | BazelProfileConstants.CAT_REMOTE_EXECUTION_SETUP.equals(event.category) 52 | || BazelProfileConstants.CAT_REMOTE_EXECUTION_QUEUING_TIME.equals( 53 | event.category) 54 | || BazelProfileConstants.CAT_REMOTE_ACTION_EXECUTION.equals(event.category) 55 | && BazelProfileConstants.COMPLETE_EXECUTE_REMOTELY.equals(event.name))); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/RemoteLatency.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import com.google.common.base.Strings; 21 | import java.time.Duration; 22 | import java.util.Optional; 23 | import javax.annotation.Nullable; 24 | 25 | /** Estimated upper bound of latency for remote operations */ 26 | public class RemoteLatency implements Datum { 27 | private final Optional remoteLatency; 28 | @Nullable private final String emptyReason; 29 | 30 | public RemoteLatency(String emptyReason) { 31 | Preconditions.checkArgument(!Strings.isNullOrEmpty(emptyReason)); 32 | this.remoteLatency = Optional.empty(); 33 | this.emptyReason = emptyReason; 34 | } 35 | 36 | public RemoteLatency(Duration remoteLatency) { 37 | Preconditions.checkNotNull(remoteLatency); 38 | this.remoteLatency = Optional.of(remoteLatency); 39 | this.emptyReason = null; 40 | } 41 | 42 | public Optional getRemoteLatency() { 43 | return remoteLatency; 44 | } 45 | 46 | @Override 47 | public boolean isEmpty() { 48 | return remoteLatency.isEmpty(); 49 | } 50 | 51 | @Override 52 | public String getEmptyReason() { 53 | return emptyReason; 54 | } 55 | 56 | @Override 57 | public String getDescription() { 58 | return "Upper bound estimate of latency to remote execution/caching system"; 59 | } 60 | 61 | @Override 62 | public String getSummary() { 63 | return isEmpty() ? null : DurationUtil.formatDuration(remoteLatency.get()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/TotalQueuingDuration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.Datum; 18 | import com.engflow.bazel.invocation.analyzer.time.DurationUtil; 19 | import com.google.common.base.Preconditions; 20 | import java.time.Duration; 21 | 22 | /** Total time actions spent queued */ 23 | public class TotalQueuingDuration implements Datum { 24 | private final Duration totalQueuingDuration; 25 | 26 | public TotalQueuingDuration(Duration totalQueuingDuration) { 27 | Preconditions.checkNotNull(totalQueuingDuration); 28 | this.totalQueuingDuration = totalQueuingDuration; 29 | } 30 | 31 | public Duration getTotalQueuingDuration() { 32 | return totalQueuingDuration; 33 | } 34 | 35 | @Override 36 | public boolean isEmpty() { 37 | return false; 38 | } 39 | 40 | @Override 41 | public String getEmptyReason() { 42 | return null; 43 | } 44 | 45 | @Override 46 | public String getDescription() { 47 | return "The total time that was spent on queuing as extracted from the Bazel profile."; 48 | } 49 | 50 | @Override 51 | public String getSummary() { 52 | return DurationUtil.formatDuration(totalQueuingDuration); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/TotalQueuingDurationDataProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 19 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 20 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplier; 21 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import com.google.common.annotations.VisibleForTesting; 26 | import java.time.Duration; 27 | import java.util.List; 28 | 29 | /** 30 | * A {@link DataProvider} that supplies the duration spent queuing for remote execution. For this, 31 | * the sum over all queuing across all actions is computed. No distinction is made on whether the 32 | * queuing was happening in parallel. 33 | */ 34 | public class TotalQueuingDurationDataProvider extends DataProvider { 35 | 36 | @Override 37 | public List> getSuppliers() { 38 | return List.of( 39 | DatumSupplierSpecification.of( 40 | TotalQueuingDuration.class, DatumSupplier.memoized(this::getTotalQueuingDuration))); 41 | } 42 | 43 | @VisibleForTesting 44 | TotalQueuingDuration getTotalQueuingDuration() 45 | throws InvalidProfileException, MissingInputException, NullDatumException { 46 | BazelProfile bazelProfile = getDataManager().getDatum(BazelProfile.class); 47 | Duration duration = 48 | bazelProfile 49 | .getThreads() 50 | .flatMap((thread) -> thread.getCompleteEvents().stream()) 51 | .filter( 52 | (event) -> 53 | BazelProfileConstants.CAT_REMOTE_EXECUTION_QUEUING_TIME.equals(event.category)) 54 | .map((event) -> event.duration) 55 | .reduce(Duration.ZERO, Duration::plus); 56 | return new TotalQueuingDuration(duration); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/suggestionproviders/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "suggestionproviders", 5 | srcs = glob(["*.java"]), 6 | visibility = ["//visibility:public"], 7 | deps = [ 8 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:util", 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:types", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution:types", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 14 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 15 | "//proto:bazel_invocation_analyzer_java_proto", 16 | "//third_party/guava", 17 | "//third_party/jsr305", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/suggestionproviders/SuggestionProviderBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.suggestionproviders; 16 | 17 | import com.engflow.bazel.invocation.analyzer.core.SuggestionProvider; 18 | 19 | public abstract class SuggestionProviderBase implements SuggestionProvider { 20 | protected SuggestionProviderUtil.SuggestionId createSuggestionId(String id) { 21 | return new SuggestionProviderUtil.SuggestionId( 22 | String.format("%s-%s", this.getClass().getName(), id)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/time/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | java_library( 6 | name = "time", 7 | srcs = glob( 8 | ["*.java"], 9 | ), 10 | deps = [ 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 12 | "//third_party/guava", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/time/DurationUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | import java.time.Duration; 18 | 19 | public class DurationUtil { 20 | /** 21 | * Returns the duration in a formatted form. 22 | * 23 | *

    For duration >= 1 hour, return 1h 2m 3s.
    24 | * For 1 hour > duration >= 1 minute, return 1m 2s.
    25 | * For 1 minute > duration >= 10 seconds, return 1s.
    26 | * Else return the duration in milliseconds as 1ms. 27 | * 28 | * @param duration The duration to format 29 | * @return a human-readable formatting of the duration 30 | */ 31 | public static String formatDuration(Duration duration) { 32 | if (duration.compareTo(Duration.ofHours(1)) >= 0) { 33 | return String.format( 34 | "%dh %dm %ds", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart()); 35 | } else if (duration.compareTo(Duration.ofMinutes(1)) >= 0) { 36 | return String.format("%dm %ds", duration.toMinutes(), duration.toSecondsPart()); 37 | } else if (duration.compareTo(Duration.ofSeconds(10)) >= 0) { 38 | return String.format("%ds", duration.toSeconds()); 39 | } else { 40 | return String.format("%dms", duration.toMillis()); 41 | } 42 | } 43 | 44 | /** 45 | * Returns the percentage of one duration relative to another duration. 46 | * 47 | * @param partial The duration to return the percentage of related to base 48 | * @param base The duration to base the percentage on 49 | * @return the percentage of partial relative to base 50 | */ 51 | public static double getPercentageOf(Duration partial, Duration base) { 52 | if (base.isZero()) { 53 | throw new IllegalArgumentException("Duration base must not be zero."); 54 | } 55 | return 100.0 * partial.toNanos() / base.toNanos(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/time/Range.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | public class Range { 18 | 19 | public static Range between(Timestamp start, Timestamp end) { 20 | return new Range(start, end); 21 | } 22 | 23 | private final Timestamp start; 24 | private final Timestamp end; 25 | 26 | private Range(Timestamp start, Timestamp end) { 27 | this.start = start; 28 | this.end = end; 29 | } 30 | 31 | public boolean contains(Timestamp... values) { 32 | for (Timestamp value : values) { 33 | if (start.plus(Timestamp.ACCEPTABLE_DIVERGENCE.negated()).compareTo(value) > 0 34 | || end.plus(Timestamp.ACCEPTABLE_DIVERGENCE).compareTo(value) < 0) { 35 | return false; 36 | } 37 | } 38 | return true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/time/TimeUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | import java.time.Duration; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | public class TimeUtil { 21 | /** 22 | * Given two {@link Timestamp}s, return the {@link Duration} that passed between them. This method 23 | * is commutative, i.e. the timestamps need not be passed in a specific order. 24 | * 25 | * @param t1 the first timestamp 26 | * @param t2 the second timestamp 27 | * @return the duration that passed between the two specified timestamps 28 | */ 29 | public static Duration getDurationBetween(Timestamp t1, Timestamp t2) { 30 | return getDurationForMicros(Math.abs(t1.getMicros() - t2.getMicros())); 31 | } 32 | 33 | /** 34 | * Given a value in microseconds, return a {@link Duration} of that length. 35 | * 36 | * @param durationInMicros the number of microseconds in the duration to return 37 | * @return the duration that represents the specified microseconds 38 | */ 39 | public static Duration getDurationForMicros(long durationInMicros) { 40 | // This should be equivalent to Duration.of(durationInMicros, ChronoUnit.MICROS). 41 | // The implementation below clarifies that combining getDurationForMicros and getMicros 42 | // leads to an identity function. 43 | return Duration.ofNanos(TimeUnit.MICROSECONDS.toNanos(durationInMicros)); 44 | } 45 | 46 | /** 47 | * Given a {@link Duration}, return its value in microseconds. 48 | * 49 | * @param duration the Duration to convert 50 | * @return the number of microseconds that represent the specified duration 51 | */ 52 | public static long getMicros(Duration duration) { 53 | return TimeUnit.NANOSECONDS.toMicros(duration.toNanos()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "traceeventformat", 5 | srcs = glob(["*.java"]), 6 | visibility = ["//visibility:public"], 7 | deps = [ 8 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 9 | "//third_party/gson", 10 | "//third_party/guava", 11 | "//third_party/jsr305", 12 | ], 13 | ) 14 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat/PartialCompleteEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.traceeventformat; 16 | 17 | import com.engflow.bazel.invocation.analyzer.time.TimeUtil; 18 | import com.engflow.bazel.invocation.analyzer.time.Timestamp; 19 | import com.google.common.base.Preconditions; 20 | import java.time.Duration; 21 | 22 | /** A {@link CompleteEvent}, which is potentially cropped in the beginning and/or end. */ 23 | public class PartialCompleteEvent { 24 | public final CompleteEvent completeEvent; 25 | public final Timestamp croppedStart; 26 | public final Duration croppedDuration; 27 | public final Timestamp croppedEnd; 28 | 29 | public PartialCompleteEvent( 30 | CompleteEvent completeEvent, Timestamp croppedStart, Timestamp croppedEnd) { 31 | // Ensure that cropping does not extend the interval of the contained CompleteEvent. 32 | Preconditions.checkArgument(completeEvent.start.compareTo(croppedStart) <= 0); 33 | Preconditions.checkArgument(completeEvent.end.compareTo(croppedEnd) >= 0); 34 | this.completeEvent = completeEvent; 35 | this.croppedStart = croppedStart; 36 | this.croppedEnd = croppedEnd; 37 | this.croppedDuration = TimeUtil.getDurationBetween(croppedStart, croppedEnd); 38 | } 39 | 40 | /** 41 | * Returns whether the event is cropped. The event is cropped, if the timing information of this 42 | * event and the contained {@llink CompleteEvent} do not match. 43 | * 44 | * @return Whether the event is cropped. 45 | */ 46 | public boolean isCropped() { 47 | return completeEvent.start.compareTo(croppedStart) != 0 48 | || completeEvent.end.compareTo(croppedEnd) != 0; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat/TraceEventFormatConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.traceeventformat; 16 | 17 | /** 18 | * Declares constants found in the Trace Event Format "specification" found at 19 | * https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.yr4qxyxotyw 20 | * 21 | *

    This list is not comprehensive and only lists the constants necessary to parse Trace Event 22 | * Format profiles produced by the Bazel build system. 23 | */ 24 | public class TraceEventFormatConstants { 25 | public static final String SECTION_OTHER_DATA = "otherData"; 26 | public static final String SECTION_TRACE_EVENTS = "traceEvents"; 27 | 28 | public static final String EVENT_ARGUMENTS = "args"; 29 | public static final String EVENT_CATEGORY = "cat"; 30 | public static final String EVENT_DURATION = "dur"; 31 | public static final String EVENT_NAME = "name"; 32 | public static final String EVENT_PHASE = "ph"; 33 | public static final String EVENT_PROCESS_ID = "pid"; 34 | public static final String EVENT_THREAD_ID = "tid"; 35 | public static final String EVENT_TIMESTAMP = "ts"; 36 | 37 | public static final String PHASE_COMPLETE = "X"; 38 | public static final String PHASE_COUNTER = "C"; 39 | public static final String PHASE_INSTANT = "i"; 40 | public static final String PHASE_METADATA = "M"; 41 | 42 | public static final String METADATA_THREAD_NAME = "thread_name"; 43 | public static final String METADATA_THREAD_SORT_INDEX = "thread_sort_index"; 44 | } 45 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "test_base", 5 | testonly = True, 6 | srcs = glob(["*.java"]), 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 14 | "//third_party/gson", 15 | "//third_party/guava", 16 | "//third_party/jsr305", 17 | "//third_party/junit", 18 | "//third_party/mockito", 19 | "@rules_java//java/runfiles", 20 | ], 21 | ) 22 | 23 | filegroup( 24 | name = "profiles", 25 | srcs = glob([ 26 | "profiles/**", 27 | ]), 28 | visibility = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:__subpackages__"], 29 | ) 30 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/UnitTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer; 16 | 17 | import static org.mockito.Mockito.mock; 18 | import static org.mockito.Mockito.when; 19 | 20 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 21 | import com.engflow.bazel.invocation.analyzer.core.DataManager; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import org.junit.Before; 26 | 27 | public abstract class UnitTestBase extends ProfileTestBase { 28 | /** DataManager to coordinate the transfer of data between Providers */ 29 | protected DataManager dataManager; 30 | 31 | @Before 32 | public void setupTestBase() { 33 | dataManager = mock(DataManager.class); 34 | } 35 | 36 | @Override 37 | protected void registerBazelProfile(BazelProfile bazelProfile) 38 | throws InvalidProfileException, MissingInputException, NullDatumException { 39 | when(dataManager.getDatum(BazelProfile.class)).thenReturn(bazelProfile); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/bazelprofile/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "bazelprofile", 5 | srcs = glob(["**/*.java"]), 6 | data = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:profiles"], 7 | test_class = "com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileTestSuite", 8 | deps = [ 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:util", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:types", 14 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 15 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 16 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 17 | "//third_party/guava", 18 | "//third_party/junit", 19 | "//third_party/truth", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/bazelprofile/BazelProfileTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.bazelprofile; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | BazelProfileTest.class, 23 | BazelEventsUtilTest.class, 24 | }) 25 | public class BazelProfileTestSuite {} 26 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/core/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library", "java_test") 2 | 3 | TYPES = [ 4 | "TestDatum.java", 5 | ] 6 | 7 | java_test( 8 | name = "core", 9 | srcs = glob( 10 | ["**/*.java"], 11 | exclude = TYPES, 12 | ), 13 | data = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:profiles"], 14 | test_class = "com.engflow.bazel.invocation.analyzer.core.CoreTestSuite", 15 | deps = [ 16 | ":types", 17 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 18 | "//third_party/guava", 19 | "//third_party/jsr305", 20 | "//third_party/junit", 21 | "//third_party/truth", 22 | ], 23 | ) 24 | 25 | java_library( 26 | name = "types", 27 | testonly = True, 28 | srcs = TYPES, 29 | visibility = ["//visibility:public"], 30 | deps = [ 31 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/core/CoreTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | DataManagerTest.class, 23 | DatumSupplierTest.class, 24 | }) 25 | public class CoreTestSuite {} 26 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/core/DatumSupplierTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.core; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | 19 | import com.engflow.bazel.invocation.analyzer.core.TestDatum.IntegerDatum; 20 | import java.util.concurrent.CountDownLatch; 21 | import java.util.concurrent.ExecutorService; 22 | import java.util.concurrent.Executors; 23 | import java.util.concurrent.atomic.AtomicInteger; 24 | import org.junit.Test; 25 | 26 | public class DatumSupplierTest { 27 | 28 | @Test 29 | public void shouldMemoize() throws Exception { 30 | AtomicInteger callCount = new AtomicInteger(); 31 | 32 | DatumSupplier supplier = 33 | DatumSupplier.memoized(() -> new IntegerDatum(callCount.incrementAndGet())); 34 | 35 | assertThat(callCount.get()).isEqualTo(0); 36 | assertThat(supplier.supply().getMyInt()).isEqualTo(1); 37 | assertThat(callCount.get()).isEqualTo(1); 38 | assertThat(supplier.supply().getMyInt()).isEqualTo(1); 39 | assertThat(callCount.get()).isEqualTo(1); 40 | } 41 | 42 | @Test(timeout = 1_000) 43 | public void memoizationIsThreadSafe() throws Exception { 44 | AtomicInteger callCount = new AtomicInteger(); 45 | AtomicInteger retrievalCount = new AtomicInteger(); 46 | 47 | DatumSupplier supplier = 48 | DatumSupplier.memoized(() -> new IntegerDatum(callCount.incrementAndGet())); 49 | 50 | ExecutorService executorService = Executors.newFixedThreadPool(100); 51 | CountDownLatch startLatch = new CountDownLatch(1); 52 | CountDownLatch endLatch = new CountDownLatch(100); 53 | for (int i = 0; i < 100; ++i) { 54 | var unused = 55 | executorService.submit( 56 | () -> { 57 | try { 58 | startLatch.await(); 59 | supplier.supply(); 60 | retrievalCount.getAndIncrement(); 61 | endLatch.countDown(); 62 | } catch (Throwable e) { 63 | throw new IllegalStateException(e); 64 | } 65 | }); 66 | } 67 | startLatch.countDown(); 68 | endLatch.await(); 69 | executorService.shutdown(); 70 | 71 | assertThat(supplier.supply().getMyInt()).isEqualTo(1); 72 | assertThat(callCount.get()).isEqualTo(1); 73 | assertThat(retrievalCount.get()).isEqualTo(100); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library", "java_test") 2 | 3 | java_test( 4 | name = "dataproviders", 5 | srcs = glob( 6 | ["**/*.java"], 7 | exclude = ["DataProviderUnitTestBase.java"], 8 | ), 9 | data = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:profiles"], 10 | test_class = "com.engflow.bazel.invocation.analyzer.dataproviders.DataProvidersTestSuite", 11 | deps = [ 12 | ":data_provider_test_base", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 14 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 15 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 16 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders", 17 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:types", 18 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 19 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 20 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 21 | "//third_party/guava", 22 | "//third_party/junit", 23 | "//third_party/mockito", 24 | "//third_party/truth", 25 | ], 26 | ) 27 | 28 | java_library( 29 | name = "data_provider_test_base", 30 | testonly = True, 31 | srcs = ["DataProviderUnitTestBase.java"], 32 | visibility = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:__subpackages__"], 33 | deps = [ 34 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 35 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 36 | "//third_party/junit", 37 | "//third_party/mockito", 38 | ], 39 | ) 40 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/BazelProfilePhaseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.junit.Assert.assertThrows; 19 | 20 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfilePhase; 21 | import org.junit.Test; 22 | 23 | public class BazelProfilePhaseTest { 24 | @Test 25 | public void getPreviousWorks() { 26 | assertThat(BazelProfilePhase.FINISH.getPrevious()).isEqualTo(BazelProfilePhase.EXECUTE); 27 | assertThat(BazelProfilePhase.EXECUTE.getPrevious()).isEqualTo(BazelProfilePhase.PREPARE); 28 | assertThat(BazelProfilePhase.PREPARE.getPrevious()).isEqualTo(BazelProfilePhase.LICENSE); 29 | assertThat(BazelProfilePhase.LICENSE.getPrevious()) 30 | .isEqualTo(BazelProfilePhase.ANALYZE_AND_EXECUTE); 31 | assertThat(BazelProfilePhase.ANALYZE_AND_EXECUTE.getPrevious()) 32 | .isEqualTo(BazelProfilePhase.ANALYZE); 33 | assertThat(BazelProfilePhase.ANALYZE.getPrevious()) 34 | .isEqualTo(BazelProfilePhase.TARGET_PATTERN_EVAL); 35 | assertThat(BazelProfilePhase.TARGET_PATTERN_EVAL.getPrevious()) 36 | .isEqualTo(BazelProfilePhase.INIT); 37 | assertThat(BazelProfilePhase.INIT.getPrevious()).isEqualTo(BazelProfilePhase.LAUNCH); 38 | assertThrows(UnsupportedOperationException.class, () -> BazelProfilePhase.LAUNCH.getPrevious()); 39 | } 40 | 41 | @Test 42 | public void getNextWorks() { 43 | assertThat(BazelProfilePhase.LAUNCH.getNext()).isEqualTo(BazelProfilePhase.INIT); 44 | assertThat(BazelProfilePhase.INIT.getNext()).isEqualTo(BazelProfilePhase.TARGET_PATTERN_EVAL); 45 | assertThat(BazelProfilePhase.TARGET_PATTERN_EVAL.getNext()) 46 | .isEqualTo(BazelProfilePhase.ANALYZE); 47 | assertThat(BazelProfilePhase.ANALYZE.getNext()) 48 | .isEqualTo(BazelProfilePhase.ANALYZE_AND_EXECUTE); 49 | assertThat(BazelProfilePhase.ANALYZE_AND_EXECUTE.getNext()) 50 | .isEqualTo(BazelProfilePhase.LICENSE); 51 | assertThat(BazelProfilePhase.LICENSE.getNext()).isEqualTo(BazelProfilePhase.PREPARE); 52 | assertThat(BazelProfilePhase.PREPARE.getNext()).isEqualTo(BazelProfilePhase.EXECUTE); 53 | assertThat(BazelProfilePhase.EXECUTE.getNext()).isEqualTo(BazelProfilePhase.FINISH); 54 | assertThrows(UnsupportedOperationException.class, () -> BazelProfilePhase.FINISH.getNext()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/BazelVersionDataProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.mockito.Mockito.mock; 19 | import static org.mockito.Mockito.when; 20 | 21 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 22 | import com.engflow.bazel.invocation.analyzer.core.InvalidProfileException; 23 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 24 | import com.engflow.bazel.invocation.analyzer.core.NullDatumException; 25 | import org.junit.Before; 26 | import org.junit.Test; 27 | 28 | public class BazelVersionDataProviderTest extends DataProviderUnitTestBase { 29 | private BazelVersionDataProvider provider; 30 | 31 | @Before 32 | public void setupTest() throws Exception { 33 | provider = new BazelVersionDataProvider(); 34 | provider.register(dataManager); 35 | super.dataProvider = provider; 36 | } 37 | 38 | @Test 39 | public void shouldReturnBazelVersionFromBazelProfile() 40 | throws InvalidProfileException, MissingInputException, NullDatumException { 41 | BazelVersion expected = BazelVersion.parse("release 1.2.3"); 42 | 43 | BazelProfile mockProfile = mock(BazelProfile.class); 44 | when(dataManager.getDatum(BazelProfile.class)).thenReturn(mockProfile); 45 | when(mockProfile.getBazelVersion()).thenReturn(expected); 46 | 47 | assertThat(provider.getBazelVersion()).isEqualTo(expected); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/BazelVersionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | 19 | import org.junit.Test; 20 | 21 | public class BazelVersionTest { 22 | @Test 23 | public void parseReturnsEmpty() { 24 | assertThat(BazelVersion.parse("").isEmpty()).isTrue(); 25 | assertThat(BazelVersion.parse("1.2.3").isEmpty()).isTrue(); 26 | assertThat(BazelVersion.parse("1.2.3-foo").isEmpty()).isTrue(); 27 | assertThat(BazelVersion.parse("release 1").isEmpty()).isTrue(); 28 | assertThat(BazelVersion.parse("release 1.2").isEmpty()).isTrue(); 29 | assertThat(BazelVersion.parse("release 1.2.3foo").isEmpty()).isTrue(); 30 | } 31 | 32 | @Test 33 | public void parseReturnsNonempty() { 34 | assertThat(BazelVersion.parse("release 1.23.4")).isEqualTo(new BazelVersion(1, 23, 4, "")); 35 | assertThat(BazelVersion.parse("release 12.3.45-foo")) 36 | .isEqualTo(new BazelVersion(12, 3, 45, "-foo")); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/DataProviderUnitTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static org.junit.Assert.assertNotNull; 18 | import static org.junit.Assert.assertThrows; 19 | import static org.mockito.ArgumentMatchers.any; 20 | import static org.mockito.Mockito.when; 21 | 22 | import com.engflow.bazel.invocation.analyzer.UnitTestBase; 23 | import com.engflow.bazel.invocation.analyzer.core.DataProvider; 24 | import com.engflow.bazel.invocation.analyzer.core.DatumSupplierSpecification; 25 | import com.engflow.bazel.invocation.analyzer.core.MissingInputException; 26 | import org.junit.Assert; 27 | import org.junit.Test; 28 | 29 | public abstract class DataProviderUnitTestBase extends UnitTestBase { 30 | protected DataProvider dataProvider; 31 | 32 | @Test 33 | public void shouldThrowMissingInputExceptionOnMissingInputs() throws Exception { 34 | assertNotNull( 35 | "dataProvider must be set by the subclass. Set super.dataProvider to an instance of the" 36 | + " DataProvider in a @Before method.", 37 | dataProvider); 38 | 39 | // Save the class type requested for later comparison. Must be wrapped in a final object to use 40 | // in a lambda. 41 | final var savedParameter = 42 | new Object() { 43 | Class classRequested; 44 | }; 45 | 46 | // Throw MissingInputException when any Datum is requested 47 | when(dataManager.getDatum(any())) 48 | .thenAnswer( 49 | x -> { 50 | savedParameter.classRequested = x.getArgument(0); 51 | throw new MissingInputException(savedParameter.classRequested); 52 | }); 53 | 54 | // Check all DatumSuppliers on the DataProvider 55 | for (DatumSupplierSpecification datumProvider : dataProvider.getSuppliers()) { 56 | var ex = 57 | assertThrows( 58 | MissingInputException.class, () -> datumProvider.getDatumSupplier().supply()); 59 | Assert.assertEquals(ex.getMissingInputClass(), savedParameter.classRequested); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/DataProvidersTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | ActionStatsDataProviderTest.class, 23 | BazelPhasesDataProviderTest.class, 24 | BazelPhaseDescriptionsTest.class, 25 | BazelVersionTest.class, 26 | BazelVersionDataProviderTest.class, 27 | BazelProfilePhaseTest.class, 28 | CachingAndExecutionMetricsDataProviderTest.class, 29 | CriticalPathDurationDataProviderTest.class, 30 | EstimatedCoresDataProviderTest.class, 31 | FlagValueDataProviderTest.class, 32 | GarbageCollectionStatsDataProviderTest.class, 33 | LocalActionsDataProviderTest.class, 34 | LocalActionsTest.class, 35 | MergedEventsPresentDataProviderTest.class, 36 | RemoteCacheMetricsDataProviderTest.class, 37 | SkymeldUsedDataProviderTest.class 38 | }) 39 | public class DataProvidersTestSuite {} 40 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/FlagValueDataProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.mainThread; 18 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.metaData; 19 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.trace; 20 | import static com.google.common.truth.Truth.assertThat; 21 | 22 | import com.engflow.bazel.invocation.analyzer.EventThreadBuilder; 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | 26 | public class FlagValueDataProviderTest extends DataProviderUnitTestBase { 27 | private FlagValueDataProvider provider; 28 | 29 | @Before 30 | public void setupTest() throws Exception { 31 | provider = new FlagValueDataProvider(); 32 | provider.register(dataManager); 33 | super.dataProvider = provider; 34 | } 35 | 36 | @Test 37 | public void flagValueExperimentalProfileIncludeTargetLabelIsFalseWhenThereAreNoActions() 38 | throws Exception { 39 | useProfile(metaData(), trace(mainThread())); 40 | 41 | assertThat(provider.getExperimentalProfileIncludeTargetLabel()) 42 | .isEqualTo(new FlagValueExperimentalProfileIncludeTargetLabel(false)); 43 | } 44 | 45 | @Test 46 | public void 47 | flagValueExperimentalProfileIncludeTargetLabelIsFalseWhenActionProcessingDoesNotHaveALabel() 48 | throws Exception { 49 | var thread = new EventThreadBuilder(1, 1); 50 | thread.actionProcessingAction("foo", null, null, 0, 1); 51 | 52 | useProfile(metaData(), trace(mainThread(), thread.asEvent())); 53 | 54 | assertThat(provider.getExperimentalProfileIncludeTargetLabel()) 55 | .isEqualTo(new FlagValueExperimentalProfileIncludeTargetLabel(false)); 56 | } 57 | 58 | @Test 59 | public void 60 | flagValueExperimentalProfileIncludeTargetLabelIsTrueWhenActionProcessingHasAnEmptyLabel() 61 | throws Exception { 62 | var thread = new EventThreadBuilder(1, 1); 63 | thread.actionProcessingAction("foo", "", null, 0, 1); 64 | 65 | useProfile(metaData(), trace(mainThread(), thread.asEvent())); 66 | 67 | assertThat(provider.getExperimentalProfileIncludeTargetLabel()) 68 | .isEqualTo(new FlagValueExperimentalProfileIncludeTargetLabel(true)); 69 | } 70 | 71 | @Test 72 | public void 73 | flagValueExperimentalProfileIncludeTargetLabelIsTrueWhenActionProcessingHasANonemptyLabel() 74 | throws Exception { 75 | var thread = new EventThreadBuilder(1, 1); 76 | thread.actionProcessingAction("foo", "my target", null, 0, 1); 77 | 78 | useProfile(metaData(), trace(mainThread(), thread.asEvent())); 79 | 80 | assertThat(provider.getExperimentalProfileIncludeTargetLabel()) 81 | .isEqualTo(new FlagValueExperimentalProfileIncludeTargetLabel(true)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/MergedEventsPresentDataProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders; 16 | 17 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.complete; 18 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.mainThread; 19 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.metaData; 20 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.thread; 21 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.trace; 22 | import static com.google.common.truth.Truth.assertThat; 23 | 24 | import com.engflow.bazel.invocation.analyzer.time.Timestamp; 25 | import java.time.Duration; 26 | import org.junit.Before; 27 | import org.junit.Test; 28 | 29 | public class MergedEventsPresentDataProviderTest extends DataProviderUnitTestBase { 30 | private MergedEventsPresentDataProvider provider; 31 | 32 | @Before 33 | public void setupTest() throws Exception { 34 | provider = new MergedEventsPresentDataProvider(); 35 | provider.register(dataManager); 36 | super.dataProvider = provider; 37 | } 38 | 39 | @Test 40 | public void shouldReturnMergedEventsPresent() throws Exception { 41 | useProfile( 42 | metaData(), 43 | trace( 44 | mainThread(), 45 | thread( 46 | 20, 47 | 0, 48 | "skyframe-evaluator 0", 49 | complete( 50 | "merged 3 events", 51 | "Unknown event", 52 | Timestamp.ofMicros(123), 53 | Duration.ofMillis(1))))); 54 | 55 | MergedEventsPresent mergedEventsPresent = provider.getMergedEventsPresent(); 56 | assertThat(mergedEventsPresent.hasMergedEvents()).isTrue(); 57 | } 58 | 59 | @Test 60 | public void shouldReturnMergedEventsNotPresent() throws Exception { 61 | useProfile( 62 | metaData(), 63 | trace( 64 | mainThread(), 65 | thread( 66 | 20, 67 | 0, 68 | "skyframe-evaluator 0", 69 | complete( 70 | "other rule merged 3 events", 71 | "Unknown event", 72 | Timestamp.ofMicros(123), 73 | Duration.ofMillis(1))))); 74 | 75 | MergedEventsPresent mergedEventsPresent = provider.getMergedEventsPresent(); 76 | assertThat(mergedEventsPresent.hasMergedEvents()).isFalse(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "remoteexecution", 5 | srcs = glob(["**/*.java"]), 6 | data = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:profiles"], 7 | test_class = "com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.RemoteExecutionDataProviderSuite", 8 | deps = [ 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution:types", 14 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 15 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 16 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders:data_provider_test_base", 17 | "//third_party/junit", 18 | "//third_party/mockito", 19 | "//third_party/truth", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/QueuingObservedDataProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.complete; 18 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.mainThread; 19 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.metaData; 20 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.thread; 21 | import static com.engflow.bazel.invocation.analyzer.WriteBazelProfile.trace; 22 | import static com.google.common.truth.Truth.assertThat; 23 | 24 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfileConstants; 25 | import com.engflow.bazel.invocation.analyzer.core.DuplicateProviderException; 26 | import com.engflow.bazel.invocation.analyzer.dataproviders.DataProviderUnitTestBase; 27 | import com.engflow.bazel.invocation.analyzer.time.Timestamp; 28 | import java.time.Duration; 29 | import org.junit.Before; 30 | import org.junit.Test; 31 | 32 | public class QueuingObservedDataProviderTest extends DataProviderUnitTestBase { 33 | private QueuingObservedDataProvider provider; 34 | 35 | @Before 36 | public void setupTest() throws DuplicateProviderException { 37 | provider = new QueuingObservedDataProvider(); 38 | provider.register(dataManager); 39 | super.dataProvider = provider; 40 | } 41 | 42 | @Test 43 | public void shouldReturnQueuingObserved() throws Exception { 44 | useProfile( 45 | metaData(), 46 | trace( 47 | mainThread(), 48 | thread( 49 | 0, 50 | 0, 51 | "foo", 52 | complete( 53 | "bar", 54 | BazelProfileConstants.CAT_REMOTE_EXECUTION_QUEUING_TIME, 55 | Timestamp.ofMicros(123), 56 | Duration.ZERO)))); 57 | 58 | assertThat(provider.getQueuingObserved().isQueuingObserved()).isTrue(); 59 | } 60 | 61 | @Test 62 | public void shouldReturnQueuingNotObserved() throws Exception { 63 | useProfile(metaData(), trace(mainThread())); 64 | 65 | assertThat(provider.getQueuingObserved().isQueuingObserved()).isFalse(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution/RemoteExecutionDataProviderSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | CriticalPathQueuingDurationDataProviderTest.class, 23 | QueuingObservedDataProviderTest.class, 24 | RemoteCachingUsedDataProviderTest.class, 25 | RemoteExecutionUsedDataProviderTest.class, 26 | RemoteLatencyDataProviderTest.class, 27 | TotalQueuingDurationDataProviderTest.class, 28 | }) 29 | public class RemoteExecutionDataProviderSuite {} 30 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/integrationtests/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "integrationtests", 5 | srcs = glob(["**/*.java"]), 6 | data = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:profiles"], 7 | test_class = "com.engflow.bazel.invocation.analyzer.integrationtests.IntegrationTestSuite", 8 | deps = [ 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:types", 14 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution", 15 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/suggestionproviders", 16 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 17 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 18 | "//proto:bazel_invocation_analyzer_java_proto", 19 | "//third_party/junit", 20 | "//third_party/truth", 21 | ], 22 | ) 23 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/integrationtests/IntegerationTestBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.integrationtests; 16 | 17 | import com.engflow.bazel.invocation.analyzer.ProfileTestBase; 18 | import com.engflow.bazel.invocation.analyzer.bazelprofile.BazelProfile; 19 | import com.engflow.bazel.invocation.analyzer.core.DataManager; 20 | import com.engflow.bazel.invocation.analyzer.core.DuplicateProviderException; 21 | import org.junit.Before; 22 | 23 | public abstract class IntegerationTestBase extends ProfileTestBase { 24 | /** DataManager to coordinate the transfer of data between Providers */ 25 | protected DataManager dataManager; 26 | 27 | @Before 28 | public void setupInstance() { 29 | dataManager = new DataManager(); 30 | } 31 | 32 | @Override 33 | protected void registerBazelProfile(BazelProfile bazelProfile) throws DuplicateProviderException { 34 | bazelProfile.registerWithDataManager(dataManager); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/integrationtests/IntegrationTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.integrationtests; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | JobsSuggestionProviderIntegrationTest.class, 23 | NegligiblePhaseSuggestionProviderIntegrationTest.class, 24 | }) 25 | public class IntegrationTestSuite {} 26 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/bazel-profile-Long-Phase-Test.json: -------------------------------------------------------------------------------- 1 | { 2 | "otherData": { 3 | "build_id": "52f0a044-539c-488c-8a7d-9a7d43af4745", 4 | "date": "Tue Aug 02 17:11:16 UTC 2022", 5 | "output_base": "/home/github-actions-runner/.cache/bazel/_bazel_github-actions-runner/821f525b4992dc2a685662ed20d9fe01" 6 | }, 7 | "traceEvents": [ 8 | { 9 | "args": { 10 | "name": "Main Thread" 11 | }, 12 | "name": "thread_name", 13 | "ph": "M", 14 | "pid": 1, 15 | "tid": 20 16 | }, 17 | { 18 | "cat": "build phase marker", 19 | "dur": 17000, 20 | "name": "Launch Blaze", 21 | "ph": "X", 22 | "pid": 1, 23 | "tid": 20, 24 | "ts": -17000 25 | }, 26 | { 27 | "cat": "build phase marker", 28 | "name": "Initialize command", 29 | "ph": "i", 30 | "pid": 1, 31 | "tid": 20, 32 | "ts": 0 33 | }, 34 | { 35 | "cat": "build phase marker", 36 | "name": "Evaluate target patterns", 37 | "ph": "i", 38 | "pid": 1, 39 | "tid": 20, 40 | "ts": 31229183 41 | }, 42 | { 43 | "cat": "build phase marker", 44 | "name": "Load and analyze dependencies", 45 | "ph": "i", 46 | "pid": 1, 47 | "tid": 20, 48 | "ts": 34200314 49 | }, 50 | { 51 | "cat": "build phase marker", 52 | "name": "Prepare for build", 53 | "ph": "i", 54 | "pid": 1, 55 | "tid": 20, 56 | "ts": 77059750 57 | }, 58 | { 59 | "cat": "build phase marker", 60 | "name": "Build artifacts", 61 | "ph": "i", 62 | "pid": 1, 63 | "tid": 20, 64 | "ts": 77090175 65 | }, 66 | { 67 | "cat": "build phase marker", 68 | "name": "Complete build", 69 | "ph": "i", 70 | "pid": 1, 71 | "tid": 20, 72 | "ts": 727135633 73 | }, 74 | { 75 | "cat": "general information", 76 | "name": "Finishing", 77 | "ph": "i", 78 | "pid": 1, 79 | "tid": 20, 80 | "ts": 727213543 81 | } 82 | ] 83 | } 84 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/bazel-profile-with_queuing.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/bazel-profile-with_queuing.json.gz -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/local-jobs-100.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/local-jobs-100.json.gz -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/local-jobs-4.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/local-jobs-4.json.gz -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/local-jobs-none.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/local-jobs-none.json.gz -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/tiny.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/analyzer/javatests/com/engflow/bazel/invocation/analyzer/profiles/tiny.json.gz -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/suggestionproviders/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "suggestionproviders", 5 | srcs = glob(["**/*.java"]), 6 | data = ["//analyzer/javatests/com/engflow/bazel/invocation/analyzer:profiles"], 7 | test_class = "com.engflow.bazel.invocation.analyzer.suggestionproviders.SuggestionProvidersTestSuite", 8 | deps = [ 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile:types", 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:types", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders/remoteexecution:types", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/suggestionproviders", 14 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 15 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 16 | "//proto:bazel_invocation_analyzer_java_proto", 17 | "//third_party/junit", 18 | "//third_party/mockito", 19 | "//third_party/truth", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/suggestionproviders/BuildWithoutTheBytesSuggestionProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.suggestionproviders; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.mockito.Mockito.verify; 19 | import static org.mockito.Mockito.verifyNoMoreInteractions; 20 | import static org.mockito.Mockito.when; 21 | 22 | import com.engflow.bazel.invocation.analyzer.SuggestionOutput; 23 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.RemoteExecutionUsed; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | 27 | public class BuildWithoutTheBytesSuggestionProviderTest extends SuggestionProviderUnitTestBase { 28 | // These variables are returned from calls to DataManager.getDatum for the associated types. They 29 | // are set up with reasonable defaults before each test is run, but can be overridden within the 30 | // tests when custom values are desired for the testing being conducted (without the need to 31 | // re-initialize the mocking). 32 | private RemoteExecutionUsed remoteExecutionUsed; 33 | 34 | @Before 35 | public void setup() throws Exception { 36 | // Create reasonable defaults and set up to return the class-variables when the associated types 37 | // are requested. 38 | remoteExecutionUsed = new RemoteExecutionUsed(true); 39 | when(dataManager.getDatum(RemoteExecutionUsed.class)).thenAnswer(i -> remoteExecutionUsed); 40 | 41 | suggestionProvider = new BuildWithoutTheBytesSuggestionProvider(); 42 | } 43 | 44 | @Test 45 | public void shouldReturnSuggestionForRemoteExecutionInvocation() throws Exception { 46 | remoteExecutionUsed = new RemoteExecutionUsed(true); 47 | 48 | SuggestionOutput suggestionOutput = suggestionProvider.getSuggestions(dataManager); 49 | verify(dataManager).getDatum(RemoteExecutionUsed.class); 50 | verifyNoMoreInteractions(dataManager); 51 | 52 | assertThat(suggestionOutput.getAnalyzerClassname()) 53 | .isEqualTo(BuildWithoutTheBytesSuggestionProvider.class.getName()); 54 | assertThat(suggestionOutput.getSuggestionList().size()).isEqualTo(1); 55 | assertThat(suggestionOutput.hasFailure()).isFalse(); 56 | } 57 | 58 | @Test 59 | public void shouldNotReturnSuggestionForLocalInvocation() throws Exception { 60 | remoteExecutionUsed = new RemoteExecutionUsed(false); 61 | 62 | SuggestionOutput suggestionOutput = suggestionProvider.getSuggestions(dataManager); 63 | verify(dataManager).getDatum(RemoteExecutionUsed.class); 64 | verifyNoMoreInteractions(dataManager); 65 | 66 | assertThat(suggestionOutput.getSuggestionList()).isEmpty(); 67 | assertThat(suggestionOutput.hasFailure()).isFalse(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/suggestionproviders/MergedEventsSuggestionProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.suggestionproviders; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.mockito.Mockito.verify; 19 | import static org.mockito.Mockito.verifyNoMoreInteractions; 20 | import static org.mockito.Mockito.when; 21 | 22 | import com.engflow.bazel.invocation.analyzer.SuggestionOutput; 23 | import com.engflow.bazel.invocation.analyzer.dataproviders.MergedEventsPresent; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | 27 | public class MergedEventsSuggestionProviderTest extends SuggestionProviderUnitTestBase { 28 | @Before 29 | public void setup() { 30 | suggestionProvider = new MergedEventsSuggestionProvider(); 31 | } 32 | 33 | @Test 34 | public void shouldNotReturnSuggestionWhenNoMergedEventsArePresent() throws Exception { 35 | when(dataManager.getDatum(MergedEventsPresent.class)) 36 | .thenReturn(new MergedEventsPresent(false)); 37 | SuggestionOutput suggestionOutput = suggestionProvider.getSuggestions(dataManager); 38 | 39 | verify(dataManager).getDatum(MergedEventsPresent.class); 40 | verifyNoMoreInteractions(dataManager); 41 | 42 | assertThat(suggestionOutput.getAnalyzerClassname()) 43 | .isEqualTo(MergedEventsSuggestionProvider.class.getName()); 44 | assertThat(suggestionOutput.getSuggestionList()).isEmpty(); 45 | assertThat(suggestionOutput.hasFailure()).isFalse(); 46 | } 47 | 48 | @Test 49 | public void shouldReturnSuggestionWhenMergedEventsArePresent() throws Exception { 50 | when(dataManager.getDatum(MergedEventsPresent.class)).thenReturn(new MergedEventsPresent(true)); 51 | SuggestionOutput suggestionOutput = suggestionProvider.getSuggestions(dataManager); 52 | 53 | verify(dataManager).getDatum(MergedEventsPresent.class); 54 | verifyNoMoreInteractions(dataManager); 55 | 56 | assertThat(suggestionOutput.getAnalyzerClassname()) 57 | .isEqualTo(MergedEventsSuggestionProvider.class.getName()); 58 | assertThat(suggestionOutput.getSuggestionList().size()).isEqualTo(1); 59 | assertThat(suggestionOutput.hasFailure()).isFalse(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/suggestionproviders/SuggestionProvidersTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.suggestionproviders; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | BottleneckSuggestionProviderTest.class, 23 | BuildWithoutTheBytesSuggestionProviderTest.class, 24 | CriticalPathNotDominantSuggestionProviderTest.class, 25 | GarbageCollectionSuggestionProviderTest.class, 26 | IncompleteProfileSuggestionProviderTest.class, 27 | InvestigateRemoteCacheMissesSuggestionProviderTest.class, 28 | JobsSuggestionProviderTest.class, 29 | LocalActionsWithRemoteExecutionSuggestionProviderTest.class, 30 | MergedEventsSuggestionProviderTest.class, 31 | NegligiblePhaseSuggestionProviderTest.class, 32 | NoCacheActionsSuggestionProviderTest.class, 33 | QueuingSuggestionProviderTest.class, 34 | UseRemoteCachingSuggestionProviderTest.class, 35 | UseSkymeldSuggestionProviderTest.class, 36 | }) 37 | public class SuggestionProvidersTestSuite {} 38 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/suggestionproviders/UseRemoteCachingSuggestionProviderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.suggestionproviders; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.mockito.Mockito.when; 19 | 20 | import com.engflow.bazel.invocation.analyzer.SuggestionOutput; 21 | import com.engflow.bazel.invocation.analyzer.dataproviders.remoteexecution.RemoteCachingUsed; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | public class UseRemoteCachingSuggestionProviderTest extends SuggestionProviderUnitTestBase { 26 | // These variables are returned from calls to DataManager.getDatum for the associated types. They 27 | // are set up with reasonable defaults before each test is run, but can be overridden within the 28 | // tests when custom values are desired for the testing being conducted (without the need to 29 | // re-initialize the mocking). 30 | private RemoteCachingUsed remoteCachingUsed; 31 | 32 | @Before 33 | public void setup() throws Exception { 34 | // Create reasonable defaults and set up to return the class-variables when the associated types 35 | // are requested. 36 | when(dataManager.getDatum(RemoteCachingUsed.class)).thenAnswer(i -> remoteCachingUsed); 37 | 38 | suggestionProvider = new UseRemoteCachingSuggestionProvider(); 39 | } 40 | 41 | @Test 42 | public void shouldReturnSuggestionIfRemoteCachingIsNotUsed() { 43 | remoteCachingUsed = new RemoteCachingUsed(false); 44 | 45 | SuggestionOutput suggestionOutput = suggestionProvider.getSuggestions(dataManager); 46 | assertThat(suggestionOutput.getAnalyzerClassname()) 47 | .isEqualTo(UseRemoteCachingSuggestionProvider.class.getName()); 48 | assertThat(suggestionOutput.getSuggestionList().size()).isEqualTo(1); 49 | assertThat(suggestionOutput.hasFailure()).isFalse(); 50 | } 51 | 52 | @Test 53 | public void shouldNotReturnSuggestionIfRemoteCachingIsUsed() { 54 | remoteCachingUsed = new RemoteCachingUsed(true); 55 | 56 | SuggestionOutput suggestionOutput = suggestionProvider.getSuggestions(dataManager); 57 | assertThat(suggestionOutput.getSuggestionList()).isEmpty(); 58 | assertThat(suggestionOutput.hasFailure()).isFalse(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/time/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "time", 5 | srcs = glob(["**/*.java"]), 6 | test_class = "com.engflow.bazel.invocation.analyzer.time.TimeTestSuite", 7 | deps = [ 8 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 9 | "//third_party/guava", 10 | "//third_party/junit", 11 | "//third_party/truth", 12 | ], 13 | ) 14 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/time/DurationUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.junit.Assert.assertThrows; 19 | 20 | import java.time.Duration; 21 | import org.junit.Test; 22 | 23 | public class DurationUtilTest { 24 | @Test 25 | public void formatHours() { 26 | assertThat(DurationUtil.formatDuration(Duration.ofHours(1))).isEqualTo("1h 0m 0s"); 27 | assertThat(DurationUtil.formatDuration(Duration.ofHours(1).plus(Duration.ofSeconds(2)))) 28 | .isEqualTo("1h 0m 2s"); 29 | assertThat(DurationUtil.formatDuration(Duration.ofHours(36))).isEqualTo("36h 0m 0s"); 30 | } 31 | 32 | @Test 33 | public void formatMinutes() { 34 | assertThat(DurationUtil.formatDuration(Duration.ofMinutes(1))).isEqualTo("1m 0s"); 35 | assertThat(DurationUtil.formatDuration(Duration.ofMinutes(1).plus(Duration.ofSeconds(2)))) 36 | .isEqualTo("1m 2s"); 37 | assertThat(DurationUtil.formatDuration(Duration.ofMinutes(59))).isEqualTo("59m 0s"); 38 | } 39 | 40 | @Test 41 | public void formatSeconds() { 42 | assertThat(DurationUtil.formatDuration(Duration.ofSeconds(10).plus(Duration.ofMillis(10)))) 43 | .isEqualTo("10s"); 44 | assertThat(DurationUtil.formatDuration(Duration.ofSeconds(59))).isEqualTo("59s"); 45 | } 46 | 47 | @Test 48 | public void formatMilliseconds() { 49 | assertThat(DurationUtil.formatDuration(Duration.ofSeconds(1))).isEqualTo("1000ms"); 50 | assertThat(DurationUtil.formatDuration(Duration.ofSeconds(9).plus(Duration.ofMillis(42)))) 51 | .isEqualTo("9042ms"); 52 | } 53 | 54 | @Test 55 | public void getPercentageOfZeroBase() { 56 | assertThrows( 57 | IllegalArgumentException.class, 58 | () -> DurationUtil.getPercentageOf(Duration.ofSeconds(1), Duration.ZERO)); 59 | } 60 | 61 | @Test 62 | public void getPercentageOfZeroFraction() { 63 | assertThat(DurationUtil.getPercentageOf(Duration.ZERO, Duration.ofSeconds(4))).isEqualTo(0); 64 | } 65 | 66 | @Test 67 | public void getPercentageOfFraction() { 68 | assertThat(DurationUtil.getPercentageOf(Duration.ofSeconds(1), Duration.ofSeconds(4))) 69 | .isEqualTo(25); 70 | } 71 | 72 | @Test 73 | public void getPercentageOfMultiple() { 74 | assertThat(DurationUtil.getPercentageOf(Duration.ofSeconds(4), Duration.ofSeconds(2))) 75 | .isEqualTo(200); 76 | } 77 | 78 | @Test 79 | public void getPercentageOfYears() { 80 | assertThat(DurationUtil.getPercentageOf(Duration.ofDays(4 * 365), Duration.ofDays(5 * 365))) 81 | .isEqualTo(80); 82 | } 83 | 84 | @Test 85 | public void getPercentageOfNanos() { 86 | assertThat(DurationUtil.getPercentageOf(Duration.ofNanos(200), Duration.ofNanos(5000))) 87 | .isEqualTo(4); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/time/TimeTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | DurationUtilTest.class, 23 | TimeUtilTest.class, 24 | TimestampTest.class, 25 | }) 26 | public class TimeTestSuite {} 27 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/time/TimeUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | 19 | import java.time.Duration; 20 | import java.util.concurrent.TimeUnit; 21 | import org.junit.Test; 22 | 23 | public class TimeUtilTest { 24 | @Test 25 | public void getDurationForMicrosAndGetMicrosShouldMatch() { 26 | long durationInMicros = 123_456; 27 | assertThat(TimeUtil.getMicros(TimeUtil.getDurationForMicros(durationInMicros))) 28 | .isEqualTo(durationInMicros); 29 | } 30 | 31 | @Test 32 | public void getDurationForMicrosShouldNotLoseAccuracy() { 33 | Duration duration = TimeUtil.getDurationForMicros(1); 34 | assertThat(TimeUtil.getMicros(duration)) 35 | .isEqualTo(TimeUnit.NANOSECONDS.toMicros(duration.toNanos())); 36 | } 37 | 38 | @Test 39 | public void getDurationBetweenShouldNotLoseAccuracy() { 40 | long first = 123_456; 41 | long second = 789_012; 42 | Timestamp firstTimestamp = Timestamp.ofMicros(first); 43 | Timestamp secondTimestamp = Timestamp.ofMicros(second); 44 | assertThat(TimeUtil.getDurationBetween(firstTimestamp, secondTimestamp)) 45 | .isEqualTo(TimeUtil.getDurationForMicros(second - first)); 46 | } 47 | 48 | @Test 49 | public void getDurationBetweenShouldBeCommutative() { 50 | long first = 123_456; 51 | long second = 789_012; 52 | Timestamp firstTimestamp = Timestamp.ofMicros(first); 53 | Timestamp secondTimestamp = Timestamp.ofMicros(second); 54 | assertThat(TimeUtil.getDurationBetween(firstTimestamp, secondTimestamp)) 55 | .isEqualTo(TimeUtil.getDurationBetween(secondTimestamp, firstTimestamp)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/time/TimestampTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.time; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | 19 | import java.time.Duration; 20 | import java.util.concurrent.TimeUnit; 21 | import org.junit.Test; 22 | 23 | public class TimestampTest { 24 | @Test 25 | public void plusShouldAddDurationCorrectly() { 26 | long timestampMicros = 100_000; 27 | long durationMicros = 23_456; 28 | Timestamp timestamp = Timestamp.ofMicros(timestampMicros); 29 | Duration duration = Duration.ofNanos(TimeUnit.MICROSECONDS.toNanos(durationMicros)); 30 | assertThat(timestamp.plus(duration)) 31 | .isEqualTo(Timestamp.ofMicros(timestampMicros + durationMicros)); 32 | } 33 | 34 | @Test 35 | public void plusShouldBeCommutative() { 36 | long a = 12; 37 | long b = 34; 38 | assertThat(Timestamp.ofSeconds(a).plus(Duration.ofSeconds(b))) 39 | .isEqualTo(Timestamp.ofSeconds(b).plus(Duration.ofSeconds(a))); 40 | } 41 | 42 | @Test 43 | public void ofMicrosAndOfSecondsShouldEqual() { 44 | int seconds = 12; 45 | Timestamp ofSeconds = Timestamp.ofSeconds(seconds); 46 | Timestamp ofMicros = Timestamp.ofMicros(TimeUnit.SECONDS.toMicros(seconds)); 47 | assertThat(ofSeconds).isEqualTo(ofMicros); 48 | } 49 | 50 | @Test 51 | public void almostEqualsShouldReturnTrueOnSameTimestamps() { 52 | Timestamp timestamp = Timestamp.ofMicros(123_456); 53 | assertThat(timestamp.almostEquals(timestamp)).isTrue(); 54 | } 55 | 56 | @Test 57 | public void almostEqualsShouldReturnTrueOnVeryCloseTimestamps() { 58 | Timestamp timestamp = Timestamp.ofMicros(123_456); 59 | Duration acceptableDifference = Timestamp.ACCEPTABLE_DIVERGENCE.minus(Duration.ofNanos(1)); 60 | assertThat(timestamp.almostEquals(timestamp.plus(acceptableDifference))).isTrue(); 61 | } 62 | 63 | @Test 64 | public void almostEqualsShouldReturnFalseOnDifferingTimestamps() { 65 | Timestamp timestamp = Timestamp.ofMicros(123_456); 66 | assertThat(timestamp.almostEquals(timestamp.plus(Timestamp.ACCEPTABLE_DIVERGENCE))).isFalse(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/traceeventformat/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "traceeventformat", 5 | srcs = glob(["**/*.java"]), 6 | test_class = "com.engflow.bazel.invocation.analyzer.traceeventformat.TraceEventFormatTestSuite", 7 | deps = [ 8 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/time", 9 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/traceeventformat", 10 | "//third_party/gson", 11 | "//third_party/junit", 12 | "//third_party/truth", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/traceeventformat/CounterEventTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.traceeventformat; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.junit.Assert.assertThrows; 19 | 20 | import com.google.gson.JsonObject; 21 | import org.junit.Test; 22 | 23 | public class CounterEventTest { 24 | @Test 25 | public void fromJsonThrowsOnMissingMembers() { 26 | var jsonObject = new JsonObject(); 27 | var e = assertThrows(IllegalArgumentException.class, () -> CounterEvent.fromJson(jsonObject)); 28 | for (var member : CounterEvent.REQUIRED_JSON_MEMBERS) { 29 | assertThat(e.getMessage()).contains(member); 30 | } 31 | } 32 | 33 | @Test 34 | public void fromJson() { 35 | var jsonObject = new JsonObject(); 36 | jsonObject.addProperty(TraceEventFormatConstants.EVENT_NAME, "someEventName"); 37 | jsonObject.addProperty(TraceEventFormatConstants.EVENT_TIMESTAMP, 1_234_567_890); 38 | 39 | var args = new JsonObject(); 40 | args.addProperty("argFooKey", 1.23); 41 | args.addProperty("argBarKey", 3.45); 42 | jsonObject.add(TraceEventFormatConstants.EVENT_ARGUMENTS, args); 43 | 44 | var event = CounterEvent.fromJson(jsonObject); 45 | assertThat(event.getName()).isEqualTo("someEventName"); 46 | assertThat(event.getTimestamp().getMicros()).isEqualTo(1_234_567_890); 47 | assertThat(event.getTotalValue()).isEqualTo(1.23 + 3.45); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/traceeventformat/InstantEventTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.traceeventformat; 16 | 17 | import static com.google.common.truth.Truth.assertThat; 18 | import static org.junit.Assert.assertThrows; 19 | 20 | import com.google.gson.JsonObject; 21 | import org.junit.Test; 22 | 23 | public class InstantEventTest { 24 | @Test 25 | public void fromJsonThrowsOnMissingMembers() { 26 | var jsonObject = new JsonObject(); 27 | var e = assertThrows(IllegalArgumentException.class, () -> InstantEvent.fromJson(jsonObject)); 28 | for (var member : InstantEvent.REQUIRED_JSON_MEMBERS) { 29 | assertThat(e.getMessage()).contains(member); 30 | } 31 | } 32 | 33 | @Test 34 | public void fromJson() { 35 | var jsonObject = new JsonObject(); 36 | jsonObject.addProperty(TraceEventFormatConstants.EVENT_CATEGORY, "someCategory"); 37 | jsonObject.addProperty(TraceEventFormatConstants.EVENT_NAME, "someEventName"); 38 | jsonObject.addProperty(TraceEventFormatConstants.EVENT_TIMESTAMP, 987_654_321); 39 | 40 | var event = InstantEvent.fromJson(jsonObject); 41 | assertThat(event.getName()).isEqualTo("someEventName"); 42 | assertThat(event.getCategory()).isEqualTo("someCategory"); 43 | assertThat(event.getTimestamp().getMicros()).isEqualTo(987_654_321); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /analyzer/javatests/com/engflow/bazel/invocation/analyzer/traceeventformat/TraceEventFormatTestSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.traceeventformat; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | CompleteEventTest.class, 23 | CounterEventTest.class, 24 | InstantEventTest.class, 25 | }) 26 | public class TraceEventFormatTestSuite {} 27 | -------------------------------------------------------------------------------- /cli/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_binary") 2 | 3 | java_binary( 4 | name = "cli", 5 | main_class = "com.engflow.bazel.invocation.analyzer.Main", 6 | runtime_deps = [ 7 | "//cli/java/com/engflow/bazel/invocation/analyzer", 8 | ], 9 | ) 10 | 11 | package_group( 12 | name = "default_visibility", 13 | packages = [ 14 | "//cli/...", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "analyzer", 5 | srcs = glob(["*.java"]), 6 | visibility = [ 7 | "//cli:__pkg__", 8 | ], 9 | deps = [ 10 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/bazelprofile", 11 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/dataproviders:util", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/suggestionproviders", 14 | "//cli/java/com/engflow/bazel/invocation/analyzer/consoleoutput", 15 | "//cli/java/com/engflow/bazel/invocation/analyzer/options", 16 | "//proto:bazel_invocation_analyzer_java_proto", 17 | "//third_party/guava", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/consoleoutput/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "consoleoutput", 5 | srcs = glob( 6 | ["*.java"], 7 | ), 8 | visibility = [ 9 | "//cli:default_visibility", 10 | ], 11 | deps = [ 12 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 13 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/suggestionproviders", 14 | "//proto:bazel_invocation_analyzer_java_proto", 15 | "//third_party/guava", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/consoleoutput/ConsoleOutputStyle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.consoleoutput; 16 | 17 | public enum ConsoleOutputStyle { 18 | TEXT_BOLD(1), 19 | TEXT_DIM(2), 20 | TEXT_UNDERLINE(4), 21 | TEXT_BG_INVERSE(7), 22 | TEXT_BLACK(30), 23 | TEXT_RED(31), 24 | TEXT_GREEN(32), 25 | TEXT_YELLOW(33), 26 | TEXT_BLUE(34), 27 | TEXT_MAGENTA(35), 28 | TEXT_CYAN(36), 29 | TEXT_WHITE(37), 30 | BG_BLACK(40), 31 | BG_RED(41), 32 | BG_GREEN(42), 33 | BG_YELLOW(43), 34 | BG_BLUE(44), 35 | BG_MAGENTA(45), 36 | BG_CYAN(46), 37 | BG_WHITE(47); 38 | 39 | public final int code; 40 | 41 | ConsoleOutputStyle(int code) { 42 | this.code = code; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/options/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "options", 5 | srcs = glob( 6 | ["*.java"], 7 | ), 8 | visibility = [ 9 | "//cli:default_visibility", 10 | ], 11 | deps = [ 12 | "//third_party/commons-cli:commons_cli", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/options/IaOption.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.options; 16 | 17 | import java.util.Arrays; 18 | import java.util.Locale; 19 | import java.util.stream.Collectors; 20 | import org.apache.commons.cli.Option; 21 | 22 | public enum IaOption { 23 | HELP( 24 | Option.builder() 25 | .option("h") 26 | .longOpt("help") 27 | .desc("Print this help message.") 28 | .type(Boolean.class) 29 | .build()), 30 | OUTPUT_PLAINTEXT( 31 | Option.builder() 32 | .longOpt("plaintext") 33 | .desc("Enable to output unformatted console output.") 34 | .type(Boolean.class) 35 | .build()), 36 | OUTPUT_VERBOSE( 37 | Option.builder() 38 | .longOpt("verbose") 39 | .desc("Enable to output verbose console output.") 40 | .type(Boolean.class) 41 | .build()), 42 | OUTPUT_MODE( 43 | Option.builder() 44 | .longOpt("mode") 45 | .hasArgs() 46 | .valueSeparator(',') 47 | .desc( 48 | "Specify what information to generate. One or more of " 49 | + Arrays.stream(Mode.values()) 50 | .map(Mode::toString) 51 | .map(s -> s.toLowerCase(Locale.US)) 52 | .collect(Collectors.joining(",")) 53 | + " separated by commas.") 54 | .type(String.class) 55 | .build()); 56 | 57 | public final Option option; 58 | 59 | IaOption(Option option) { 60 | this.option = option; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/options/IaOptions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.options; 16 | 17 | import org.apache.commons.cli.CommandLine; 18 | import org.apache.commons.cli.DefaultParser; 19 | import org.apache.commons.cli.HelpFormatter; 20 | import org.apache.commons.cli.Options; 21 | import org.apache.commons.cli.ParseException; 22 | 23 | public final class IaOptions { 24 | private final CommandLine commandLine; 25 | private final Options options; 26 | 27 | public IaOptions(String[] args) throws ParseException { 28 | options = new Options(); 29 | for (IaOption iaOption : IaOption.values()) { 30 | options.addOption(iaOption.option); 31 | } 32 | this.commandLine = new DefaultParser().parse(options, args); 33 | } 34 | 35 | /** 36 | * Returns true iff the boolean iaOption is supplied, else false. 37 | * 38 | * @param iaOption the option to check for 39 | * @return true iff the iaOption is supplied 40 | * @throws IllegalArgumentException if the iaOption is not of Boolean type 41 | */ 42 | public Boolean hasOption(IaOption iaOption) { 43 | if (iaOption.option.getType() != Boolean.class) { 44 | throw new IllegalArgumentException( 45 | String.format( 46 | "Option %s does not have boolean type (actual: %s)", 47 | iaOption.option.getLongOpt(), iaOption.option.getType())); 48 | } 49 | return commandLine.hasOption(iaOption.option); 50 | } 51 | 52 | /** 53 | * Returns the option's value, or null if not set 54 | * 55 | * @param iaOption the option to retrieve 56 | * @return if set, the value of the option, otherwise null 57 | */ 58 | public String getOption(IaOption iaOption) { 59 | return commandLine.getOptionValue(iaOption.option); 60 | } 61 | 62 | /** 63 | * Returns the option's values, or null if not set 64 | * 65 | * @param iaOption the option to retrieve 66 | * @return if set, the value of the option, otherwise null 67 | * @throws IllegalArgumentException if the passed in option does not support multiple values 68 | */ 69 | public String[] getOptions(IaOption iaOption) { 70 | if (!iaOption.option.hasArgs()) { 71 | throw new IllegalArgumentException( 72 | "Can only call getOptions on options that accept multiple values"); 73 | } 74 | return commandLine.getOptionValues(iaOption.option); 75 | } 76 | 77 | /** 78 | * @return all the positional arguments without options 79 | */ 80 | public String[] getArguments() { 81 | return commandLine.getArgs(); 82 | } 83 | 84 | public void printHelp() { 85 | final var helpFormatter = new HelpFormatter(); 86 | helpFormatter.setLongOptSeparator("="); 87 | helpFormatter.printHelp("bazel-invocation-analyzer [OPTIONS...] FILE", options); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /cli/java/com/engflow/bazel/invocation/analyzer/options/Mode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.options; 16 | 17 | /** 18 | * Specifies what information about the analyzed profile is printed. 19 | * 20 | *

    Modes are combinable for printing multiple categories of information. 21 | */ 22 | public enum Mode { 23 | /** Include all datum elements produced by DataProviders. */ 24 | ALL_DATA, 25 | /** 26 | * Include any datum elements consumed by SuggestionProviders. 27 | * 28 | *

    This option has no effect when ALL_DATA is specified. 29 | */ 30 | USED_DATA, 31 | /** 32 | * Include all suggestions generated by SuggestionProviders. 33 | * 34 | *

    This is the default mode if no mode is specified. 35 | */ 36 | SUGGESTIONS 37 | } 38 | -------------------------------------------------------------------------------- /cli/javatests/com/engflow/bazel/invocation/analyzer/consoleoutput/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_test") 2 | 3 | java_test( 4 | name = "consoleoutput", 5 | srcs = glob(["*.java"]), 6 | test_class = "com.engflow.bazel.invocation.analyzer.consoleoutput.ConsoleOutputSuite", 7 | deps = [ 8 | "//analyzer/java/com/engflow/bazel/invocation/analyzer/core", 9 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer:test_base", 10 | "//analyzer/javatests/com/engflow/bazel/invocation/analyzer/core:types", 11 | "//cli/java/com/engflow/bazel/invocation/analyzer/consoleoutput", 12 | "//proto:bazel_invocation_analyzer_java_proto", 13 | "//third_party/guava", 14 | "//third_party/junit", 15 | "//third_party/truth", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /cli/javatests/com/engflow/bazel/invocation/analyzer/consoleoutput/ConsoleOutputSuite.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 EngFlow Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | 15 | package com.engflow.bazel.invocation.analyzer.consoleoutput; 16 | 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Suite; 19 | 20 | @RunWith(Suite.class) 21 | @Suite.SuiteClasses({ 22 | ConsoleOutputTest.class, 23 | }) 24 | public class ConsoleOutputSuite {} 25 | -------------------------------------------------------------------------------- /conditions/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | config_setting( 4 | name = "darwin_arm64", 5 | constraint_values = [ 6 | "@platforms//cpu:arm64", 7 | "@platforms//os:macos", 8 | ], 9 | ) 10 | 11 | config_setting( 12 | name = "darwin_x86_64", 13 | constraint_values = [ 14 | "@platforms//cpu:x86_64", 15 | "@platforms//os:macos", 16 | ], 17 | ) 18 | 19 | config_setting( 20 | name = "linux_aarch64", 21 | constraint_values = [ 22 | "@platforms//os:linux", 23 | "@platforms//cpu:aarch64", 24 | ], 25 | ) 26 | 27 | config_setting( 28 | name = "linux_x86_64", 29 | constraint_values = [ 30 | "@platforms//cpu:x86_64", 31 | "@platforms//os:linux", 32 | ], 33 | ) 34 | 35 | config_setting( 36 | name = "windows", 37 | constraint_values = ["@platforms//os:windows"], 38 | ) 39 | -------------------------------------------------------------------------------- /docs/assets/gc-profile-in-chrome-tracing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/docs/assets/gc-profile-in-chrome-tracing.png -------------------------------------------------------------------------------- /docs/assets/gc-suggestion-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngFlow/bazel_invocation_analyzer/034c619c61313623f7e32d182b37c0d92a5dbcf9/docs/assets/gc-suggestion-output.png -------------------------------------------------------------------------------- /infra/BUILD: -------------------------------------------------------------------------------- 1 | sh_binary( 2 | name = "lint", 3 | srcs = [":lint.sh"], 4 | data = [ 5 | "//third_party/buildifier", 6 | "//third_party/google-java-format", 7 | ], 8 | env = { 9 | "JAVA_FORMATTER": "$(rlocationpath //third_party/google-java-format)", 10 | "STARLARK_FORMATTER": "$(rlocationpath //third_party/buildifier)", 11 | }, 12 | deps = ["@bazel_tools//tools/bash/runfiles"], 13 | ) 14 | -------------------------------------------------------------------------------- /infra/git/hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2022 EngFlow Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script bootstraps building a Bazel binary without Bazel then 18 | # use this compiled Bazel to bootstrap Bazel itself. It can also 19 | # be provided with a previous version of Bazel to bootstrap Bazel 20 | # itself. 21 | # The resulting binary can be found at output/bazel. 22 | 23 | set -o nounset -o pipefail -o errexit 24 | [[ -n "${SCRIPT_DEBUG:-}" ]] && set -o xtrace 25 | 26 | bazel run --ui_event_filters=WARNING,ERROR --noshow_progress //infra:lint -- "$(pwd)" 27 | -------------------------------------------------------------------------------- /infra/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2022 EngFlow Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # This script bootstraps building a Bazel binary without Bazel then 18 | # use this compiled Bazel to bootstrap Bazel itself. It can also 19 | # be provided with a previous version of Bazel to bootstrap Bazel 20 | # itself. 21 | # The resulting binary can be found at output/bazel. 22 | 23 | set -o nounset -o pipefail -o errexit 24 | [[ -n "${SCRIPT_DEBUG:-}" ]] && set -o xtrace 25 | 26 | rm -f .git/hooks/pre-commit 27 | ln -s ../../infra/git/hooks/pre-commit .git/hooks/pre-commit -------------------------------------------------------------------------------- /proto/BUILD: -------------------------------------------------------------------------------- 1 | load("@protobuf//bazel:java_proto_library.bzl", "java_proto_library") 2 | load("@protobuf//bazel:proto_library.bzl", "proto_library") 3 | 4 | proto_library( 5 | name = "bazel_invocation_analyzer_proto", 6 | srcs = [ 7 | "bazel_invocation_analyzer.proto", 8 | ], 9 | visibility = ["//visibility:public"], 10 | ) 11 | 12 | java_proto_library( 13 | name = "bazel_invocation_analyzer_java_proto", 14 | visibility = ["//visibility:public"], 15 | deps = [ 16 | ":bazel_invocation_analyzer_proto", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /third_party/buildifier/BUILD: -------------------------------------------------------------------------------- 1 | load("@buildifier_prebuilt//:rules.bzl", "buildifier_binary") 2 | 3 | package(default_visibility = ["//infra:__subpackages__"]) 4 | 5 | buildifier_binary( 6 | name = "buildifier", 7 | visibility = ["//visibility:public"], 8 | ) 9 | -------------------------------------------------------------------------------- /third_party/commons-cli/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "commons_cli", 5 | visibility = ["//visibility:public"], 6 | exports = [ 7 | "@maven//:commons_cli_commons_cli", 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /third_party/google-java-format/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_binary") 2 | 3 | package(default_visibility = ["//infra:__subpackages__"]) 4 | 5 | java_binary( 6 | name = "google-java-format", 7 | jvm_flags = [ 8 | "--add-opens=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", 9 | "--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", 10 | "--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", 11 | "--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", 12 | "--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", 13 | ], 14 | main_class = "com.google.googlejavaformat.java.Main", 15 | runtime_deps = ["@maven//:com_google_googlejavaformat_google_java_format"], 16 | ) 17 | -------------------------------------------------------------------------------- /third_party/gson/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "gson", 5 | visibility = ["//visibility:public"], 6 | exports = [ 7 | "@maven//:com_google_code_gson_gson", 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /third_party/guava/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "guava", 5 | visibility = ["//visibility:public"], 6 | exports = [ 7 | "@maven//:com_google_guava_failureaccess", 8 | "@maven//:com_google_guava_guava", 9 | ], 10 | ) 11 | -------------------------------------------------------------------------------- /third_party/jsr305/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "jsr305", 5 | visibility = ["//visibility:public"], 6 | exports = [ 7 | "@maven//:com_google_code_findbugs_jsr305", 8 | ], 9 | ) 10 | -------------------------------------------------------------------------------- /third_party/junit/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "junit", 5 | testonly = 1, 6 | visibility = ["//visibility:public"], 7 | exports = [ 8 | "@maven//:junit_junit", 9 | ], 10 | ) 11 | -------------------------------------------------------------------------------- /third_party/mockito/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "mockito", 5 | testonly = 1, 6 | visibility = ["//visibility:public"], 7 | exports = [ 8 | "@maven//:org_mockito_mockito_core", 9 | ], 10 | ) 11 | -------------------------------------------------------------------------------- /third_party/truth/BUILD: -------------------------------------------------------------------------------- 1 | load("@rules_java//java:defs.bzl", "java_library") 2 | 3 | java_library( 4 | name = "truth", 5 | testonly = 1, 6 | visibility = ["//visibility:public"], 7 | exports = [ 8 | "@maven//:com_google_truth_extensions_truth_java8_extension", 9 | "@maven//:com_google_truth_truth", 10 | ], 11 | runtime_deps = [ 12 | "//third_party/guava", 13 | ], 14 | ) 15 | --------------------------------------------------------------------------------