• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const readline = require('readline');
4
5function pad(input, minLength, fill) {
6  const result = String(input);
7  const padding = fill.repeat(Math.max(0, minLength - result.length));
8  return `${padding}${result}`;
9}
10
11function fraction(numerator, denominator) {
12  const fdenominator = String(denominator);
13  const fnumerator = pad(numerator, fdenominator.length, ' ');
14  return `${fnumerator}/${fdenominator}`;
15}
16
17function getTime(diff) {
18  const time = Math.ceil(diff[0] + diff[1] / 1e9);
19  const hours = pad(Math.floor(time / 3600), 2, '0');
20  const minutes = pad(Math.floor((time % 3600) / 60), 2, '0');
21  const seconds = pad((time % 3600) % 60, 2, '0');
22  return `${hours}:${minutes}:${seconds}`;
23}
24
25// A run is an item in the job queue: { binary, filename, iter }
26// A config is an item in the subqueue: { binary, filename, iter, configs }
27class BenchmarkProgress {
28  constructor(queue, benchmarks) {
29    this.queue = queue;  // Scheduled runs.
30    this.benchmarks = benchmarks;  // Filenames of scheduled benchmarks.
31    this.completedRuns = 0;  // Number of completed runs.
32    this.scheduledRuns = queue.length;  // Number of scheduled runs.
33    // Time when starting to run benchmarks.
34    this.startTime = process.hrtime();
35    // Number of times each file will be run (roughly).
36    this.runsPerFile = queue.length / benchmarks.length;
37    this.currentFile = '';  // Filename of current benchmark.
38    // Number of configurations already run for the current file.
39    this.completedConfig = 0;
40    // Total number of configurations for the current file
41    this.scheduledConfig = 0;
42  }
43
44  startQueue(index) {
45    this.kStartOfQueue = index;
46    this.currentFile = this.queue[index].filename;
47    this.interval = setInterval(() => {
48      if (this.completedRuns === this.scheduledRuns) {
49        clearInterval(this.interval);
50      } else {
51        this.updateProgress();
52      }
53    }, 1000);
54  }
55
56  startSubqueue(data, index) {
57    // This subqueue is generated by a new benchmark
58    if (data.name !== this.currentFile || index === this.kStartOfQueue) {
59      this.currentFile = data.name;
60      this.scheduledConfig = data.queueLength;
61    }
62    this.completedConfig = 0;
63    this.updateProgress();
64  }
65
66  completeConfig() {
67    this.completedConfig++;
68    this.updateProgress();
69  }
70
71  completeRun() {
72    this.completedRuns++;
73    this.updateProgress();
74  }
75
76  getProgress() {
77    // Get time as soon as possible.
78    const diff = process.hrtime(this.startTime);
79
80    const completedRuns = this.completedRuns;
81    const scheduledRuns = this.scheduledRuns;
82    const finished = completedRuns === scheduledRuns;
83
84    // Calculate numbers for fractions.
85    const runsPerFile = this.runsPerFile;
86    const completedFiles = Math.floor(completedRuns / runsPerFile);
87    const scheduledFiles = this.benchmarks.length;
88    const completedRunsForFile =
89      finished ? runsPerFile : completedRuns % runsPerFile;
90    const completedConfig = this.completedConfig;
91    const scheduledConfig = this.scheduledConfig;
92
93    // Calculate the percentage.
94    let runRate = 0;  // Rate of current incomplete run.
95    if (completedConfig !== scheduledConfig) {
96      runRate = completedConfig / scheduledConfig;
97    }
98    const completedRate = ((completedRuns + runRate) / scheduledRuns);
99    const percent = pad(Math.floor(completedRate * 100), 3, ' ');
100
101    const caption = finished ? 'Done\n' : this.currentFile;
102    return `[${getTime(diff)}|% ${percent}| ` +
103           `${fraction(completedFiles, scheduledFiles)} files | ` +
104           `${fraction(completedRunsForFile, runsPerFile)} runs | ` +
105           `${fraction(completedConfig, scheduledConfig)} configs]: ` +
106           `${caption} `;
107  }
108
109  updateProgress() {
110    if (!process.stderr.isTTY || process.stdout.isTTY) {
111      return;
112    }
113    readline.clearLine(process.stderr);
114    readline.cursorTo(process.stderr, 0);
115    process.stderr.write(this.getProgress());
116  }
117}
118
119module.exports = BenchmarkProgress;
120