// Copyright 2017 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.benchmark; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.benchmark.codegenerator.CodeGenerator; import com.google.devtools.build.benchmark.codegenerator.CppCodeGenerator; import com.google.devtools.build.benchmark.codegenerator.JavaCodeGenerator; import com.google.devtools.build.lib.shell.CommandException; import java.io.IOException; import java.nio.file.Path; /** Class for running a build group with all build targets and getting performance results. */ class BuildGroupRunner { private static final String GENERATED_CODE_FOR_COPY_DIR = "GeneratedCodeForCopy"; private static final String GENERATED_CODE_DIR = "GeneratedCode"; private static final String BUILDER_DIR = "BuilderBazel"; private static final int REPEAT_TIMES = 3; private final Path workspace; private Builder builder = null; BuildGroupRunner(Path workspace) { this.workspace = workspace; } BuildGroupResult run(BenchmarkOptions opt) throws IOException, CommandException { BuildCase buildCase = new BazelBuildCase(); ImmutableList<BuildTargetConfig> buildTargetConfigs = buildCase.getBuildTargetConfigs(); ImmutableList<BuildEnvConfig> buildEnvConfigs = buildCase.getBuildEnvConfigs(); // Prepare builder (Bazel) prepareBuilder(); System.out.println("Done preparing builder."); // Get code versions (commit hashtag for Bazel) and datetimes ImmutableList<String> codeVersions = buildCase.getCodeVersions(builder, opt); ImmutableList<String> datetimes = builder.getDatetimeForCodeVersions(codeVersions); System.out.println("Ready to run benchmark for the following versions:"); for (String version : codeVersions) { System.out.println(version); } BuildGroupResult.Builder buildGroupResultBuilder = getBuildGroupResultBuilder(buildTargetConfigs, buildEnvConfigs, codeVersions, datetimes); for (int versionIndex = 0; versionIndex < codeVersions.size(); ++versionIndex) { String version = codeVersions.get(versionIndex); System.out.format("Benchmark for version %s started.\n", version); // Get builder binary (build Bazel binary) Path buildBinary = builder.getBuildBinary(version); // Repeat several times to calculate average result for (int t = 0; t < REPEAT_TIMES; ++t) { // Prepare generated code for build buildCase.prepareGeneratedCode( workspace.resolve(GENERATED_CODE_FOR_COPY_DIR), workspace.resolve(GENERATED_CODE_DIR)); // Target config for (int targetIndex = 0; targetIndex < buildTargetConfigs.size(); ++targetIndex) { System.out.println( "Started target: " + buildTargetConfigs.get(targetIndex).getDescription()); // Environment config for (int envIndex = 0; envIndex < buildEnvConfigs.size(); ++envIndex) { System.out.println("Started config: " + buildEnvConfigs.get(envIndex).getDescription()); double elapsedTime = buildSingleTargetAndGetElapsedTime( buildTargetConfigs, buildEnvConfigs, buildBinary, targetIndex, envIndex); // Store result buildGroupResultBuilder .getBuildTargetResultsBuilder(targetIndex) .getBuildEnvResultsBuilder(envIndex) .getResultsBuilder(versionIndex) .addResults(elapsedTime); } } } } return buildGroupResultBuilder.build(); } private double buildSingleTargetAndGetElapsedTime( ImmutableList<BuildTargetConfig> buildTargetConfigs, ImmutableList<BuildEnvConfig> buildEnvConfigs, Path buildBinary, int targetIndex, int envIndex) throws CommandException { BuildTargetConfig targetConfig = buildTargetConfigs.get(targetIndex); BuildEnvConfig envConfig = buildEnvConfigs.get(envIndex); // Clean if should if (envConfig.getCleanBeforeBuild()) { builder.clean(); } // Modify generated code if should (only this target) if (envConfig.getIncremental()) { String targetName = targetConfig.getBuildTarget(); targetName = targetName.substring(targetName.lastIndexOf('/') + 1, targetName.length()); CodeGenerator codeGenerator = new JavaCodeGenerator(); codeGenerator.modifyExistingProject( workspace.resolve(GENERATED_CODE_DIR) + codeGenerator.getDirSuffix(), ImmutableSet.of(targetName)); codeGenerator = new CppCodeGenerator(); codeGenerator.modifyExistingProject( workspace.resolve(GENERATED_CODE_DIR) + codeGenerator.getDirSuffix(), ImmutableSet.of(targetName)); } // Remove the first target since it's slow if (targetIndex == 0 && envIndex == 0) { buildTargetAndGetElapsedTime(buildBinary, envConfig, targetConfig); builder.clean(); } return buildTargetAndGetElapsedTime(buildBinary, envConfig, targetConfig); } private double buildTargetAndGetElapsedTime( Path buildBinary, BuildEnvConfig envConfig, BuildTargetConfig targetConfig) throws CommandException { // Run build double elapsedTime = builder.buildAndGetElapsedTime( buildBinary, builder.getCommandFromConfig(targetConfig, envConfig)); System.out.println(elapsedTime); return elapsedTime; } private static BuildGroupResult.Builder getBuildGroupResultBuilder( ImmutableList<BuildTargetConfig> buildTargetConfigs, ImmutableList<BuildEnvConfig> buildEnvConfigs, ImmutableList<String> codeVersions, ImmutableList<String> datetimes) { // Initialize a BuildGroupResult object to preserve array length BuildGroupResult.Builder buildGroupResultBuilder = BuildGroupResult.newBuilder(); for (BuildTargetConfig targetConfig : buildTargetConfigs) { BuildTargetResult.Builder targetBuilder = BuildTargetResult.newBuilder().setBuildTargetConfig(targetConfig); prepareBuildEnvConfigs(buildEnvConfigs, targetBuilder, codeVersions, datetimes); buildGroupResultBuilder.addBuildTargetResults(targetBuilder.build()); } return buildGroupResultBuilder; } private static void prepareBuildEnvConfigs( ImmutableList<BuildEnvConfig> buildEnvConfigs, BuildTargetResult.Builder targetBuilder, ImmutableList<String> codeVersions, ImmutableList<String> datetimes) { for (BuildEnvConfig envConfig : buildEnvConfigs) { BuildEnvResult.Builder envBuilder = BuildEnvResult.newBuilder().setConfig(envConfig); for (int i = 0; i < codeVersions.size(); ++i) { envBuilder.addResults( SingleBuildResult.newBuilder() .setCodeVersion(codeVersions.get(i)) .setDatetime(datetimes.get(i)) .build()); } targetBuilder.addBuildEnvResults(envBuilder.build()); } } private void prepareBuilder() throws IOException, CommandException { builder = new BazelBuilder(workspace.resolve(GENERATED_CODE_DIR), workspace.resolve(BUILDER_DIR)); builder.prepare(); } }