-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
benchmark: add progress indicator to compare.js #10823
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have an opinion. I just use node ./compare.js | tee file.csv
and I know the benchmark I'm running fairly well. But I think you can do better in terms of code readability.
`${data.rate}, ${data.time}`); | ||
console.log(`"${job.binary}", "${job.filename}", "${conf}", ` + | ||
`${data.rate}, ${data.time}`); | ||
} else if (showProgress && data.type === 'config') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this code rather hard to read, I don't understand it so it is hard to be constructive, but maybe:
- reduce the amount of global variables.
- explain
lines
,runLines
andallLines
. - wrap complexity in a function.
When I made the original suggestion I more or less had in mind something like node's Example:
I'm not sure what, if any additional information placed after the end of the above indicator like the |
b8b0acc
to
a5519f1
Compare
@mscdex @AndreasMadsen I've updated the code to wrap the progress-related logic into a separate class and print a self-overwriting progress bar. PTAL. New demo: |
--runs 30 number of samples | ||
--filter pattern string to filter benchmark scripts | ||
--set variable=value set benchmark variable (can be repeated) | ||
--progress true|false show benchmark progress indicator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we just make it so that it can be enabled with just --progress
? We may need to specially check for it in the arg parsing since it doesn't have a value associated with it, I'm not sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The arg parser has some support, it defaults to true
when no value is passed. However it will always expect the next argument to be the value, even if it starts with --
. For example --process --runs 20
will not work. The feature is not used anywhere, it is just an implementation detail.
Looks better, but I'm thinking we will want to add some kind of labels if we're going to add more fields as it's not immediately obvious what those values represent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do prefer this, but I still don't have much of an opinion on it.
I left a few comments:
const kStartOfQueue = 0; | ||
|
||
const showProgress = cli.optional.progress === 'true'; | ||
var progress; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let
?
function pad(input, minLength, fill) { | ||
var result = input + ''; | ||
while (result.length < minLength) { | ||
result = fill + result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use return result + fill.repeat(Math.max(0, minLength - result.length))
.
startQueue(index) { | ||
this.kStartOfQueue = index; | ||
this.currentFile = this.queue[index].filename; | ||
this.interval = setInterval(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this interval required? It seams to me that all state updating functions calls updateProgress
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably to at least regularly update the elapsed time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, of cause!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, see the comments of interval
in the constructor.
@@ -128,6 +128,13 @@ Benchmark.prototype.http = function(options, cb) { | |||
|
|||
Benchmark.prototype._run = function() { | |||
const self = this; | |||
if (process.env.hasOwnProperty('NODE_RUN_BENCHMARK_PROGRESS')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: we could just always send this information when possible, e.g. replace with if (process.send)
. Conditionals that require a larger context knowledge are often hard to understand.
const percent = pad(Math.floor(completedRate * 100), 3, ' '); | ||
const caption = finished ? 'Done\n' : this.currentFile; | ||
return `[${getTime(diff)}|% ${percent}` + | ||
`| ${fraction(completedRuns, scheduledRuns)}` + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would make more sense if this was fraction(completedFiles, this.benchmarks.length)
.
a5519f1
to
ebd4922
Compare
@AndreasMadsen @mscdex I've added some labels and changed the parser to accept |
@@ -128,6 +128,11 @@ Benchmark.prototype.http = function(options, cb) { | |||
|
|||
Benchmark.prototype._run = function() { | |||
const self = this; | |||
sendResult({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check that this works when running benchmarks individually (for example node benchmark/url/url-format.js
), I don't think it will.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed & Fixed. Thanks for catching that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -3,6 +3,7 @@ | |||
const fork = require('child_process').fork; | |||
const path = require('path'); | |||
const CLI = require('./_cli.js'); | |||
const BenchmarkProgress = require('./_benchmark_progress'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I personally prefer to be explicit with .js
, but I don't think we have a rule.
Does anyone have any objections to just making |
On second thought, how does this work when there is an error in one of the benchmark scripts, or something else that also prints to stderr? |
No objections for it being the default |
@AndreasMadsen If we have benchmarks printing to stderr, I'd consider that a bug that should be fixed... |
@mscdex of cause, but I would like to be able to read the error such that I can fix it. |
@AndreasMadsen That typically won't be an issue since exceptions and the like will end on a newline, so nothing should be erased. |
@AndreasMadsen There are logic handling child processes exiting with non-zero exit code(both in common.js and compare.js) so the whole thing will be stopped when there are uncaught exceptions in a benchmark script. If the error happens when the benchmark is parsed(syntax error), or somewhere in If the error happens after |
@mscdex Don't have an opinion about making it a default (I always type a bunch of arguments when running compare.js so one more |
@joyeecheung I'm just viewing it in the same light as |
We can show |
@AndreasMadsen When would that ever be the case? |
@mscdex Would that not be the case if you run |
@AndreasMadsen Ah, I see what you're saying. Yes, implicitly enabling |
38f46dc
to
a5e5a4c
Compare
@AndreasMadsen Great idea! Updated to print progress by default when stderr is TTY and stdout is not. PTAL. |
Plan to land this if there is nothing else to be addressed. |
@mscdex Can I have a LGTM? |
* Print the progress bar and the current benchmark to stderr when stderr is TTY and stdout is not. * Allow cli arguments without values via setting.boolArgs * Add `--no-progress` option
a5e5a4c
to
e27fb9f
Compare
Squashed. One more CI before landing: https://ci.nodejs.org/job/node-test-pull-request/6112/ |
CI failure is unrelated. Landed in 60d77bd. |
* Print the progress bar and the current benchmark to stderr when stderr is TTY and stdout is not. * Allow cli arguments without values via setting.boolArgs * Add --no-progress option PR-URL: #10823 Fixes: #8659 Reviewed-By: Andreas Madsen <[email protected]>
* Print the progress bar and the current benchmark to stderr when stderr is TTY and stdout is not. * Allow cli arguments without values via setting.boolArgs * Add --no-progress option PR-URL: #10823 Fixes: #8659 Reviewed-By: Andreas Madsen <[email protected]>
Would require a backport PR to land on either v6 or v4 (if at all) |
Print statistics about scheduled runs, completed runs,
configurations, etc. to stderr.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
benchmark
Fixes: #8659
Didn't give too much thought about the format so any ideas would be definitely welcome!
Demo:
cc @AndreasMadsen @mscdex