From 40d77c56055cca89437b36bb5763a820ef931539 Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Tue, 6 Jun 2023 12:53:41 -0600 Subject: [PATCH] chore(core): build_bench tool (#19387) This is a quick tool that I've been using to build benchmarking builds for Deno. Usage: Build a benchmark `HEAD~1` and `origin/main` executable: ```sh deno run tools/build_bench.ts HEAD~1 origin/main ``` Build debug benchmark executables of the last three commits: ```sh deno run tools/build_bench.ts --profile debug HEAD HEAD~1 HEAD~2 ``` --- tools/build_bench.ts | 136 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 tools/build_bench.ts diff --git a/tools/build_bench.ts b/tools/build_bench.ts new file mode 100755 index 0000000000..dbbe029677 --- /dev/null +++ b/tools/build_bench.ts @@ -0,0 +1,136 @@ +#!/usr/bin/env -S deno run --unstable --allow-env --allow-read --allow-write --allow-run +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +import $ from "https://deno.land/x/dax@0.32.0/mod.ts"; + +if (Deno.args.length === 0) { + $.log( + "Usage: build_bench [-v] [--profile release|debug] commit1 [commit2 [comment3...]]", + ); + Deno.exit(1); +} + +const args = Deno.args.slice(); +let verbose = false; +if (args[0] == "-v") { + args.shift(); + verbose = true; +} + +let profile = "release"; +if (args[0] == "--profile") { + args.shift(); + profile = args.shift(); +} + +function exit(msg: string) { + $.logError(msg); + Deno.exit(1); +} + +// Make sure the .git dir exists +const gitDir = Deno.cwd() + "/.git"; +await Deno.stat(gitDir); + +async function runCommand(human: string, cmd) { + if (verbose) { + const out = await cmd.noThrow(); + if (out.code != 0) { + exit(human); + } + } else { + const out = await cmd.stdout("piped").stderr("piped").noThrow(); + if (out.code != 0) { + $.logLight("stdout"); + $.logGroup(); + $.log(out.stdout); + $.logGroupEnd(); + $.logLight("stderr"); + $.logGroup(); + $.log(out.stderr); + $.logGroupEnd(); + exit(human); + } + } +} + +async function buildGitCommit(progress, commit) { + const tempDir = $.path(await Deno.makeTempDir()); + + const gitInfo = + await $`git log --pretty=oneline --abbrev-commit -n1 ${commit}`.stdout( + "piped", + ).stderr("piped").noThrow(); + if (gitInfo.code != 0) { + $.log(gitInfo.stdout); + $.log(gitInfo.stderr); + exit(`Failed to get git info for commit ${commit}`); + } + + const hash = gitInfo.stdout.split(" ")[0]; + progress.message(`${commit} is ${hash}`); + + progress.message(`clone ${hash}`); + await runCommand( + `Failed to clone commit ${commit}`, + $`git clone ${gitDir} ${tempDir}`, + ); + + progress.message(`reset ${hash}`); + await runCommand( + `Failed to reset commit ${commit}`, + $`git reset --hard ${hash}`.cwd(tempDir), + ); + + progress.message(`build ${hash} (please wait)`); + const now = Date.now(); + const interval = setInterval(() => { + const elapsed = Math.round((Date.now() - now) / 1000); + progress.message(`build ${hash} (${elapsed}s)`); + }, 100); + try { + if (profile === "debug") { + await runCommand( + `Failed to build commit ${commit}`, + $`cargo build`.cwd(tempDir), + ); + } else { + await runCommand( + `Failed to build commit ${commit}`, + $`cargo build --profile ${profile}`.cwd(tempDir), + ); + } + } finally { + clearInterval(interval); + } + const elapsed = Math.round((Date.now() - now) / 1000); + + let file; + if (profile === "release") { + file = `deno-${hash}`; + } else { + file = `deno-${profile}-${hash}`; + } + progress.message(`copy ${hash}`); + await tempDir.join("target").join(profile).join("deno").copyFile(file); + + progress.message(`cleanup ${hash}`); + await tempDir.remove({ recursive: true }); + + progress.message("done"); + $.log(`Built ./${file} (${commit}) in ${elapsed}s: ${gitInfo.stdout}`); +} + +const promises = []; +for (const arg of args) { + if (verbose) { + promises.push(buildGitCommit({ message() {} }, arg)); + } else { + const progress = $.progress(`${arg}`); + promises.push(progress.with(async () => { + await buildGitCommit(progress, arg); + })); + } +} + +await Promise.all(promises);