// 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.devtools.build.lib.profiler.ProfileInfo; import com.google.devtools.build.lib.profiler.ProfilePhase; import java.util.EnumMap; import java.util.Iterator; import java.util.NoSuchElementException; /** * Extracts and keeps summary statistics from all {@link ProfilePhase}s for formatting to various * outputs. */ public final class PhaseSummaryStatistics implements Iterable<ProfilePhase> { private long totalDurationNanos; private final EnumMap<ProfilePhase, Long> durations; public PhaseSummaryStatistics() { durations = new EnumMap<>(ProfilePhase.class); totalDurationNanos = 0; } public PhaseSummaryStatistics(ProfileInfo info) { this(); addProfileInfo(info); } /** * Add a summary of the {@link ProfilePhase}s durations from a {@link ProfileInfo}. */ public 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); } } } /** * @return whether the given {@link ProfilePhase} was executed */ public boolean contains(ProfilePhase phase) { return durations.containsKey(phase); } /** * @return the execution duration of a given {@link ProfilePhase} * @throws NoSuchElementException if the given {@link ProfilePhase} was not executed */ public long getDurationNanos(ProfilePhase phase) { checkContains(phase); return durations.get(phase); } /** * @return The duration of the phase relative to the sum of all phase durations * @throws NoSuchElementException if the given {@link ProfilePhase} was not executed */ public double getRelativeDuration(ProfilePhase phase) { checkContains(phase); return (double) getDurationNanos(phase) / totalDurationNanos; } /** * Converts {@link #getRelativeDuration(ProfilePhase)} to a percentage string * @return formatted percentage string ("%.2f%%") or "N/A" when totalNanos is 0. * @throws NoSuchElementException if the given {@link ProfilePhase} was not executed */ public String getPrettyPercentage(ProfilePhase phase) { checkContains(phase); if (totalDurationNanos == 0) { // Return "not available" string if total is 0 and result is undefined. return "N/A"; } return String.format("%.2f%%", getRelativeDuration(phase) * 100); } public long getTotalDuration() { return totalDurationNanos; } @Override public Iterator<ProfilePhase> iterator() { return durations.keySet().iterator(); } private void checkContains(ProfilePhase phase) { if (!contains(phase)) { throw new NoSuchElementException("Phase " + phase + " was not executed"); } } }