Skip to content

Cleanup & improvements to perf-tester #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 55 additions & 99 deletions ci/perf-tester/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ const { setFailed, startGroup, endGroup, debug } = require("@actions/core");
const { GitHub, context } = require("@actions/github");
const { exec } = require("@actions/exec");
const {
getInput,
config,
runBenchmark,
averageBenchmarks,
toDiff,
diffTable,
toBool,
} = require("./utils.js");

const benchmarkParallel = 2;
const benchmarkSerial = 2;
const benchmarkParallel = 4;
const benchmarkSerial = 4;
const runBenchmarks = async () => {
let results = [];
for (let i = 0; i < benchmarkSerial; i++) {
Expand All @@ -44,7 +43,10 @@ const runBenchmarks = async () => {
return averageBenchmarks(results);
};

async function run(octokit, context, token) {
const perfActionComment =
"<!-- this-is-an-automated-performance-comment-do-not-edit -->";

async function run(octokit, context) {
const { number: pull_number } = context.issue;

const pr = context.payload.pull_request;
Expand All @@ -61,9 +63,8 @@ async function run(octokit, context, token) {
`PR #${pull_number} is targetted at ${pr.base.ref} (${pr.base.sha})`
);

const buildScript = getInput("build-script");
startGroup(`[current] Build using '${buildScript}'`);
await exec(buildScript);
startGroup(`[current] Build using '${config.buildScript}'`);
await exec(config.buildScript);
endGroup();

startGroup(`[current] Running benchmark`);
Expand Down Expand Up @@ -104,8 +105,8 @@ async function run(octokit, context, token) {
}
endGroup();

startGroup(`[base] Build using '${buildScript}'`);
await exec(buildScript);
startGroup(`[base] Build using '${config.buildScript}'`);
await exec(config.buildScript);
endGroup();

startGroup(`[base] Running benchmark`);
Expand All @@ -118,10 +119,7 @@ async function run(octokit, context, token) {
collapseUnchanged: true,
omitUnchanged: false,
showTotal: true,
minimumChangeThreshold: parseInt(
getInput("minimum-change-threshold"),
10
),
minimumChangeThreshold: config.minimumChangeThreshold,
});

let outputRawMarkdown = false;
Expand All @@ -133,79 +131,58 @@ async function run(octokit, context, token) {

const comment = {
...commentInfo,
body:
markdownDiff +
'\n\n<a href="https://github.com/j-f1/performance-action"><sub>performance-action</sub></a>',
body: markdownDiff + "\n\n" + perfActionComment,
};

if (toBool(getInput("use-check"))) {
if (token) {
const finish = await createCheck(octokit, context);
await finish({
conclusion: "success",
output: {
title: `Compressed Size Action`,
summary: markdownDiff,
},
});
} else {
outputRawMarkdown = true;
startGroup(`Updating stats PR comment`);
let commentId;
try {
const comments = (await octokit.issues.listComments(commentInfo)).data;
for (let i = comments.length; i--; ) {
const c = comments[i];
if (c.user.type === "Bot" && c.body.includes(perfActionComment)) {
commentId = c.id;
break;
}
}
} else {
startGroup(`Updating stats PR comment`);
let commentId;
} catch (e) {
console.log("Error checking for previous comments: " + e.message);
}

if (commentId) {
console.log(`Updating previous comment #${commentId}`);
try {
const comments = (await octokit.issues.listComments(commentInfo))
.data;
for (let i = comments.length; i--; ) {
const c = comments[i];
if (
c.user.type === "Bot" &&
/<sub>[\s\n]*performance-action/.test(c.body)
) {
commentId = c.id;
break;
}
}
await octokit.issues.updateComment({
...context.repo,
comment_id: commentId,
body: comment.body,
});
} catch (e) {
console.log("Error checking for previous comments: " + e.message);
console.log("Error editing previous comment: " + e.message);
commentId = null;
}
}

if (commentId) {
console.log(`Updating previous comment #${commentId}`);
// no previous or edit failed
if (!commentId) {
console.log("Creating new comment");
try {
await octokit.issues.createComment(comment);
} catch (e) {
console.log(`Error creating comment: ${e.message}`);
console.log(`Submitting a PR review comment instead...`);
try {
await octokit.issues.updateComment({
...context.repo,
comment_id: commentId,
const issue = context.issue || pr;
await octokit.pulls.createReview({
owner: issue.owner,
repo: issue.repo,
pull_number: issue.number,
event: "COMMENT",
body: comment.body,
});
} catch (e) {
console.log("Error editing previous comment: " + e.message);
commentId = null;
}
}

// no previous or edit failed
if (!commentId) {
console.log("Creating new comment");
try {
await octokit.issues.createComment(comment);
} catch (e) {
console.log(`Error creating comment: ${e.message}`);
console.log(`Submitting a PR review comment instead...`);
try {
const issue = context.issue || pr;
await octokit.pulls.createReview({
owner: issue.owner,
repo: issue.repo,
pull_number: issue.number,
event: "COMMENT",
body: comment.body,
});
} catch (e) {
console.log("Error creating PR review.");
outputRawMarkdown = true;
}
console.log("Error creating PR review.");
outputRawMarkdown = true;
}
}
endGroup();
Expand All @@ -225,31 +202,10 @@ async function run(octokit, context, token) {
console.log("All done!");
}

// create a check and return a function that updates (completes) it
async function createCheck(octokit, context) {
const check = await octokit.checks.create({
...context.repo,
name: "Compressed Size",
head_sha: context.payload.pull_request.head.sha,
status: "in_progress",
});

return async (details) => {
await octokit.checks.update({
...context.repo,
check_run_id: check.data.id,
completed_at: new Date().toISOString(),
status: "completed",
...details,
});
};
}

(async () => {
try {
const token = getInput("repo-token", { required: true });
const octokit = new GitHub(token);
await run(octokit, context, token);
const octokit = new GitHub(process.env.GITHUB_TOKEN);
await run(octokit, context);
} catch (e) {
setFailed(e.message);
}
Expand Down
40 changes: 16 additions & 24 deletions ci/perf-tester/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,23 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

const fs = require("fs");
const { exec } = require("@actions/exec");

const getInput = (key) =>
({
"build-script": "make bootstrap benchmark_setup",
benchmark: "make -s run_benchmark",
"minimum-change-threshold": 5,
"use-check": "no",
"repo-token": process.env.GITHUB_TOKEN,
}[key]);
exports.getInput = getInput;
const formatMS = (ms) =>
`${ms.toLocaleString("en-US", {
maximumFractionDigits: 0,
})}ms`;

const config = {
buildScript: "make bootstrap benchmark_setup",
benchmark: "make -s run_benchmark",
minimumChangeThreshold: 5,
};
exports.config = config;

exports.runBenchmark = async () => {
let benchmarkBuffers = [];
await exec(getInput("benchmark"), [], {
await exec(config.benchmark, [], {
listeners: {
stdout: (data) => benchmarkBuffers.push(data),
},
Expand Down Expand Up @@ -88,8 +89,7 @@ exports.toDiff = (before, after) => {
* @param {number} difference
*/
function getDeltaText(delta, difference) {
let deltaText =
(delta > 0 ? "+" : "") + delta.toLocaleString("en-US") + "ms";
let deltaText = (delta > 0 ? "+" : "") + formatMS(delta);
if (delta && Math.abs(delta) > 1) {
deltaText += ` (${Math.abs(difference)}%)`;
}
Expand Down Expand Up @@ -183,7 +183,7 @@ exports.diffTable = (

const columns = [
name,
time.toLocaleString("en-US") + "ms",
formatMS(time),
getDeltaText(delta, difference),
iconForDifference(difference),
];
Expand All @@ -198,24 +198,16 @@ exports.diffTable = (

if (unChangedRows.length !== 0) {
const outUnchanged = markdownTable(unChangedRows);
out += `\n\n<details><summary>ℹ️ <strong>View Unchanged</strong></summary>\n\n${outUnchanged}\n\n</details>\n\n`;
out += `\n\n<details><summary><strong>View Unchanged</strong></summary>\n\n${outUnchanged}\n\n</details>\n\n`;
}

if (showTotal) {
const totalDifference = ((totalDelta / totalTime) * 100) | 0;
let totalDeltaText = getDeltaText(totalDelta, totalDifference);
let totalIcon = iconForDifference(totalDifference);
out = `**Total Time:** ${totalTime.toLocaleString(
"en-US"
)}ms\n\n${out}`;
out = `**Total Time:** ${formatMS(totalTime)}\n\n${out}`;
out = `**Time Change:** ${totalDeltaText} ${totalIcon}\n\n${out}`;
}

return out;
};

/**
* Convert a string "true"/"yes"/"1" argument value to a boolean
* @param {string} v
*/
exports.toBool = (v) => /^(1|true|yes)$/.test(v);