| // Copyright 2023 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.skyframe; | |
| /** | |
| * Tracks the priority of node evaluations. | |
| * | |
| * <p>Prioritization has two goals: decrease the total walltime and minimize the number of inflight | |
| * nodes. The build graph has uneven depth. When the build is less CPU-bound due to available | |
| * parallelism, long sequential dependencies should be prioritized first so that they do not become | |
| * long poles in walltime. | |
| * | |
| * <p>Minimizing inflight nodes is desirable because they contribute to memory pressure. A high | |
| * inflight node count increases work done by the garbage collector and triggers cache clearing. | |
| * Assigning higher priority to nodes with a higher likelihood of completing, without further | |
| * fanout, helps to avoid these causes of poor performance. | |
| * | |
| * <p>Prioritization uses two runtime signals. | |
| * | |
| * <ul> | |
| * <li><i>depth</i>: the deeper a node, the more likely it is to be one that could be on a long | |
| * critical path of computations and the closer to leaf-level and the less likely it is to | |
| * cause further fanout. | |
| * <li><i>evaluationCount</i>: {@link SkyFunction}s are written to minimize restarts and they are | |
| * usually bounded for any node. The higher the evaluation count, the more likely the next | |
| * restart completes the node, reducing memory pressure. | |
| * </ul> | |
| * | |
| * <p>Prioritization also uses statically determined information. Certain types of nodes have high | |
| * fanout by design. These may be annotated using the {@link SkyKey#hasLowFanout} method. | |
| */ | |
| interface PriorityTracker { | |
| /** The priority with higher meaning more urgent. */ | |
| int getPriority(); | |
| /** | |
| * Current estimated depth. | |
| * | |
| * <p>Depth is initialized by adding one to parent depth. For heavy computations to prioritize | |
| * correctly, their reverse dependencies under transitive closure (excluding the root) should also | |
| * track depth. | |
| * | |
| * <p>8-bits is likely enough for this. It's an {@code int} because Java doesn't support | |
| * arithmetic operations on narrower types. | |
| */ | |
| int depth(); | |
| /** | |
| * Attempts to update the depth. | |
| * | |
| * <p>During evaluation, parent nodes initialize priority as one more than their own priority. | |
| * Since a node may have multiple parents, depth may increase during evaluation. | |
| */ | |
| void updateDepthIfGreater(int proposedDepth); | |
| /** Adds one to the evaluation count component of priority. */ | |
| void incrementEvaluationCount(); | |
| default int getChildDepth() { | |
| return depth() + 1; | |
| } | |
| } |