Delete read functionality for the old-style binary profile format.
RELNOTES[INC]: The old-style binary profile format is no longer suppported, use the new JSON trace profile instead.
PiperOrigin-RevId: 298574830
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 70c8070..85c8a74 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
@@ -66,74 +66,14 @@
* build.lib.vfs contain Profiler invocations and any dependency on those two packages would create
* circular relationship.
*
- * <p>All gathered instrumentation data will be stored in the file. Please, note, that while file
- * format is described here it is considered internal and can change at any time. For scripting,
- * using blaze analyze-profile --dump=raw would be more robust and stable solution.
- *
* <p>
*
- * <pre>
- * Profiler file consists of the deflated stream with following overall structure:
- * HEADER
- * TASK_TYPE_TABLE
- * TASK_RECORD...
- * EOF_MARKER
- *
- * HEADER:
- * int32: magic token (Profiler.MAGIC)
- * int32: version format (Profiler.VERSION)
- * string: file comment
- *
- * TASK_TYPE_TABLE:
- * int32: number of type names below
- * string... : type names. Each of the type names is assigned id according to
- * their position in this table starting from 0.
- *
- * TASK_RECORD:
- * int32 size: size of the encoded task record
- * byte[size] encoded_task_record:
- * varint64: thread id - as was returned by Thread.getId()
- * varint32: task id - starting from 1.
- * varint32: parent task id for subtasks or 0 for root tasks
- * varint64: start time in ns, relative to the Profiler.start() invocation
- * varint64: task duration in ns
- * byte: task type id (see TASK_TYPE_TABLE)
- * varint32: description string index incremented by 1 (>0) or 0 this is
- * a first occurrence of the description string
- * AGGREGATED_STAT...: remainder of the field (if present) represents
- * aggregated stats for that task
- * string: *optional* description string, will appear only if description
- * string index above was 0. In that case this string will be
- * assigned next sequential id so every unique description string
- * will appear in the file only once - after that it will be
- * referenced by id.
- *
- * AGGREGATE_STAT:
- * byte: stat type
- * varint32: total number of subtask invocations
- * varint64: cumulative duration of subtask invocations in ns.
- *
- * EOF_MARKER:
- * int64: -1 - please note that this corresponds to the thread id in the
- * TASK_RECORD which is always > 0
- * </pre>
- *
* @see ProfilerTask enum for recognized task types.
*/
@ThreadSafe
public final class Profiler {
private static final Logger logger = Logger.getLogger(Profiler.class.getName());
- public static final int MAGIC = 0x11223344;
-
- // File version number. Note that merely adding new record types in
- // the ProfilerTask does not require bumping version number as long as original
- // enum values are not renamed or deleted.
- public static final int VERSION = 0x03;
-
- // EOF marker. Must be < 0.
- public static final int EOF_MARKER = -1;
-
/** The profiler (a static singleton instance). Inactive by default. */
private static final Profiler instance = new Profiler();
@@ -146,7 +86,7 @@
/** File format enum. */
public enum Format {
JSON_TRACE_FILE_FORMAT,
- JSON_TRACE_FILE_COMPRESSED_FORMAT;
+ JSON_TRACE_FILE_COMPRESSED_FORMAT
}
/** A task that was very slow. */
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/ProfilerTask.java b/src/main/java/com/google/devtools/build/lib/profiler/ProfilerTask.java
index fc39cdf..13974e5 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/ProfilerTask.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/ProfilerTask.java
@@ -107,14 +107,14 @@
/** True if the metric records VFS operations */
private final boolean vfs;
- private ProfilerTask(String description, long minDuration, int slowestInstanceCount) {
+ ProfilerTask(String description, long minDuration, int slowestInstanceCount) {
this.description = description;
this.minDuration = minDuration;
this.slowestInstancesCount = slowestInstanceCount;
this.vfs = this.name().startsWith("VFS");
}
- private ProfilerTask(String description) {
+ ProfilerTask(String description) {
this(description, /* minDuration= */ -1, /* slowestInstanceCount= */ 0);
}
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/analysis/ProfileInfo.java b/src/main/java/com/google/devtools/build/lib/profiler/analysis/ProfileInfo.java
deleted file mode 100644
index 83b44b0..0000000
--- a/src/main/java/com/google/devtools/build/lib/profiler/analysis/ProfileInfo.java
+++ /dev/null
@@ -1,612 +0,0 @@
-// Copyright 2014 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.analysis;
-
-import static com.google.devtools.build.lib.profiler.ProfilerTask.TASK_COUNT;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.devtools.build.lib.profiler.ProfilePhase;
-import com.google.devtools.build.lib.profiler.Profiler;
-import com.google.devtools.build.lib.profiler.ProfilerTask;
-import com.google.devtools.build.lib.util.VarInt;
-import com.google.devtools.build.lib.vfs.Path;
-import java.io.BufferedInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-
-/**
- * Holds parsed profile file information and provides various ways of
- * accessing it (mostly through different dictionaries or sorted lists).
- *
- * <p>Class should not be instantiated directly but through the use of the
- * ProfileLoader.loadProfile() method.
- */
-public class ProfileInfo {
-
- /**
- * Immutable container for the aggregated stats.
- */
- public static final class AggregateAttr {
- public final int count;
- public final long totalTime;
-
- AggregateAttr(int count, long totalTime) {
- this.count = count;
- this.totalTime = totalTime;
- }
- }
-
- /** Immutable compact representation of the Map<ProfilerTask, AggregateAttr>. */
- public static final class CompactStatistics {
- final byte[] content;
-
- CompactStatistics(byte[] content) {
- this.content = content;
- }
-
- /**
- * Create compact task statistic instance using provided array.
- * Array length must exactly match ProfilerTask value space.
- * Each statistic is stored in the array according to the ProfilerTask
- * value ordinal() number. Absent statistics are represented by null.
- */
- CompactStatistics(AggregateAttr[] stats) {
- Preconditions.checkArgument(stats.length == TASK_COUNT);
- ByteBuffer sink = ByteBuffer.allocate(TASK_COUNT * (1 + 5 + 10));
- for (int i = 0; i < TASK_COUNT; i++) {
- if (stats[i] != null && stats[i].count > 0) {
- sink.put((byte) i);
- VarInt.putVarInt(stats[i].count, sink);
- VarInt.putVarLong(stats[i].totalTime, sink);
- }
- }
- content = sink.position() > 0 ? Arrays.copyOf(sink.array(), sink.position()) : null;
- }
-
- public boolean isEmpty() {
- return content == null;
- }
-
- /**
- * Converts instance back into AggregateAttr[TASK_COUNT]. See constructor documentation for more
- * information.
- */
- public AggregateAttr[] toArray() {
- AggregateAttr[] stats = new AggregateAttr[TASK_COUNT];
- if (!isEmpty()) {
- ByteBuffer source = ByteBuffer.wrap(content);
- while (source.hasRemaining()) {
- byte id = source.get();
- int count = VarInt.getVarInt(source);
- long time = VarInt.getVarLong(source);
- stats[id] = new AggregateAttr(count, time);
- }
- }
- return stats;
- }
-
- /** Returns AggregateAttr instance for the given ProfilerTask value. */
- public AggregateAttr getAttr(ProfilerTask task) {
- if (isEmpty()) { return ZERO; }
- ByteBuffer source = ByteBuffer.wrap(content);
- byte id = (byte) task.ordinal();
- while (source.hasRemaining()) {
- if (id == source.get()) {
- int count = VarInt.getVarInt(source);
- long time = VarInt.getVarLong(source);
- return new AggregateAttr(count, time);
- } else {
- VarInt.getVarInt(source);
- VarInt.getVarLong(source);
- }
- }
- return ZERO;
- }
-
- /**
- * Returns cumulative time stored in this instance across whole
- * ProfilerTask dimension.
- */
- long getTotalTime() {
- if (isEmpty()) { return 0; }
- ByteBuffer source = ByteBuffer.wrap(content);
- long totalTime = 0;
- while (source.hasRemaining()) {
- source.get();
- VarInt.getVarInt(source);
- totalTime += VarInt.getVarLong(source);
- }
- return totalTime;
- }
- }
-
- /**
- * Container for the profile record information.
- *
- * <p> TODO(bazel-team): (2010) Current Task instance heap size is 72 bytes. And there are
- * millions of them. Consider trimming some attributes.
- */
- public final class Task implements Comparable<Task> {
- public final long threadId;
- public final int id;
- public final int parentId;
- public final long startTime;
- public final long durationNanos;
- public final ProfilerTask type;
- public final CompactStatistics stats;
- // Contains statistic for a task and all subtasks. Populated only for root tasks.
- public CompactStatistics aggregatedStats = null;
- // Subtasks are stored as an array for performance and memory utilization
- // reasons (we can easily deal with millions of those objects).
- public Task[] subtasks = NO_TASKS;
- final int descIndex;
- // Reference to the related task (e.g. ACTION_GRAPH->ACTION task relation).
- private Task relatedTask;
-
- Task(
- long threadId,
- int id,
- int parentId,
- long startTime,
- long durationNanos,
- ProfilerTask type,
- int descIndex,
- CompactStatistics stats) {
- this.threadId = threadId;
- this.id = id;
- this.parentId = parentId;
- this.startTime = startTime;
- this.durationNanos = durationNanos;
- this.type = type;
- this.descIndex = descIndex;
- this.stats = stats;
- relatedTask = null;
- }
-
- public String getDescription() {
- return descriptionList.get(descIndex);
- }
-
- public boolean hasStats() {
- return !stats.isEmpty();
- }
-
- public long getInheritedDuration() {
- return stats.getTotalTime();
- }
-
- public AggregateAttr[] getStatAttrArray() {
- Preconditions.checkNotNull(stats);
- return stats.toArray();
- }
-
- private void combineStats(int[] counts, long[] duration) {
- int ownIndex = type.ordinal();
- if (parentId != 0) {
- // Parent task already accounted for this task total duration. We need to adjust
- // for the inherited duration.
- duration[ownIndex] -= getInheritedDuration();
- }
- AggregateAttr[] ownStats = stats.toArray();
- for (int i = 0; i < TASK_COUNT; i++) {
- AggregateAttr attr = ownStats[i];
- if (attr != null) {
- counts[i] += attr.count;
- duration[i] += attr.totalTime;
- }
- }
- for (Task task : subtasks) {
- task.combineStats(counts, duration);
- }
- }
-
- /**
- * Calculates aggregated statistics covering all subtasks (including
- * nested ones). Must be called only for parent tasks.
- */
- void calculateRootStats() {
- Preconditions.checkState(parentId == 0);
- int[] counts = new int[TASK_COUNT];
- long[] duration = new long[TASK_COUNT];
- combineStats(counts, duration);
- AggregateAttr[] statArray = ProfileInfo.createEmptyStatArray();
- for (int i = 0; i < TASK_COUNT; i++) {
- statArray[i] = new AggregateAttr(counts[i], duration[i]);
- }
- this.aggregatedStats = new CompactStatistics(statArray);
- }
-
- @Override
- public boolean equals(Object o) {
- return (o instanceof ProfileInfo.Task) && ((Task) o).id == this.id;
- }
-
- @Override
- public int hashCode() {
- return this.id;
- }
-
- @Override
- public String toString() {
- return type + "(" + id + "," + getDescription() + ")";
- }
-
- /**
- * Tasks records by default sorted by their id. Since id was obtained using
- * AtomicInteger, this comparison will correctly sort tasks in time-ascending
- * order regardless of their origin thread.
- */
- @Override
- public int compareTo(Task task) {
- return this.id - task.id;
- }
- }
-
- /**
- * Helper class to create space-efficient task multimap, used to associate
- * array of tasks with specific key.
- */
- private abstract static class TaskMapCreator<K> implements Comparator<Task> {
- @Override
- public abstract int compare(Task a, Task b);
- public abstract K getKey(Task task);
-
- public Map<K, Task[]> createTaskMap(List<Task> taskList) {
- // Created map usually will end up with thousands of entries, so we
- // preinitialize it to the 10000.
- Map<K, Task[]> taskMap = Maps.newHashMapWithExpectedSize(10000);
- if (taskList.isEmpty()) {
- return taskMap;
- }
- Task[] taskArray = taskList.toArray(new Task[taskList.size()]);
- Arrays.sort(taskArray, this);
- K key = getKey(taskArray[0]);
- int start = 0;
- for (int i = 0; i < taskArray.length; i++) {
- K currentKey = getKey(taskArray[i]);
- if (!key.equals(currentKey)) {
- taskMap.put(key, Arrays.copyOfRange(taskArray, start, i));
- key = currentKey;
- start = i;
- }
- }
- if (start < taskArray.length) {
- taskMap.put(key, Arrays.copyOfRange(taskArray, start, taskArray.length));
- }
- return taskMap;
- }
- }
-
- /**
- * An interface to pass back profile loading and aggregation messages.
- */
- public interface InfoListener {
- void info(String text);
- void warn(String text);
- }
-
- private static final Task[] NO_TASKS = new Task[0];
- private static final AggregateAttr ZERO = new AggregateAttr(0, 0);
-
- public final String comment;
- private long minTaskStartTime = Long.MAX_VALUE;
- private boolean corruptedOrIncomplete = false;
-
- // TODO(bazel-team): (2010) In one case, this list took 277MB of heap. Ideally it should be
- // replaced with a trie.
- private final List<String> descriptionList;
- public final List<Task> allTasksById;
- public List<Task> rootTasksById; // Not final due to the late initialization.
- public final List<Task> phaseTasks;
-
- private ProfileInfo(String comment) {
- this.comment = comment;
-
- descriptionList = Lists.newArrayListWithExpectedSize(10000);
- allTasksById = Lists.newArrayListWithExpectedSize(50000);
- phaseTasks = Lists.newArrayList();
- }
-
- private void addTask(Task task) {
- allTasksById.add(task);
- minTaskStartTime = Math.min(minTaskStartTime, task.startTime);
- }
-
- /**
- * Returns true if profile datafile was corrupted or incomplete
- * and false otherwise.
- */
- public boolean isCorruptedOrIncomplete() {
- return corruptedOrIncomplete;
- }
-
- /**
- * Initializes minimum internal data structures necessary to obtain individual
- * task statistic. This method is sufficient to initialize data for dumping.
- */
- public void calculateStats() {
- if (allTasksById.isEmpty()) {
- return;
- }
-
- Collections.sort(allTasksById);
-
- Map<Integer, Task[]> subtaskMap = new TaskMapCreator<Integer>() {
- @Override
- public int compare(Task a, Task b) {
- return a.parentId != b.parentId ? a.parentId - b.parentId : a.compareTo(b);
- }
- @Override
- public Integer getKey(Task task) { return task.parentId; }
- }.createTaskMap(allTasksById);
- for (Task task : allTasksById) {
- Task[] subtasks = subtaskMap.get(task.id);
- if (subtasks != null) {
- task.subtasks = subtasks;
- }
- }
- rootTasksById = Arrays.asList(subtaskMap.get(0));
-
- for (Task task : rootTasksById) {
- task.calculateRootStats();
- if (task.type == ProfilerTask.PHASE) {
- if (!phaseTasks.isEmpty()) {
- phaseTasks.get(phaseTasks.size() - 1).relatedTask = task;
- }
- phaseTasks.add(task);
- }
- }
- }
-
- /**
- * Calculates cumulative time attributed to the specific task type.
- * Expects to be called only for root (parentId = 0) tasks.
- * calculateStats() must have been called first.
- */
- public AggregateAttr getStatsForType(ProfilerTask type, Collection<Task> tasks) {
- long totalTime = 0;
- int count = 0;
- for (Task task : tasks) {
- if (task.parentId > 0) {
- throw new IllegalArgumentException("task " + task.id + " is not a root task");
- }
- AggregateAttr attr = task.aggregatedStats.getAttr(type);
- count += attr.count;
- totalTime += attr.totalTime;
- if (task.type == type) {
- count++;
- totalTime += (task.durationNanos - task.getInheritedDuration());
- }
- }
- return new AggregateAttr(count, totalTime);
- }
-
- /**
- * Returns list of all root tasks related to (in other words, started during)
- * the specified phase task.
- */
- public List<Task> getTasksForPhase(Task phaseTask) {
- Preconditions.checkArgument(phaseTask.type == ProfilerTask.PHASE,
- "Unsupported task type %s", phaseTask.type);
-
- // Algorithm below takes into account fact that rootTasksById list is sorted
- // by the task id and task id values are monotonically increasing with time
- // (this property is guaranteed by the profiler). Thus list is effectively
- // sorted by the startTime. We are trying to select a sublist that includes
- // all tasks that were started later than the given task but earlier than
- // its completion time.
- int startIndex = Collections.binarySearch(rootTasksById, phaseTask);
- Preconditions.checkState(startIndex >= 0,
- "Phase task %s is not a root task", phaseTask.id);
- int endIndex = (phaseTask.relatedTask != null)
- ? Collections.binarySearch(rootTasksById, phaseTask.relatedTask)
- : rootTasksById.size();
- Preconditions.checkState(endIndex >= startIndex,
- "Failed to find end of the phase marked by the task %s", phaseTask.id);
- return rootTasksById.subList(startIndex, endIndex);
- }
-
- /**
- * Returns task with "Build artifacts" description - corresponding to the
- * execution phase. Usually used to location ACTION_GRAPH task tree.
- */
- public Task getPhaseTask(ProfilePhase phase) {
- for (Task task : phaseTasks) {
- if (task.getDescription().equals(phase.description)) {
- return task;
- }
- }
- return null;
- }
-
- /**
- * Returns duration of the given phase in ns.
- */
- public long getPhaseDuration(Task phaseTask) {
- Preconditions.checkArgument(phaseTask.type == ProfilerTask.PHASE,
- "Unsupported task type %s", phaseTask.type);
-
- long duration;
- if (phaseTask.relatedTask != null) {
- duration = phaseTask.relatedTask.startTime - phaseTask.startTime;
- } else {
- Task lastTask = rootTasksById.get(rootTasksById.size() - 1);
- duration = lastTask.startTime + lastTask.durationNanos - phaseTask.startTime;
- }
- Preconditions.checkState(duration >= 0);
- return duration;
- }
-
- /**
- * Returns an empty array used to store task statistics. Array index
- * corresponds to the ProfilerTask ordinal() value associated with the
- * given statistic. Absent statistics are stored as null.
- * <p>
- * In essence, it is a fast equivalent of Map<ProfilerTask, AggregateAttr>.
- */
- public static AggregateAttr[] createEmptyStatArray() {
- return new AggregateAttr[TASK_COUNT];
- }
-
- /**
- * Loads and parses Blaze profile file.
- *
- * @param profileStream profile file path
- *
- * @return ProfileInfo object with some fields populated (call calculateStats()
- * and analyzeRelationships() to populate the remaining fields)
- * @throws UnsupportedEncodingException if the file format is invalid
- * @throws IOException if the file can't be read
- */
- public static ProfileInfo loadProfile(InputStream profileStream) throws IOException {
- // It is extremely important to wrap InflaterInputStream using BufferedInputStream because
- // the majority of reads would be done using readInt()/readLong() methods and
- // InflaterInputStream is very inefficient in handling small read requests (performance
- // difference with 1MB buffer used below is almost 10x).
- DataInputStream in =
- new DataInputStream(
- new BufferedInputStream(
- new InflaterInputStream(profileStream, new Inflater(false), 65536), 1024 * 1024));
-
- if (in.readInt() != Profiler.MAGIC) {
- in.close();
- throw new UnsupportedEncodingException("Invalid profile datafile format");
- }
- if (in.readInt() != Profiler.VERSION) {
- in.close();
- throw new UnsupportedEncodingException("Incompatible profile datafile version");
- }
- String fileComment = in.readUTF();
-
- // Read list of used record types
- int typeCount = in.readInt();
- boolean hasUnknownTypes = false;
- Set<String> supportedTasks = new HashSet<>();
- for (ProfilerTask task : ProfilerTask.values()) {
- supportedTasks.add(task.toString());
- }
- List<ProfilerTask> typeList = new ArrayList<>();
- for (int i = 0; i < typeCount; i++) {
- String name = in.readUTF();
- if (supportedTasks.contains(name)) {
- typeList.add(ProfilerTask.valueOf(name));
- } else {
- hasUnknownTypes = true;
- typeList.add(ProfilerTask.UNKNOWN);
- }
- }
-
- ProfileInfo info = new ProfileInfo(fileComment);
-
- // Read record until we encounter end marker (-1).
- // TODO(bazel-team): Maybe this still should handle corrupted(truncated) files.
- try {
- int size;
- while ((size = in.readInt()) != Profiler.EOF_MARKER) {
- byte[] backingArray = new byte[size];
- in.readFully(backingArray);
- ByteBuffer buffer = ByteBuffer.wrap(backingArray);
- long threadId = VarInt.getVarLong(buffer);
- int id = VarInt.getVarInt(buffer);
- int parentId = VarInt.getVarInt(buffer);
- long startTime = VarInt.getVarLong(buffer);
- long duration = VarInt.getVarLong(buffer);
- int descIndex = VarInt.getVarInt(buffer) - 1;
- if (descIndex == -1) {
- String desc = in.readUTF();
- descIndex = info.descriptionList.size();
- info.descriptionList.add(desc);
- }
- ProfilerTask type = typeList.get(buffer.get());
- byte[] stats = null;
- if (buffer.hasRemaining()) {
- // Copy aggregated stats.
- int offset = buffer.position();
- stats = Arrays.copyOfRange(backingArray, offset, size);
- if (hasUnknownTypes) {
- while (buffer.hasRemaining()) {
- byte attrType = buffer.get();
- if (typeList.get(attrType) == ProfilerTask.UNKNOWN) {
- // We're dealing with unknown aggregated type - update stats array to
- // use ProfilerTask.UNKNOWN.ordinal() value.
- stats[buffer.position() - 1 - offset] = (byte) ProfilerTask.UNKNOWN.ordinal();
- }
- VarInt.getVarInt(buffer);
- VarInt.getVarLong(buffer);
- }
- }
- }
- ProfileInfo.Task task = info.new Task(threadId, id, parentId, startTime, duration, type,
- descIndex, new CompactStatistics(stats));
- info.addTask(task);
- }
- } catch (IOException e) {
- info.corruptedOrIncomplete = true;
- } finally {
- in.close();
- }
-
- return info;
- }
-
- /**
- * Loads and parses Blaze profile file, and reports what it is doing.
- *
- * @param profileFile profile file path
- * @param reporter for progress messages and warnings
- *
- * @return ProfileInfo object with most fields populated
- * (call analyzeRelationships() to populate the remaining fields)
- * @throws UnsupportedEncodingException if the file format is invalid
- * @throws IOException if the file can't be read
- */
- public static ProfileInfo loadProfileVerbosely(Path profileFile, InfoListener reporter)
- throws IOException {
- reporter.info("Loading " + profileFile.getPathString());
- ProfileInfo profileInfo;
- try (InputStream in = profileFile.getInputStream()) {
- profileInfo = ProfileInfo.loadProfile(in);
- }
- if (profileInfo.isCorruptedOrIncomplete()) {
- reporter.warn("Profile file is incomplete or corrupted - not all records were parsed");
- }
- reporter.info(profileInfo.comment + ", " + profileInfo.allTasksById.size() + " record(s)");
- return profileInfo;
- }
-
- /*
- * Sorts and aggregates Blaze profile file, and reports what it is doing.
- */
- public static void aggregateProfile(ProfileInfo profileInfo, InfoListener reporter) {
- reporter.info("Aggregating task statistics");
- profileInfo.calculateStats();
- }
-
-}
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/output/PhaseText.java b/src/main/java/com/google/devtools/build/lib/profiler/output/PhaseText.java
index 7472fc0..3a70b21 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/output/PhaseText.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/output/PhaseText.java
@@ -13,58 +13,33 @@
// limitations under the License.
package com.google.devtools.build.lib.profiler.output;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.profiler.ProfilePhase;
-import com.google.devtools.build.lib.profiler.ProfilerTask;
import com.google.devtools.build.lib.profiler.statistics.CriticalPathStatistics;
-import com.google.devtools.build.lib.profiler.statistics.PhaseStatistics;
import com.google.devtools.build.lib.profiler.statistics.PhaseSummaryStatistics;
-import com.google.devtools.build.lib.util.TimeUtilities;
import java.io.PrintStream;
import java.time.Duration;
-import java.util.Arrays;
-import java.util.EnumMap;
-/** Output {@link PhaseSummaryStatistics} and {@link PhaseStatistics} in text format. */
+/** Output {@link PhaseSummaryStatistics} and {@link CriticalPathStatistics} in text format. */
public final class PhaseText extends TextPrinter {
private final PhaseSummaryStatistics phaseSummaryStats;
- private final Optional<EnumMap<ProfilePhase, PhaseStatistics>> phaseStatistics;
- private final Optional<CriticalPathStatistics> criticalPathStatistics;
+ private final CriticalPathStatistics criticalPathStatistics;
public PhaseText(
PrintStream out,
PhaseSummaryStatistics phaseSummaryStats,
- Optional<EnumMap<ProfilePhase, PhaseStatistics>> phaseStatistics,
- Optional<CriticalPathStatistics> critPathStats) {
+ CriticalPathStatistics criticalPathStatistics) {
super(out);
this.phaseSummaryStats = phaseSummaryStats;
- this.phaseStatistics = phaseStatistics;
- this.criticalPathStatistics = critPathStats;
+ this.criticalPathStatistics = criticalPathStatistics;
}
public void print() {
printPhaseSummaryStatistics();
- if (phaseStatistics.isPresent()) {
- for (ProfilePhase phase :
- Arrays.asList(ProfilePhase.INIT, ProfilePhase.LOAD, ProfilePhase.ANALYZE)) {
- PhaseStatistics statistics = phaseStatistics.get().get(phase);
- if (statistics.wasExecuted()) {
- printPhaseStatistics(statistics);
- }
- }
-
- printExecutionPhaseStatistics();
- }
-
- CriticalPathText criticalPaths = null;
- if (criticalPathStatistics.isPresent()) {
- criticalPaths = new CriticalPathText(out, criticalPathStatistics.get());
- criticalPaths.printCriticalPaths();
- printLn();
- }
+ CriticalPathText criticalPaths = new CriticalPathText(out, criticalPathStatistics);
+ criticalPaths.printCriticalPaths();
+ printLn();
}
/**
@@ -92,74 +67,5 @@
"100.00%");
printLn();
}
-
- /**
- * Prints all statistics from {@link PhaseStatistics} in text form.
- */
- private void printPhaseStatistics(PhaseStatistics stats) {
- lnPrintf("=== %s PHASE INFORMATION ===\n", stats.getProfilePhase().nick.toUpperCase());
-
- lnPrintf(
- TWO_COLUMN_FORMAT,
- "Total " + stats.getProfilePhase().nick + " phase time",
- TimeUtilities.prettyTime(stats.getPhaseDurationNanos()));
- printLn();
-
- if (!stats.isEmpty()) {
- printTimingDistribution(stats);
- }
- }
-
- private void printExecutionPhaseStatistics() {
- Preconditions.checkArgument(phaseStatistics.isPresent());
- PhaseStatistics prepPhase = phaseStatistics.get().get(ProfilePhase.PREPARE);
- PhaseStatistics execPhase = phaseStatistics.get().get(ProfilePhase.EXECUTE);
- PhaseStatistics finishPhase = phaseStatistics.get().get(ProfilePhase.FINISH);
- if (!execPhase.wasExecuted()) {
- return;
- }
- lnPrint("=== EXECUTION PHASE INFORMATION ===\n");
-
- long execTime = execPhase.getPhaseDurationNanos();
-
- if (prepPhase.wasExecuted()) {
- lnPrintf(
- TWO_COLUMN_FORMAT,
- "Total preparation time",
- TimeUtilities.prettyTime(prepPhase.getPhaseDurationNanos()));
- }
- lnPrintf(
- TWO_COLUMN_FORMAT,
- "Total execution phase time",
- TimeUtilities.prettyTime(execPhase.getPhaseDurationNanos()));
- if (finishPhase.wasExecuted()) {
- lnPrintf(
- TWO_COLUMN_FORMAT,
- "Total time finalizing build",
- TimeUtilities.prettyTime(finishPhase.getPhaseDurationNanos()));
- }
- printLn();
- lnPrintf(TWO_COLUMN_FORMAT, "Actual execution time", TimeUtilities.prettyTime(execTime));
-
- printTimingDistribution(execPhase);
- printLn();
- }
-
- /**
- * Prints a table of task types and their relative total and average execution time as well as
- * how many tasks of each type there were
- */
- private void printTimingDistribution(PhaseStatistics stats) {
- lnPrint("Total time (across all threads) spent on:");
- lnPrintf("%18s %8s %8s %11s", "Type", "Total", "Count", "Average");
- for (ProfilerTask type : stats) {
- lnPrintf(
- "%18s %8s %8d %11s",
- type.toString(),
- prettyPercentage(stats.getTotalRelativeDuration(type)),
- stats.getCount(type),
- TimeUtilities.prettyTime(stats.getMeanDuration(type)));
- }
- }
}
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/output/TextPrinter.java b/src/main/java/com/google/devtools/build/lib/profiler/output/TextPrinter.java
index 7e08172..5e428ff 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/output/TextPrinter.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/output/TextPrinter.java
@@ -20,7 +20,6 @@
*/
public abstract class TextPrinter {
- protected static final String TWO_COLUMN_FORMAT = "%-37s %10s";
protected static final String THREE_COLUMN_FORMAT = "%-28s %10s %8s";
protected final PrintStream out;
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/statistics/CriticalPathStatistics.java b/src/main/java/com/google/devtools/build/lib/profiler/statistics/CriticalPathStatistics.java
index 63e4983..a4b50c7 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/statistics/CriticalPathStatistics.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/statistics/CriticalPathStatistics.java
@@ -13,43 +13,20 @@
// limitations under the License.
package com.google.devtools.build.lib.profiler.statistics;
-import static com.google.devtools.build.lib.profiler.ProfilerTask.CRITICAL_PATH;
-
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.profiler.ProfilerTask;
import com.google.devtools.build.lib.profiler.TraceEvent;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo.Task;
import java.time.Duration;
import java.util.List;
/**
- * Keeps a predefined list of {@link Task}'s cumulative durations and allows iterating over pairs of
- * their descriptions and relative durations.
+ * Keeps a predefined list of {@link TraceEvent}'s cumulative durations and allows iterating over
+ * pairs of their descriptions and relative durations.
*/
public final class CriticalPathStatistics {
private final ImmutableList<TraceEvent> criticalPathEntries;
private Duration totalDuration = Duration.ZERO;
- public CriticalPathStatistics(ProfileInfo info) {
- ImmutableList.Builder<TraceEvent> criticalPathEntriesBuilder = new ImmutableList.Builder<>();
- for (Task task : info.rootTasksById) {
- if (task.type == CRITICAL_PATH) {
- for (Task criticalPathEntry : task.subtasks) {
- totalDuration = totalDuration.plus(Duration.ofNanos(criticalPathEntry.durationNanos));
- criticalPathEntriesBuilder.add(
- TraceEvent.create(
- ProfilerTask.CRITICAL_PATH_COMPONENT.description,
- criticalPathEntry.getDescription(),
- Duration.ofNanos(criticalPathEntry.startTime),
- Duration.ofNanos(criticalPathEntry.durationNanos),
- criticalPathEntry.threadId));
- }
- }
- }
- this.criticalPathEntries = criticalPathEntriesBuilder.build();
- }
-
public CriticalPathStatistics(List<TraceEvent> traceEvents) {
ImmutableList.Builder<TraceEvent> criticalPathEntriesBuilder = new ImmutableList.Builder<>();
for (TraceEvent traceEvent : traceEvents) {
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseStatistics.java b/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseStatistics.java
deleted file mode 100644
index 607821b..0000000
--- a/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseStatistics.java
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2015 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.statistics;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterators;
-import com.google.devtools.build.lib.profiler.ProfilePhase;
-import com.google.devtools.build.lib.profiler.ProfilerTask;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo.AggregateAttr;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo.Task;
-import java.util.EnumMap;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Extracts and keeps statistics for one {@link ProfilePhase} for formatting to various outputs.
- */
-public final class PhaseStatistics implements Iterable<ProfilerTask> {
-
- private final ProfilePhase phase;
- private long phaseDurationNanos;
- private long totalDurationNanos;
- private final EnumMap<ProfilerTask, Long> taskDurations;
- private final EnumMap<ProfilerTask, Long> taskCounts;
- private boolean wasExecuted;
-
- public PhaseStatistics(ProfilePhase phase) {
- this.phase = phase;
- this.taskDurations = new EnumMap<>(ProfilerTask.class);
- this.taskCounts = new EnumMap<>(ProfilerTask.class);
- }
-
- public PhaseStatistics(ProfilePhase phase, ProfileInfo info) {
- this(phase);
- addProfileInfo(info);
- }
-
- /** Add statistics from {@link ProfileInfo} to the ones already accumulated for this phase. */
- public void addProfileInfo(ProfileInfo info) {
- Task phaseTask = info.getPhaseTask(phase);
- if (phaseTask != null) {
- wasExecuted = true;
- long infoPhaseDuration = info.getPhaseDuration(phaseTask);
- phaseDurationNanos += infoPhaseDuration;
- List<Task> taskList = info.getTasksForPhase(phaseTask);
- long duration = infoPhaseDuration;
- for (Task task : taskList) {
- // Tasks on the phaseTask thread already accounted for in the phaseDuration.
- if (task.threadId != phaseTask.threadId) {
- duration += task.durationNanos;
- }
- }
- totalDurationNanos += duration;
- for (ProfilerTask type : ProfilerTask.values()) {
- AggregateAttr attr = info.getStatsForType(type, taskList);
- long totalTime = Math.max(0, attr.totalTime);
- long count = Math.max(0, attr.count);
- add(taskCounts, type, count);
- add(taskDurations, type, totalTime);
- }
- }
- }
-
- /** Helper method to sum up long values within an {@link EnumMap}. */
- private static <T extends Enum<T>> void add(EnumMap<T, Long> map, T key, long value) {
- long previous;
- if (map.containsKey(key)) {
- previous = map.get(key);
- } else {
- previous = 0;
- }
- map.put(key, previous + value);
- }
-
- public ProfilePhase getProfilePhase() {
- return phase;
- }
-
- /**
- * @return true if no {@link ProfilerTask}s have been executed in this phase, false otherwise
- */
- public boolean isEmpty() {
- return taskCounts.isEmpty();
- }
-
- /** @return true if the phase was not executed at all, false otherwise */
- public boolean wasExecuted() {
- return wasExecuted;
- }
-
- /** @return true if a task of the given {@link ProfilerTask} type was executed in this phase */
- public boolean wasExecuted(ProfilerTask taskType) {
- Long count = taskCounts.get(taskType);
- return count != null && count != 0;
- }
-
- public long getPhaseDurationNanos() {
- return phaseDurationNanos;
- }
-
- /** @return the sum of all task durations of the given type */
- public long getTotalDurationNanos(ProfilerTask taskType) {
- Long duration = taskDurations.get(taskType);
- if (duration == null) {
- return 0;
- }
- return duration;
- }
-
- /**
- * @return the average duration of all {@link ProfilerTask}
- */
- public double getMeanDuration(ProfilerTask taskType) {
- if (wasExecuted(taskType)) {
- double duration = taskDurations.get(taskType);
- long count = taskCounts.get(taskType);
- return duration / count;
- }
- return 0;
- }
-
- /**
- * @return the duration of all {@link ProfilerTask} executed in the phase relative to the total
- * phase duration
- */
- public double getTotalRelativeDuration(ProfilerTask taskType) {
- Long duration = taskDurations.get(taskType);
- if (duration == null || duration == 0) {
- return 0;
- }
- // sanity check for broken profile files
- Preconditions.checkState(
- totalDurationNanos != 0,
- "Profiler tasks of type %s have non-zero duration %s in phase %s but the phase itself has"
- + " zero duration. Most likely the profile file is broken.",
- taskType,
- duration,
- phase);
- return (double) duration / totalDurationNanos;
- }
-
- /**
- * @return how many tasks of the given type were executed in this phase
- */
- public long getCount(ProfilerTask taskType) {
- Long count = taskCounts.get(taskType);
- if (count == null) {
- return 0;
- }
- return count;
- }
-
- /**
- * Iterator over all {@link ProfilerTask}s that were executed at least once and have a total
- * duration greater than 0.
- */
- @Override
- public Iterator<ProfilerTask> iterator() {
- return Iterators.filter(
- taskCounts.keySet().iterator(),
- taskType -> getTotalDurationNanos(taskType) > 0 && wasExecuted(taskType));
- }
-}
-
diff --git a/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseSummaryStatistics.java b/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseSummaryStatistics.java
index 2ce3025..8352b55 100644
--- a/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseSummaryStatistics.java
+++ b/src/main/java/com/google/devtools/build/lib/profiler/statistics/PhaseSummaryStatistics.java
@@ -14,7 +14,6 @@
package com.google.devtools.build.lib.profiler.statistics;
import com.google.devtools.build.lib.profiler.ProfilePhase;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo;
import java.time.Duration;
import java.util.EnumMap;
import java.util.Iterator;
@@ -34,23 +33,6 @@
totalDurationNanos = 0;
}
- public PhaseSummaryStatistics(ProfileInfo info) {
- this();
- addProfileInfo(info);
- }
-
- /** Add a summary of the {@link ProfilePhase}s durations from a {@link ProfileInfo}. */
- private void addProfileInfo(ProfileInfo info) {
- for (ProfilePhase phase : ProfilePhase.values()) {
- ProfileInfo.Task phaseTask = info.getPhaseTask(phase);
- if (phaseTask != null) {
- long phaseDuration = info.getPhaseDuration(phaseTask);
- totalDurationNanos += phaseDuration;
- durations.put(phase, phaseDuration);
- }
- }
- }
-
/** Add a single profile phase. */
public void addProfilePhase(ProfilePhase phase, Duration duration) {
totalDurationNanos += duration.toNanos();
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java
index 9b27c6d..310a199 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java
@@ -13,27 +13,16 @@
// limitations under the License.
package com.google.devtools.build.lib.runtime.commands;
-import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Reporter;
import com.google.devtools.build.lib.profiler.JsonProfile;
-import com.google.devtools.build.lib.profiler.ProfilePhase;
-import com.google.devtools.build.lib.profiler.ProfilerTask;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo;
-import com.google.devtools.build.lib.profiler.analysis.ProfileInfo.InfoListener;
import com.google.devtools.build.lib.profiler.output.PhaseText;
import com.google.devtools.build.lib.profiler.statistics.CriticalPathStatistics;
-import com.google.devtools.build.lib.profiler.statistics.PhaseStatistics;
-import com.google.devtools.build.lib.profiler.statistics.PhaseSummaryStatistics;
import com.google.devtools.build.lib.runtime.BlazeCommand;
import com.google.devtools.build.lib.runtime.BlazeCommandResult;
import com.google.devtools.build.lib.runtime.Command;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.util.ExitCode;
-import com.google.devtools.build.lib.util.StringUtil;
-import com.google.devtools.build.lib.util.TimeUtilities;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.common.options.Converters;
import com.google.devtools.common.options.Option;
@@ -47,7 +36,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
-import java.util.EnumMap;
/** Command line wrapper for analyzing Blaze build profiles. */
@Command(
@@ -81,22 +69,6 @@
public String dumpMode;
}
- private InfoListener getInfoListener(final CommandEnvironment env) {
- return new InfoListener() {
- private final EventHandler reporter = env.getReporter();
-
- @Override
- public void info(String text) {
- reporter.handle(Event.info(text));
- }
-
- @Override
- public void warn(String text) {
- reporter.handle(Event.warn(text));
- }
- };
- }
-
/**
* Note that this is just a basic check whether the file is zlib compressed.
*
@@ -126,7 +98,6 @@
try (PrintStream out = getOutputStream(env)) {
Reporter reporter = env.getReporter();
- InfoListener infoListener = getInfoListener(env);
reporter.handle(
Event.warn(
@@ -135,15 +106,11 @@
for (String name : options.getResidue()) {
Path profileFile = env.getWorkingDirectory().getRelative(name);
if (isOldBinaryProfile(profileFile.getPathFile())) {
- BlazeCommandResult commandResult =
- handleOldBinaryProfile(env, dumpMode, out, profileFile, infoListener);
- if (commandResult != null) {
- return commandResult;
- }
reporter.handle(
- Event.warn(
+ Event.error(
"The old binary profile format is deprecated."
+ " Use the JSON trace profile instead."));
+ return BlazeCommandResult.exitCode(ExitCode.PARSING_FAILURE);
} else {
try {
if (dumpMode != null) {
@@ -155,20 +122,20 @@
JsonProfile.BuildMetadata buildMetadata = jsonProfile.getBuildMetadata();
if (buildMetadata != null) {
- infoListener.info(
- "Profile created on "
- + buildMetadata.date()
- + ", build ID: "
- + buildMetadata.buildId()
- + ", output base: "
- + buildMetadata.outputBase());
+ reporter.handle(
+ Event.info(
+ "Profile created on "
+ + buildMetadata.date()
+ + ", build ID: "
+ + buildMetadata.buildId()
+ + ", output base: "
+ + buildMetadata.outputBase()));
}
new PhaseText(
out,
jsonProfile.getPhaseSummaryStatistics(),
- /* phaseStatistics= */ Optional.absent(),
- Optional.of(new CriticalPathStatistics(jsonProfile.getTraceEvents())))
+ new CriticalPathStatistics(jsonProfile.getTraceEvents()))
.print();
} catch (IOException e) {
reporter.handle(Event.error("Failed to analyze profile file(s): " + e.getMessage()));
@@ -180,116 +147,8 @@
return BlazeCommandResult.exitCode(ExitCode.SUCCESS);
}
- private static BlazeCommandResult handleOldBinaryProfile(
- CommandEnvironment env,
- String dumpMode,
- PrintStream out,
- Path profileFile,
- InfoListener infoListener) {
- try {
- ProfileInfo info = ProfileInfo.loadProfileVerbosely(profileFile, infoListener);
-
- if (dumpMode != null) {
- dumpProfile(info, out, dumpMode);
- return null;
- }
-
- ProfileInfo.aggregateProfile(info, infoListener);
- PhaseSummaryStatistics phaseSummaryStatistics = new PhaseSummaryStatistics(info);
- EnumMap<ProfilePhase, PhaseStatistics> phaseStatistics = new EnumMap<>(ProfilePhase.class);
-
- for (ProfilePhase phase : ProfilePhase.values()) {
- phaseStatistics.put(phase, new PhaseStatistics(phase, info));
- }
-
- new PhaseText(
- out,
- phaseSummaryStatistics,
- Optional.of(phaseStatistics),
- Optional.of(new CriticalPathStatistics(info)))
- .print();
- } catch (IOException e) {
- System.out.println(e);
- env.getReporter().handle(Event.error("Failed to analyze profile file(s): " + e.getMessage()));
- return BlazeCommandResult.exitCode(ExitCode.PARSING_FAILURE);
- }
- return null;
- }
-
private static PrintStream getOutputStream(CommandEnvironment env) {
return new PrintStream(
new BufferedOutputStream(env.getReporter().getOutErr().getOutputStream()), false);
}
-
- /** Dumps all tasks in the requested format. */
- private static void dumpProfile(ProfileInfo info, PrintStream out, String dumpMode) {
- if (dumpMode.contains("raw")) {
- for (ProfileInfo.Task task : info.allTasksById) {
- dumpRaw(task, out);
- }
- } else {
- for (ProfileInfo.Task task : info.rootTasksById) {
- dumpTask(task, out, 0);
- }
- }
- }
-
- /** Dumps the task information and all subtasks. */
- private static void dumpTask(ProfileInfo.Task task, PrintStream out, int indent) {
- StringBuilder builder =
- new StringBuilder(
- String.format(
- Joiner.on('\n')
- .join(
- "",
- "%s %s",
- "Thread: %-6d Id: %-6d Parent: %d",
- "Start time: %-12s Duration: %s"),
- task.type,
- task.getDescription(),
- task.threadId,
- task.id,
- task.parentId,
- TimeUtilities.prettyTime(task.startTime),
- TimeUtilities.prettyTime(task.durationNanos)));
- if (task.hasStats()) {
- builder.append("\n");
- ProfileInfo.AggregateAttr[] stats = task.getStatAttrArray();
- for (ProfilerTask type : ProfilerTask.values()) {
- ProfileInfo.AggregateAttr attr = stats[type.ordinal()];
- if (attr != null) {
- builder.append(type.toString().toLowerCase()).append("=(").
- append(attr.count).append(", ").
- append(TimeUtilities.prettyTime(attr.totalTime)).append(") ");
- }
- }
- }
- out.println(StringUtil.indent(builder.toString(), indent));
- for (ProfileInfo.Task subtask : task.subtasks) {
- dumpTask(subtask, out, indent + 1);
- }
- }
-
- private static void dumpRaw(ProfileInfo.Task task, PrintStream out) {
- StringBuilder aggregateString = new StringBuilder();
- ProfileInfo.AggregateAttr[] stats = task.getStatAttrArray();
- for (ProfilerTask type : ProfilerTask.values()) {
- ProfileInfo.AggregateAttr attr = stats[type.ordinal()];
- if (attr != null) {
- aggregateString.append(type.toString().toLowerCase()).append(",").
- append(attr.count).append(",").append(attr.totalTime).append(" ");
- }
- }
- out.println(
- Joiner.on('|')
- .join(
- task.threadId,
- task.id,
- task.parentId,
- task.startTime,
- task.durationNanos,
- aggregateString.toString().trim(),
- task.type,
- task.getDescription()));
- }
}