From 40f36b9e0111ce76487f6f12e240545a0ea70003 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sat, 26 Sep 2020 00:56:00 +0100 Subject: [PATCH] improve `ufuzz` duty cycle heuristic (#4153) --- .github/workflows/ufuzz.yml | 9 ++-- test/ufuzz/actions.js | 64 +++++++++++++++------------- test/ufuzz/job.js | 84 +++++++++++++++++++++++-------------- 3 files changed, 90 insertions(+), 67 deletions(-) diff --git a/.github/workflows/ufuzz.yml b/.github/workflows/ufuzz.yml index 64b45565..ea37f5dd 100644 --- a/.github/workflows/ufuzz.yml +++ b/.github/workflows/ufuzz.yml @@ -6,6 +6,7 @@ on: env: BASE_URL: https://api.github.com/repos/${{ github.repository }} CAUSE: ${{ github.event_name }} + RUN_NUM: ${{ github.run_number }} TOKEN: ${{ github.token }} jobs: ufuzz: @@ -36,12 +37,8 @@ jobs: npm config set update-notifier false npm --version while !(npm install); do echo "'npm install' failed - retrying..."; done - PERIOD=-5000 if [[ $CAUSE == "schedule" ]]; then - PERIOD=`node test/ufuzz/actions $BASE_URL $TOKEN` - fi - if (( $PERIOD == 0 )); then - echo "too many jobs in queue - skipping..." + node test/ufuzz/job $BASE_URL $TOKEN $RUN_NUM else - node test/ufuzz/job $PERIOD + node test/ufuzz/job 5000 fi diff --git a/test/ufuzz/actions.js b/test/ufuzz/actions.js index a5cd0eb2..b4d8c86b 100644 --- a/test/ufuzz/actions.js +++ b/test/ufuzz/actions.js @@ -1,32 +1,42 @@ -require("../../tools/exit"); - var get = require("https").get; var parse = require("url").parse; -var base = process.argv[2]; -var token = process.argv[3]; -var queued = 0, total = 0, earliest, now = Date.now(); -process.on("beforeExit", function() { - if (queued > 3) { - process.stdout.write("0"); - } else { - var average = total > 2 && (now - earliest) / (total - 1); - process.stdout.write(Math.min(Math.max(20 * average, 2700000), 18000000).toFixed(0)); - } -}); -read(base + "/actions/workflows/ufuzz.yml/runs?event=schedule", function(reply) { - check(reply, "workflow_runs").filter(function(workflow) { - return /^(in_progress|queued|)$/.test(workflow.status); - }).forEach(function(workflow) { - read(workflow.jobs_url, function(reply) { - check(reply, "jobs").forEach(function(job) { - if (job.status == "queued") queued++; - total++; - var start = Date.parse(job.started_at); - if (!(earliest < start)) earliest = start; - }); + +var base, token, run_number, eldest = true; +exports.init = function(url, auth, num) { + base = url; + token = auth; + run_number = num; +}; +exports.should_stop = function(callback) { + read(base + "/actions/runs?per_page=100", function(reply) { + if (!reply || !Array.isArray(reply.workflow_runs)) return; + var runs = reply.workflow_runs.filter(function(workflow) { + return workflow.status != "completed"; + }).sort(function(a, b) { + return b.run_number - a.run_number; }); + if (runs.length < 10) return; + var found = false, remaining = 20; + (function next() { + if (!runs.length) return; + var workflow = runs.pop(); + if (workflow.run_number == run_number) found = true; + read(workflow.jobs_url, function(reply) { + if (!reply || !Array.isArray(reply.jobs)) return; + if (!reply.jobs.every(function(job) { + if (job.status == "completed") return true; + remaining--; + return found; + })) return; + if (remaining >= 0) { + next(); + } else { + callback(); + } + }); + })(); }); -}); +}; function read(url, callback) { var options = parse(url); @@ -44,7 +54,3 @@ function read(url, callback) { }); }); } - -function check(reply, field) { - return reply && Array.isArray(reply[field]) ? reply[field] : []; -} diff --git a/test/ufuzz/job.js b/test/ufuzz/job.js index 5d4add83..e4d9ece7 100644 --- a/test/ufuzz/job.js +++ b/test/ufuzz/job.js @@ -1,43 +1,63 @@ +var actions = require("./actions"); var child_process = require("child_process"); -var ping = 5 * 60 * 1000; -var period = +process.argv[2]; -var endTime = period < 0 ? period : Date.now() + period; -for (var i = 0; i < 2; i++) spawn(endTime); - -function spawn(endTime) { - var args = [ - "--max-old-space-size=2048", - "test/ufuzz" - ]; - if (endTime < 0) args.push(-endTime); - var child = child_process.spawn("node", args, { - stdio: [ "ignore", "pipe", "pipe" ] - }).on("exit", respawn); - var stdout = ""; - child.stdout.on("data", function(data) { - stdout += data; +var args = [ + "--max-old-space-size=2048", + "test/ufuzz", +]; +var iterations; +switch (process.argv.length) { + case 3: + iterations = +process.argv[2]; + args.push(iterations); + break; + case 5: + actions.init(process.argv[2], process.argv[3], +process.argv[4]); + break; + default: + throw new Error("invalid parameters"); +} +var tasks = [ run(), run() ]; +if (iterations) return; +var alive = setInterval(function() { + actions.should_stop(function() { + clearInterval(alive); + tasks.forEach(function(kill) { + kill(); + }); }); - var stderr = ""; - child.stderr.on("data", trap).pipe(process.stdout); - var keepAlive = setInterval(function() { - var end = stdout.lastIndexOf("\r"); - console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end)); - stdout = stdout.slice(end + 1); - }, ping); - if (endTime < 0) return; - var timer = setTimeout(function() { - clearInterval(keepAlive); +}, 8 * 60 * 1000); + +function run() { + var child, stdout, stderr, log; + spawn(); + return function() { + clearInterval(log); child.removeListener("exit", respawn); child.kill(); - }, endTime - Date.now()); + }; + + function spawn() { + child = child_process.spawn("node", args, { + stdio: [ "ignore", "pipe", "pipe" ] + }).on("exit", respawn); + stdout = ""; + child.stdout.on("data", function(data) { + stdout += data; + }); + stderr = ""; + child.stderr.on("data", trap).pipe(process.stdout); + log = setInterval(function() { + var end = stdout.lastIndexOf("\r"); + console.log(stdout.slice(stdout.lastIndexOf("\r", end - 1) + 1, end)); + stdout = stdout.slice(end + 1); + }, 5 * 60 * 1000); + } function respawn() { console.log(stdout.replace(/[^\r\n]*\r/g, "")); - clearInterval(keepAlive); - if (endTime < 0) return; - clearTimeout(timer); - spawn(endTime); + clearInterval(log); + if (!iterations) spawn(); } function trap(data) { -- 2.34.1