| // 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 com.google.common.util.concurrent.ListenableFuture; | |
| import com.google.devtools.build.lib.clock.Clock; | |
| import com.google.devtools.build.lib.runtime.BlazeService; | |
| import com.google.devtools.build.lib.skybridge.SkybridgeInterface; | |
| import com.google.errorprone.annotations.CanIgnoreReturnValue; | |
| import java.io.IOException; | |
| import java.io.OutputStream; | |
| import java.time.Duration; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Set; | |
| import java.util.UUID; | |
| import java.util.function.Predicate; | |
| import java.util.function.Supplier; | |
| /** | |
| * Interface for the Blaze internal profiler. Provides facility to report various Blaze tasks and | |
| * store them (asynchronously) in the file for future analysis. | |
| * | |
| * <p>Implemented as singleton so any caller should use Profiler.instance() to obtain reference. | |
| * | |
| * <p>Internally, profiler uses two data structures - ThreadLocal task stack to track nested tasks | |
| * and single ConcurrentLinkedQueue to gather all completed tasks. | |
| * | |
| * <p>Also, due to the nature of the provided functionality (instrumentation of all Blaze | |
| * components), build.lib.profiler package will be used by almost every other Blaze package, so | |
| * special attention should be paid to avoid any dependencies on the rest of the Blaze code, | |
| * including build.lib.util and build.lib.vfs. This is important because build.lib.util and | |
| * build.lib.vfs contain Profiler invocations and any dependency on those two packages would create | |
| * circular relationship. | |
| * | |
| * @see ProfilerTask enum for recognized task types. | |
| */ | |
| @SkybridgeInterface | |
| @SuppressWarnings("GoodTime") // This code is very performance sensitive. | |
| public interface TraceProfilerService extends BlazeService { | |
| /** File format. */ | |
| public final class Format { | |
| public static final Format JSON_TRACE_FILE_FORMAT = new Format(); | |
| public static final Format JSON_TRACE_FILE_COMPRESSED_FORMAT = new Format(); | |
| private Format() {} | |
| } | |
| /** Returns the nanoTime of the current profiler instance, or -1 if not active. */ | |
| long nanoTimeMaybe(); | |
| /** Returns true iff profiling is currently enabled. */ | |
| boolean isActive(); | |
| /** | |
| * Records the beginning of a task as specified, and returns a {@link SilentCloseable} instance | |
| * that ends the task. This lets the system do the work of ending the task, with the compiler | |
| * giving a warning if the returned instance is not closed. | |
| * | |
| * <p>Use of this method allows to support nested task monitoring. For tasks that are known to not | |
| * have any subtasks, logSimpleTask() should be used instead. | |
| * | |
| * <p>Use like this: | |
| * | |
| * <pre>{@code | |
| * try (SilentCloseable c = Profiler.instance().profile(type, "description")) { | |
| * // Your code here. | |
| * } | |
| * }</pre> | |
| * | |
| * @param type predefined task type - see ProfilerTask for available types. | |
| * @param description task description. May be stored until the end of the build. | |
| */ | |
| SilentCloseable profile(ProfilerTask type, String description); | |
| /** | |
| * Version of {@link #profile(ProfilerTask, String)} that avoids creating string unless actually | |
| * profiling. | |
| */ | |
| SilentCloseable profile(ProfilerTask type, Supplier<String> description); | |
| /** | |
| * Records the beginning of a task as specified, and returns a {@link SilentCloseable} instance | |
| * that ends the task. This lets the system do the work of ending the task, with the compiler | |
| * giving a warning if the returned instance is not closed. | |
| * | |
| * <p>Use of this method allows to support nested task monitoring. For tasks that are known to not | |
| * have any subtasks, logSimpleTask() should be used instead. | |
| * | |
| * <p>This is a convenience method that uses {@link ProfilerTask#INFO}. | |
| * | |
| * <p>Use like this: | |
| * | |
| * <pre>{@code | |
| * try (SilentCloseable c = Profiler.instance().profile("description")) { | |
| * // Your code here. | |
| * } | |
| * }</pre> | |
| * | |
| * @param description task description. May be stored until the end of the build. | |
| */ | |
| SilentCloseable profile(String description); | |
| /** | |
| * Used externally to submit simple task (one that does not have any subtasks). Depending on the | |
| * minDuration attribute of the task type, task may be just aggregated into the parent task and | |
| * not stored directly. | |
| * | |
| * @param startTimeNanos task start time (obtained through {@link Profiler#nanoTimeMaybe()}) | |
| * @param type task type | |
| * @param description task description. May be stored until the end of the build. | |
| */ | |
| void logSimpleTask(long startTimeNanos, ProfilerTask type, String description); | |
| /** | |
| * Used externally to submit simple task (one that does not have any subtasks). Depending on the | |
| * minDuration attribute of the task type, task may be just aggregated into the parent task and | |
| * not stored directly. | |
| * | |
| * <p>Note that start and stop time must both be acquired from the same clock instance. | |
| * | |
| * @param startTimeNanos task start time | |
| * @param stopTimeNanos task stop time | |
| * @param type task type | |
| * @param description task description. May be stored until the end of the build. | |
| */ | |
| void logSimpleTask( | |
| long startTimeNanos, long stopTimeNanos, ProfilerTask type, String description); | |
| /** | |
| * Used externally to submit simple task (one that does not have any subtasks). Depending on the | |
| * minDuration attribute of the task type, task may be just aggregated into the parent task and | |
| * not stored directly. | |
| * | |
| * @param startTimeNanos task start time (obtained through {@link Profiler#nanoTimeMaybe()}) | |
| * @param duration the duration of the task | |
| * @param type task type | |
| * @param description task description. May be stored until the end of the build. | |
| */ | |
| void logSimpleTaskDuration( | |
| long startTimeNanos, Duration duration, ProfilerTask type, String description); | |
| /** | |
| * Similar to logSimpleTaskDuration, specific for action-related tasks (such as ACTION or | |
| * CRITICAL_PATH_COMPONENT) that have additional information such as primary output path and | |
| * target label. | |
| */ | |
| default void logActionTaskDuration( | |
| long startTimeNanos, | |
| Duration duration, | |
| ProfilerTask type, | |
| String description, | |
| String mnemonic, | |
| String primaryOutput, | |
| String targetLabel, | |
| String configuration) { | |
| logSimpleTaskDuration(startTimeNanos, duration, type, description); | |
| } | |
| /** Used to log "events" happening at a specific time - tasks with zero duration. */ | |
| void logEventAtTime(long atTimeNanos, ProfilerTask type, String description); | |
| /** Used to log "events" - tasks with zero duration. */ | |
| void logEvent(ProfilerTask type, String description); | |
| /** Sets the heuristics for determining the filesystem type of a given path. */ | |
| void setVfsTypeHeuristics(Map<String, ? extends Predicate<? super String>> vfsTypeHeuristics); | |
| /** | |
| * Enable profiling. | |
| * | |
| * <p>Subsequent calls to beginTask/endTask will be recorded in the provided output stream. Please | |
| * note that stream performance is extremely important and buffered streams should be utilized. | |
| * | |
| * @param profiledTasks which of {@link ProfilerTask}s to track | |
| * @param stream output stream to store profile data. Note: passing unbuffered stream object | |
| * reference may result in significant performance penalties | |
| * @param recordAllDurations iff true, record all tasks regardless of their duration; otherwise | |
| * some tasks may get aggregated if they finished quick enough | |
| * @param clock a {@code BlazeClock.instance()} | |
| * @param execStartTimeNanos execution start time in nanos obtained from {@code clock.nanoTime()} | |
| */ | |
| void start( | |
| Set<ProfilerTask> profiledTasks, | |
| OutputStream stream, | |
| Format format, | |
| String outputBase, | |
| UUID buildID, | |
| boolean recordAllDurations, | |
| Clock clock, | |
| long execStartTimeNanos, | |
| boolean slimProfile, | |
| long slimProfileSizeLimit, | |
| boolean includePrimaryOutput, | |
| boolean includeTargetLabel, | |
| boolean includeConfiguration, | |
| boolean collectTaskHistograms) | |
| throws IOException; | |
| /** | |
| * Disable profiling and complete profile file creation. Subsequent calls to beginTask/endTask | |
| * will no longer be recorded in the profile. | |
| */ | |
| void stop() throws IOException; | |
| /** | |
| * Clears the records the profiler instance keeps. | |
| * | |
| * <p>Should always be called between a {@link #stop()} and a subsequent {@link #start}. | |
| */ | |
| void clear(); | |
| /** | |
| * Returns task histograms. This must be called between calls to {@link #start} and {@link #stop}, | |
| * or the returned recorders are all empty. Note that the returned recorders may still be modified | |
| * concurrently (but at least they are thread-safe, so that's good). | |
| * | |
| * <p>The stat recorders are indexed by {@code ProfilerTask#ordinal}. //TODO(b/458037154): Maybe | |
| * make the enums stable. | |
| */ | |
| List<StatRecorder> getTasksHistograms(); | |
| /** | |
| * Returns task histograms. This must be called between calls to {@link #start} and {@link #stop}, | |
| * or the returned list is empty. | |
| */ | |
| Iterable<SlowTask> getSlowestTasks(); | |
| boolean isProfiling(ProfilerTask type); | |
| /** Convenience method to log phase marker tasks. */ | |
| void markPhase(ProfilePhase phase) throws InterruptedException; | |
| /** | |
| * Similar to {@link #profile}, but specific to action-related events. Takes an extra argument: | |
| * primaryOutput. | |
| */ | |
| SilentCloseable profileAction( | |
| ProfilerTask type, | |
| String mnemonic, | |
| String description, | |
| String primaryOutput, | |
| String targetLabel, | |
| String configuration); | |
| /** | |
| * Records the end of a task as specified. | |
| * | |
| * @param startTimeNanos task start time | |
| * @param type task type | |
| * @param description task description | |
| */ | |
| void completeTask(long startTimeNanos, ProfilerTask type, String description); | |
| void registerCounterSeriesCollector(CounterSeriesCollector collector); | |
| void unregisterCounterSeriesCollector(CounterSeriesCollector collector); | |
| /** Adds a whole action count series to the writer bypassing histogram and subtask creation. */ | |
| void logCounters( | |
| Map<CounterSeriesTask, double[]> counterSeriesMap, | |
| Duration profileStart, | |
| Duration bucketDuration); | |
| Duration getProfileElapsedTime(); | |
| Duration getServerProcessCpuTime(); | |
| /** | |
| * Profiles a future. | |
| * | |
| * @param future the future to profile | |
| * @param prefix the prefix of the virtual lanes. Similar to the thread name prefix. | |
| * @param type task type | |
| * @param description task description. May be stored until the end of the build. | |
| */ | |
| @CanIgnoreReturnValue | |
| <T> ListenableFuture<T> profileFuture( | |
| ListenableFuture<T> future, String prefix, ProfilerTask type, String description); | |
| /** | |
| * Creates a profiler that can be used to profile async operations of a task. | |
| * | |
| * @param prefix the prefix of the virtual lanes. Similar to the thread name prefix. | |
| * @param description the description of task. | |
| */ | |
| AsyncProfiler profileAsync(String prefix, String description); | |
| /** Creates a time series with the given start time and bucket duration. */ | |
| TimeSeries createTimeSeries(Duration startTime, Duration bucketDuration); | |
| } |