diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD index 313dccb6e1af12..f0d6b1d732a196 100644 --- a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD +++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD @@ -27,6 +27,7 @@ proto_library( srcs = ["build_event_stream.proto"], deps = [ "//src/main/protobuf:command_line_proto", + "//src/main/protobuf:critical_path_proto", "//src/main/protobuf:failure_details_proto", "//src/main/protobuf:invocation_policy_proto", "@com_google_protobuf//:duration_proto", diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto index 6af667e3377751..09fa00f75e0123 100644 --- a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto +++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto @@ -19,6 +19,7 @@ package build_event_stream; import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; import "src/main/protobuf/command_line.proto"; +import "src/main/protobuf/critical_path.proto"; import "src/main/protobuf/failure_details.proto"; import "src/main/protobuf/invocation_policy.proto"; @@ -222,6 +223,7 @@ message BuildEventId { // Identifier of an event providing convenience symlinks information. message ConvenienceSymlinksIdentifiedId {} + // Next id: 28. oneof id { UnknownBuildEventId unknown = 1; ProgressId progress = 2; @@ -249,6 +251,7 @@ message BuildEventId { WorkspaceConfigId workspace = 23; BuildMetadataId build_metadata = 24; ConvenienceSymlinksIdentifiedId convenience_symlinks_identified = 25; + build.bazel.bep.CriticalPath.BepId critical_path = 27; } } @@ -1151,6 +1154,8 @@ message ConvenienceSymlink { // events as children. More details, which are specific to the kind of event // that is observed, is provided in the payload. More options for the payload // might be added in the future. +// +// Next id: 30. message BuildEvent { reserved 11, 19; BuildEventId id = 1; @@ -1180,5 +1185,6 @@ message BuildEvent { WorkspaceConfig workspace_info = 25; BuildMetadata build_metadata = 26; ConvenienceSymlinksIdentified convenience_symlinks_identified = 27; + build.bazel.bep.CriticalPath critical_path = 29; } } diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java index 3069056ab3a0a7..4dfa5d323d5412 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java @@ -45,6 +45,7 @@ import com.google.devtools.build.lib.events.OutputFilter; import com.google.devtools.build.lib.events.Reporter; import com.google.devtools.build.lib.exec.ExecutionOptions; +import com.google.devtools.build.lib.metrics.criticalpath.CriticalPathEvent; import com.google.devtools.build.lib.pkgcache.LoadingFailedException; import com.google.devtools.build.lib.profiler.ProfilePhase; import com.google.devtools.build.lib.profiler.Profiler; @@ -694,7 +695,9 @@ public void stopRequest( new BuildCompleteEvent( result, ImmutableList.of( - BuildEventIdUtil.buildToolLogs(), BuildEventIdUtil.buildMetrics()))); + BuildEventIdUtil.buildToolLogs(), + BuildEventIdUtil.buildMetrics(), + CriticalPathEvent.BEP_ID))); } // Post the build tool logs event; the corresponding local files may be contributed from // modules, and this has to happen after posting the BuildCompleteEvent because that's when diff --git a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/AggregatedCriticalPath.java b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/AggregatedCriticalPath.java index a976ce4cc46ed4..66b073f3fed813 100644 --- a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/AggregatedCriticalPath.java +++ b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/AggregatedCriticalPath.java @@ -15,7 +15,9 @@ package com.google.devtools.build.lib.metrics.criticalpath; import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.eventbus.EventBus; import com.google.devtools.build.lib.actions.AggregatedSpawnMetrics; import com.google.devtools.build.lib.actions.SpawnMetrics; import java.time.Duration; @@ -103,4 +105,11 @@ public String toStringSummary() { public String toStringSummaryNoRemote() { return toString(true, false); } + + /**Posts the {@code BEP} event for the critical path on the provided {@link EventBus}. */ + public void postEvent(EventBus eventBus) { + Preconditions.checkNotNull(eventBus); + + eventBus.post(new CriticalPathEvent(Duration.ofMillis(totalTimeInMs))); + } } diff --git a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/BUILD b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/BUILD index 70fc413931cf15..72dc94bd78e0ef 100644 --- a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/BUILD +++ b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/BUILD @@ -17,12 +17,17 @@ java_library( deps = [ "//src/main/java/com/google/devtools/build/lib/actions", "//src/main/java/com/google/devtools/build/lib/actions:artifacts", + "//src/main/java/com/google/devtools/build/lib/buildeventstream", + "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto", "//src/main/java/com/google/devtools/build/lib/clock", "//src/main/java/com/google/devtools/build/lib/cmdline", "//src/main/java/com/google/devtools/build/lib/concurrent", + "//src/main/java/com/google/devtools/build/lib/events", "//src/main/java/com/google/devtools/build/lib/skyframe/rewinding:action_rewound_event", + "//src/main/protobuf:critical_path_java_proto", "//third_party:flogger", "//third_party:guava", "//third_party:jsr305", + "@com_google_protobuf//:protobuf_java", ], ) diff --git a/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathEvent.java b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathEvent.java new file mode 100644 index 00000000000000..5dfaae49478a8b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/metrics/criticalpath/CriticalPathEvent.java @@ -0,0 +1,47 @@ +package com.google.devtools.build.lib.metrics.criticalpath; + +import build.bazel.bep.CriticalPath; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.buildeventstream.BuildEventContext; +import com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil; +import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos; +import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId; +import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint; +import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent; +import java.time.Duration; +import java.util.Collection; + +/** {@code Build event protocol} event for the {@code critical path} of a build. */ +public final class CriticalPathEvent extends GenericBuildEvent + implements BuildEventWithOrderConstraint { + public static final BuildEventId BEP_ID = + BuildEventId.newBuilder().setCriticalPath(CriticalPath.BepId.getDefaultInstance()).build(); + + private final Duration totalTime; + + CriticalPathEvent(Duration totalTime) { + super(BEP_ID, ImmutableList.of()); + + this.totalTime = Preconditions.checkNotNull(totalTime); + } + + @Override + public Collection postedAfter() { + return ImmutableList.of(BuildEventIdUtil.buildFinished()); + } + + @Override + public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) { + return GenericBuildEvent.protoChaining(this) + .setCriticalPath( + CriticalPath.newBuilder() + .setTotalTime( + com.google.protobuf.Duration.newBuilder() + .setSeconds(totalTime.getSeconds()) + .setNanos(totalTime.getNano()) + .build()) + .build()) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java b/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java index 9a1fc76f8f8fed..359a589a3dc149 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/BuildSummaryStatsModule.java @@ -225,6 +225,8 @@ public void buildComplete(BuildCompleteEvent event) { .getResult() .getBuildToolLogCollection() .addDirectValue("process stats", spawnSummaryString.getBytes(StandardCharsets.UTF_8)); + + criticalPath.postEvent(eventBus); } finally { if (criticalPathComputer != null) { eventBus.unregister(criticalPathComputer); diff --git a/src/main/protobuf/BUILD b/src/main/protobuf/BUILD index ca6ffb099a7f89..56c1d41f76c9ba 100644 --- a/src/main/protobuf/BUILD +++ b/src/main/protobuf/BUILD @@ -90,6 +90,30 @@ java_library_srcs( deps = [":command_server_java_proto"], ) +proto_library( + name = "critical_path_proto", + srcs = [ + "critical_path.proto", + ], + deps = [ + "@com_google_protobuf//:duration_proto", + ], +) + +java_proto_library( + name = "critical_path_java_proto", + deps = [ + ":critical_path_proto", + ], +) + +java_library_srcs( + name = "critical_path_java_proto_srcs", + deps = [ + ":critical_path_java_proto", + ], +) + proto_library( name = "failure_details_proto", srcs = ["failure_details.proto"], @@ -272,6 +296,7 @@ filegroup( ":command_line_java_proto_srcs", ":command_server_java_grpc_srcs", ":command_server_java_proto_srcs", + ":critical_path_java_proto_srcs", ":failure_details_java_proto_srcs", ":option_filters_java_proto_srcs", ":profile_java_proto_srcs", diff --git a/src/main/protobuf/critical_path.proto b/src/main/protobuf/critical_path.proto new file mode 100644 index 00000000000000..034d7a06917d41 --- /dev/null +++ b/src/main/protobuf/critical_path.proto @@ -0,0 +1,33 @@ +// Copyright 2022 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package build.bazel.bep; + +import "google/protobuf/duration.proto"; + +option java_package = "build.bazel.bep"; +option java_outer_classname = "CriticalPathProtos"; +// option java_api_version = 2; +option java_multiple_files = true; + +// Represents the critical path of a build. +message CriticalPath { + // Identifier of a BES event of this type. + message BepId {} + + // The total time of the critical path. + google.protobuf.Duration total_time = 1; +} diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java b/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java index 33b09f475ec228..3d0f3a1f63a835 100644 --- a/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java @@ -84,6 +84,7 @@ import com.google.devtools.build.lib.runtime.BlazeRuntime; import com.google.devtools.build.lib.runtime.BlazeServerStartupOptions; import com.google.devtools.build.lib.runtime.BlazeWorkspace; +import com.google.devtools.build.lib.runtime.BuildSummaryStatsModule; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.runtime.NoSpawnCacheModule; import com.google.devtools.build.lib.runtime.ServerBuilder; @@ -563,7 +564,8 @@ protected BlazeRuntime.Builder getRuntimeBuilder() throws Exception { .addBlazeModule(new OutputFilteringModule()) .addBlazeModule(connectivityModule) .addBlazeModule(new SkymeldModule()) - .addBlazeModule(getMockBazelRepositoryModule()); + .addBlazeModule(getMockBazelRepositoryModule()) + .addBlazeModule(new BuildSummaryStatsModule()); getSpawnModules().forEach(builder::addBlazeModule); builder .addBlazeModule(getBuildInfoModule())