Move TaskData to its own class.
Since it's used by both the Profiler and the JsonTraceFileWriter. It also makes the Profiler code more manageable.
PiperOrigin-RevId: 828071526
Change-Id: I25ef89ba2ee9ad00544952015caf0ec73a24cc87
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/BUILD b/src/main/java/com/google/devtools/build/lib/profiler/BUILD
index 782c05f..ae23305 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/profiler/BUILD
@@ -54,6 +54,7 @@
"SingleStatRecorder.java",
"SlowTask.java",
"StatRecorder.java",
+ "TaskData.java",
"ThreadMetadata.java",
"TimeSeries.java",
"TimeSeriesImpl.java",
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/JsonTraceFileWriter.java b/src/main/java/com/google/devtools/build/lib/profiler/JsonTraceFileWriter.java
index 8146b7c..9d3997a 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/JsonTraceFileWriter.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/JsonTraceFileWriter.java
@@ -17,7 +17,6 @@
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
-import com.google.devtools.build.lib.profiler.Profiler.TaskData;
import com.google.gson.stream.JsonWriter;
import java.io.BufferedOutputStream;
import java.io.IOException;
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/Profiler.java b/src/main/java/com/google/devtools/build/lib/profiler/Profiler.java
index 3b87223..f3c33a9 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/Profiler.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/Profiler.java
@@ -27,12 +27,11 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.collect.Extrema;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.profiler.PredicateBasedStatRecorder.RecorderAndPredicate;
import com.google.devtools.build.lib.profiler.StatRecorder.VfsHeuristics;
+import com.google.devtools.build.lib.profiler.TaskData.ActionTaskData;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.gson.stream.JsonWriter;
import com.sun.management.OperatingSystemMXBean;
import java.io.IOException;
import java.io.OutputStream;
@@ -49,7 +48,6 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@@ -94,138 +92,6 @@
JSON_TRACE_FILE_COMPRESSED_FORMAT
}
- /**
- * Container for the single task record.
- *
- * <p>Class itself is not thread safe, but all access to it from Profiler methods is.
- */
- @ThreadCompatible
- static class TaskData implements TraceData {
- final long threadId;
- final long startTimeNanos;
- final ProfilerTask type;
- final String description;
-
- long durationNanos;
-
- TaskData(
- long threadId,
- long startTimeNanos,
- long durationNanos,
- ProfilerTask eventType,
- String description) {
- this.threadId = threadId;
- this.startTimeNanos = startTimeNanos;
- this.durationNanos = durationNanos;
- this.type = eventType;
- this.description = checkNotNull(description);
- }
-
- TaskData(long threadId, long startTimeNanos, ProfilerTask eventType, String description) {
- this(threadId, startTimeNanos, /* durationNanos= */ -1, eventType, description);
- }
-
- TaskData(long threadId, long startTimeNanos, long durationNanos, String description) {
- this.type = ProfilerTask.UNKNOWN;
- this.threadId = threadId;
- this.startTimeNanos = startTimeNanos;
- this.durationNanos = durationNanos;
- this.description = description;
- }
-
- @Override
- public String toString() {
- return "Thread " + threadId + ", type " + type + ", " + description;
- }
-
- @Override
- public void writeTraceData(JsonWriter jsonWriter, long profileStartTimeNanos)
- throws IOException {
- String eventType = durationNanos == 0 ? "i" : "X";
- jsonWriter.setIndent(" ");
- jsonWriter.beginObject();
- jsonWriter.setIndent("");
- if (type == null) {
- jsonWriter.setIndent(" ");
- } else {
- jsonWriter.name("cat").value(type.description);
- }
- jsonWriter.name("name").value(description);
- jsonWriter.name("ph").value(eventType);
- jsonWriter
- .name("ts")
- .value(TimeUnit.NANOSECONDS.toMicros(startTimeNanos - profileStartTimeNanos));
- if (durationNanos != 0) {
- jsonWriter.name("dur").value(TimeUnit.NANOSECONDS.toMicros(durationNanos));
- }
- jsonWriter.name("pid").value(1);
-
- if (this instanceof ActionTaskData actionTaskData) {
- if (actionTaskData.primaryOutputPath != null) {
- // Primary outputs are non-mergeable, thus incompatible with slim profiles.
- jsonWriter.name("out").value(actionTaskData.primaryOutputPath);
- }
- if (actionTaskData.targetLabel != null
- || actionTaskData.mnemonic != null
- || actionTaskData.configuration != null) {
- jsonWriter.name("args");
- jsonWriter.beginObject();
- if (actionTaskData.targetLabel != null) {
- jsonWriter.name("target").value(actionTaskData.targetLabel);
- }
- if (actionTaskData.mnemonic != null) {
- jsonWriter.name("mnemonic").value(actionTaskData.mnemonic);
- }
- if (actionTaskData.configuration != null) {
- jsonWriter.name("configuration").value(actionTaskData.configuration);
- }
- jsonWriter.endObject();
- }
- }
- if (type == ProfilerTask.CRITICAL_PATH_COMPONENT) {
- jsonWriter.name("args");
- jsonWriter.beginObject();
- jsonWriter.name("tid").value(threadId);
- jsonWriter.endObject();
- }
- jsonWriter
- .name("tid")
- .value(
- type == ProfilerTask.CRITICAL_PATH_COMPONENT
- ? ThreadMetadata.CRITICAL_PATH_THREAD_ID
- : threadId);
- jsonWriter.endObject();
- }
- }
-
- /**
- * Similar to TaskData, specific for profiled actions. Depending on options, adds additional
- * action specific information such as primary output path and target label. This is only meant to
- * be used for ProfilerTask.ACTION.
- */
- static final class ActionTaskData extends TaskData {
- @Nullable final String primaryOutputPath;
- @Nullable final String targetLabel;
- @Nullable final String mnemonic;
- @Nullable final String configuration;
-
- ActionTaskData(
- long threadId,
- long startTimeNanos,
- long durationNanos,
- ProfilerTask eventType,
- @Nullable String mnemonic,
- String description,
- @Nullable String primaryOutputPath,
- @Nullable String targetLabel,
- @Nullable String configuration) {
- super(threadId, startTimeNanos, durationNanos, eventType, description);
- this.primaryOutputPath = primaryOutputPath;
- this.targetLabel = targetLabel;
- this.mnemonic = mnemonic;
- this.configuration = configuration;
- }
- }
/**
* Aggregator class that keeps track of the slowest tasks of the specified type.
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/TaskData.java b/src/main/java/com/google/devtools/build/lib/profiler/TaskData.java
new file mode 100644
index 0000000..4f65fb3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/profiler/TaskData.java
@@ -0,0 +1,154 @@
+// Copyright 2025 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.
+package com.google.devtools.build.lib.profiler;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nullable;
+
+/**
+ * Container for the single task record.
+ *
+ * <p>Class itself is not thread safe, but all access to it from Profiler methods is.
+ */
+@ThreadCompatible
+class TaskData implements TraceData {
+ final long threadId;
+ final long startTimeNanos;
+ final ProfilerTask type;
+ final String description;
+
+ long durationNanos;
+
+ TaskData(
+ long threadId,
+ long startTimeNanos,
+ long durationNanos,
+ ProfilerTask eventType,
+ String description) {
+ this.threadId = threadId;
+ this.startTimeNanos = startTimeNanos;
+ this.durationNanos = durationNanos;
+ this.type = eventType;
+ this.description = checkNotNull(description);
+ }
+
+ TaskData(long threadId, long startTimeNanos, ProfilerTask eventType, String description) {
+ this(threadId, startTimeNanos, /* durationNanos= */ -1, eventType, description);
+ }
+
+ TaskData(long threadId, long startTimeNanos, long durationNanos, String description) {
+ this.type = ProfilerTask.UNKNOWN;
+ this.threadId = threadId;
+ this.startTimeNanos = startTimeNanos;
+ this.durationNanos = durationNanos;
+ this.description = description;
+ }
+
+ @Override
+ public String toString() {
+ return "Thread " + threadId + ", type " + type + ", " + description;
+ }
+
+ @Override
+ public void writeTraceData(JsonWriter jsonWriter, long profileStartTimeNanos) throws IOException {
+ String eventType = durationNanos == 0 ? "i" : "X";
+ jsonWriter.setIndent(" ");
+ jsonWriter.beginObject();
+ jsonWriter.setIndent("");
+ if (type == null) {
+ jsonWriter.setIndent(" ");
+ } else {
+ jsonWriter.name("cat").value(type.description);
+ }
+ jsonWriter.name("name").value(description);
+ jsonWriter.name("ph").value(eventType);
+ jsonWriter
+ .name("ts")
+ .value(TimeUnit.NANOSECONDS.toMicros(startTimeNanos - profileStartTimeNanos));
+ if (durationNanos != 0) {
+ jsonWriter.name("dur").value(TimeUnit.NANOSECONDS.toMicros(durationNanos));
+ }
+ jsonWriter.name("pid").value(1);
+
+ if (this instanceof ActionTaskData actionTaskData) {
+ if (actionTaskData.primaryOutputPath != null) {
+ // Primary outputs are non-mergeable, thus incompatible with slim profiles.
+ jsonWriter.name("out").value(actionTaskData.primaryOutputPath);
+ }
+ if (actionTaskData.targetLabel != null
+ || actionTaskData.mnemonic != null
+ || actionTaskData.configuration != null) {
+ jsonWriter.name("args");
+ jsonWriter.beginObject();
+ if (actionTaskData.targetLabel != null) {
+ jsonWriter.name("target").value(actionTaskData.targetLabel);
+ }
+ if (actionTaskData.mnemonic != null) {
+ jsonWriter.name("mnemonic").value(actionTaskData.mnemonic);
+ }
+ if (actionTaskData.configuration != null) {
+ jsonWriter.name("configuration").value(actionTaskData.configuration);
+ }
+ jsonWriter.endObject();
+ }
+ }
+ if (type == ProfilerTask.CRITICAL_PATH_COMPONENT) {
+ jsonWriter.name("args");
+ jsonWriter.beginObject();
+ jsonWriter.name("tid").value(threadId);
+ jsonWriter.endObject();
+ }
+ jsonWriter
+ .name("tid")
+ .value(
+ type == ProfilerTask.CRITICAL_PATH_COMPONENT
+ ? ThreadMetadata.CRITICAL_PATH_THREAD_ID
+ : threadId);
+ jsonWriter.endObject();
+ }
+
+ /**
+ * Similar to TaskData, specific for profiled actions. Depending on options, adds additional
+ * action specific information such as primary output path and target label. This is only meant to
+ * be used for ProfilerTask.ACTION.
+ */
+ static final class ActionTaskData extends TaskData {
+ @Nullable final String primaryOutputPath;
+ @Nullable final String targetLabel;
+ @Nullable final String mnemonic;
+ @Nullable final String configuration;
+
+ ActionTaskData(
+ long threadId,
+ long startTimeNanos,
+ long durationNanos,
+ ProfilerTask eventType,
+ @Nullable String mnemonic,
+ String description,
+ @Nullable String primaryOutputPath,
+ @Nullable String targetLabel,
+ @Nullable String configuration) {
+ super(threadId, startTimeNanos, durationNanos, eventType, description);
+ this.primaryOutputPath = primaryOutputPath;
+ this.targetLabel = targetLabel;
+ this.mnemonic = mnemonic;
+ this.configuration = configuration;
+ }
+ }
+}