// 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.collect.Maps; import com.google.common.collect.Multimap; import com.google.devtools.build.lib.profiler.analysis.ProfileInfo; import com.google.devtools.build.lib.profiler.analysis.ProfileInfo.Task; import com.google.devtools.build.lib.util.LongArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; /** * Extracts the execution times of user-defined and built-in Skylark functions and computes * statistics. * *

The statistics are separated for the total duration taken for a function call and the * "self duration" taken only within the function itself, but not within any subtask of the * corresponding {@link Task}. */ public final class SkylarkStatistics { private final Map userFunctionDurations; private final Map userCompiledDurations; private final Map builtinFunctionDurations; /** * Self duration is the time taken just within a function itself, but not other subtasks of it. */ private final Map userFunctionSelfDurations; private final Map userCompiledSelfDurations; private final Map builtinFunctionSelfDurations; private long userTotalNanos; private long userCompiledTotalNanos; private long builtinTotalNanos; public SkylarkStatistics() { userFunctionDurations = new HashMap<>(); userCompiledDurations = new HashMap<>(); builtinFunctionDurations = new HashMap<>(); userFunctionSelfDurations = new HashMap<>(); userCompiledSelfDurations = new HashMap<>(); builtinFunctionSelfDurations = new HashMap<>(); } public SkylarkStatistics(ProfileInfo info) { this(); addProfileInfo(info); } /** * Adds Skylark function task durations from a {@link ProfileInfo} file. */ public void addProfileInfo(ProfileInfo info) { computeStatistics( info.getSkylarkUserFunctionTasks(), info.getCompiledSkylarkUserFunctionTasks(), info.getSkylarkBuiltinFunctionTasks()); } /** * @return the total time taken by all calls to built-in Skylark functions */ public long getBuiltinTotalNanos() { return builtinTotalNanos; } /** * @return the total time taken by all calls to user-defined Skylark functions */ public long getCompiledUserTotalNanos() { return userCompiledTotalNanos; } /** * @return the total time taken by all calls to user-defined Skylark functions */ public long getUserTotalNanos() { return userTotalNanos; } /** * @return The execution durations of all calls to built-in Skylark functions. */ public Map getBuiltinFunctionDurations() { return builtinFunctionDurations; } /** * return The execution durations of all calls to built-in functions excluding the durations of * all subtasks. */ public Map getBuiltinFunctionSelfDurations() { return builtinFunctionSelfDurations; } /** * Builds and returns the {@link TasksStatistics} for the durations of each built-in function. * The return value is not cached and will be recomputed on another call. */ public Map getBuiltinFunctionStatistics() { return buildTasksStatistics(builtinFunctionDurations); } /** * Builds and returns the {@link TasksStatistics} for the self-times of each built-in function. * The return value is not cached and will be recomputed on another call. */ public Map getBuiltinFunctionSelfStatistics() { return buildTasksStatistics(builtinFunctionSelfDurations); } /** * @return The execution durations of all calls to user-defined Skylark functions. */ public Map getCompiledUserFunctionDurations() { return userCompiledDurations; } /** * return The execution durations of all calls to user-defined functions excluding the durations * of all subtasks. */ public Map getCompiledUserFunctionSelfDurations() { return userCompiledSelfDurations; } /** * Builds and returns the {@link TasksStatistics} for the durations of each user-defined * function. The return value is not cached and will be recomputed on another call. */ public Map getCompiledUserFunctionStatistics() { return buildTasksStatistics(userCompiledDurations); } /** * Builds and returns the {@link TasksStatistics} for the self-times of each user-defined * function. The return value is not cached and will be recomputed on another call. */ public Map getCompiledUserFunctionSelfStatistics() { return buildTasksStatistics(userCompiledSelfDurations); } /** * @return The execution durations of all calls to user-defined Skylark functions. */ public Map getUserFunctionDurations() { return userFunctionDurations; } /** * return The execution durations of all calls to user-defined functions excluding the durations * of all subtasks. */ public Map getUserFunctionSelfDurations() { return userFunctionSelfDurations; } /** * Builds and returns the {@link TasksStatistics} for the durations of each user-defined * function. The return value is not cached and will be recomputed on another call. */ public Map getUserFunctionStatistics() { return buildTasksStatistics(userFunctionDurations); } /** * Builds and returns the {@link TasksStatistics} for the self-times of each user-defined * function. The return value is not cached and will be recomputed on another call. */ public Map getUserFunctionSelfStatistics() { return buildTasksStatistics(userFunctionSelfDurations); } /** * For each Skylark function get the list of durations and self durations from the task maps. */ private void computeStatistics( Multimap userTasks, Multimap userCompiledTasks, Multimap builtinTasks) { userTotalNanos += addDurations(userTasks, userFunctionDurations, userFunctionSelfDurations); userCompiledTotalNanos += addDurations(userCompiledTasks, userCompiledDurations, userCompiledSelfDurations); builtinTotalNanos += addDurations(builtinTasks, builtinFunctionDurations, builtinFunctionSelfDurations); } /** * Add all new durations to previously collected durations for all functions mapped to tasks. * @return The sum of the execution times of all {@link Task} values in the map. */ private static long addDurations( Multimap functionTasks, Map durationsMap, Map selfDurationsMap) { long totalTime = 0; for (Map.Entry> entry : functionTasks.asMap().entrySet()) { String function = entry.getKey(); Collection tasks = entry.getValue(); LongArrayList durations; LongArrayList selfDurations; if (durationsMap.containsKey(function)) { durations = durationsMap.get(function); selfDurations = selfDurationsMap.get(function); } else { durations = new LongArrayList(tasks.size()); selfDurations = new LongArrayList(tasks.size()); durationsMap.put(function, durations); selfDurationsMap.put(function, selfDurations); } totalTime += addDurations(tasks, durations, selfDurations); } return totalTime; } /** * Add all durations and self-times of the given function to the maps. * @return The sum of the execution times of all {@link Task} values in the collection. */ private static long addDurations( Collection tasks, LongArrayList durations, LongArrayList selfDurations) { long totalTime = 0; durations.ensureCapacity(durations.size() + tasks.size()); selfDurations.ensureCapacity(selfDurations.size() + tasks.size()); for (Task task : tasks) { durations.add(task.durationNanos); selfDurations.add(task.durationNanos - task.getInheritedDuration()); totalTime += task.durationNanos; } return totalTime; } /** * Build a Map of {@link TasksStatistics} from the given duration maps. */ private static Map buildTasksStatistics( final Map durationsMap) { return Maps.transformEntries(durationsMap, TasksStatistics::create); } }