11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst readline = require('readline');
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_cifunction pad(input, minLength, fill) {
61cb0ef41Sopenharmony_ci  const result = String(input);
71cb0ef41Sopenharmony_ci  const padding = fill.repeat(Math.max(0, minLength - result.length));
81cb0ef41Sopenharmony_ci  return `${padding}${result}`;
91cb0ef41Sopenharmony_ci}
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cifunction fraction(numerator, denominator) {
121cb0ef41Sopenharmony_ci  const fdenominator = String(denominator);
131cb0ef41Sopenharmony_ci  const fnumerator = pad(numerator, fdenominator.length, ' ');
141cb0ef41Sopenharmony_ci  return `${fnumerator}/${fdenominator}`;
151cb0ef41Sopenharmony_ci}
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cifunction getTime(diff) {
181cb0ef41Sopenharmony_ci  const time = Math.ceil(diff[0] + diff[1] / 1e9);
191cb0ef41Sopenharmony_ci  const hours = pad(Math.floor(time / 3600), 2, '0');
201cb0ef41Sopenharmony_ci  const minutes = pad(Math.floor((time % 3600) / 60), 2, '0');
211cb0ef41Sopenharmony_ci  const seconds = pad((time % 3600) % 60, 2, '0');
221cb0ef41Sopenharmony_ci  return `${hours}:${minutes}:${seconds}`;
231cb0ef41Sopenharmony_ci}
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// A run is an item in the job queue: { binary, filename, iter }
261cb0ef41Sopenharmony_ci// A config is an item in the subqueue: { binary, filename, iter, configs }
271cb0ef41Sopenharmony_ciclass BenchmarkProgress {
281cb0ef41Sopenharmony_ci  constructor(queue, benchmarks) {
291cb0ef41Sopenharmony_ci    this.queue = queue;  // Scheduled runs.
301cb0ef41Sopenharmony_ci    this.benchmarks = benchmarks;  // Filenames of scheduled benchmarks.
311cb0ef41Sopenharmony_ci    this.completedRuns = 0;  // Number of completed runs.
321cb0ef41Sopenharmony_ci    this.scheduledRuns = queue.length;  // Number of scheduled runs.
331cb0ef41Sopenharmony_ci    // Time when starting to run benchmarks.
341cb0ef41Sopenharmony_ci    this.startTime = process.hrtime();
351cb0ef41Sopenharmony_ci    // Number of times each file will be run (roughly).
361cb0ef41Sopenharmony_ci    this.runsPerFile = queue.length / benchmarks.length;
371cb0ef41Sopenharmony_ci    this.currentFile = '';  // Filename of current benchmark.
381cb0ef41Sopenharmony_ci    // Number of configurations already run for the current file.
391cb0ef41Sopenharmony_ci    this.completedConfig = 0;
401cb0ef41Sopenharmony_ci    // Total number of configurations for the current file
411cb0ef41Sopenharmony_ci    this.scheduledConfig = 0;
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  startQueue(index) {
451cb0ef41Sopenharmony_ci    this.kStartOfQueue = index;
461cb0ef41Sopenharmony_ci    this.currentFile = this.queue[index].filename;
471cb0ef41Sopenharmony_ci    this.interval = setInterval(() => {
481cb0ef41Sopenharmony_ci      if (this.completedRuns === this.scheduledRuns) {
491cb0ef41Sopenharmony_ci        clearInterval(this.interval);
501cb0ef41Sopenharmony_ci      } else {
511cb0ef41Sopenharmony_ci        this.updateProgress();
521cb0ef41Sopenharmony_ci      }
531cb0ef41Sopenharmony_ci    }, 1000);
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  startSubqueue(data, index) {
571cb0ef41Sopenharmony_ci    // This subqueue is generated by a new benchmark
581cb0ef41Sopenharmony_ci    if (data.name !== this.currentFile || index === this.kStartOfQueue) {
591cb0ef41Sopenharmony_ci      this.currentFile = data.name;
601cb0ef41Sopenharmony_ci      this.scheduledConfig = data.queueLength;
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci    this.completedConfig = 0;
631cb0ef41Sopenharmony_ci    this.updateProgress();
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  completeConfig() {
671cb0ef41Sopenharmony_ci    this.completedConfig++;
681cb0ef41Sopenharmony_ci    this.updateProgress();
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  completeRun() {
721cb0ef41Sopenharmony_ci    this.completedRuns++;
731cb0ef41Sopenharmony_ci    this.updateProgress();
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  getProgress() {
771cb0ef41Sopenharmony_ci    // Get time as soon as possible.
781cb0ef41Sopenharmony_ci    const diff = process.hrtime(this.startTime);
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci    const completedRuns = this.completedRuns;
811cb0ef41Sopenharmony_ci    const scheduledRuns = this.scheduledRuns;
821cb0ef41Sopenharmony_ci    const finished = completedRuns === scheduledRuns;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci    // Calculate numbers for fractions.
851cb0ef41Sopenharmony_ci    const runsPerFile = this.runsPerFile;
861cb0ef41Sopenharmony_ci    const completedFiles = Math.floor(completedRuns / runsPerFile);
871cb0ef41Sopenharmony_ci    const scheduledFiles = this.benchmarks.length;
881cb0ef41Sopenharmony_ci    const completedRunsForFile =
891cb0ef41Sopenharmony_ci      finished ? runsPerFile : completedRuns % runsPerFile;
901cb0ef41Sopenharmony_ci    const completedConfig = this.completedConfig;
911cb0ef41Sopenharmony_ci    const scheduledConfig = this.scheduledConfig;
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    // Calculate the percentage.
941cb0ef41Sopenharmony_ci    let runRate = 0;  // Rate of current incomplete run.
951cb0ef41Sopenharmony_ci    if (completedConfig !== scheduledConfig) {
961cb0ef41Sopenharmony_ci      runRate = completedConfig / scheduledConfig;
971cb0ef41Sopenharmony_ci    }
981cb0ef41Sopenharmony_ci    const completedRate = ((completedRuns + runRate) / scheduledRuns);
991cb0ef41Sopenharmony_ci    const percent = pad(Math.floor(completedRate * 100), 3, ' ');
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci    const caption = finished ? 'Done\n' : this.currentFile;
1021cb0ef41Sopenharmony_ci    return `[${getTime(diff)}|% ${percent}| ` +
1031cb0ef41Sopenharmony_ci           `${fraction(completedFiles, scheduledFiles)} files | ` +
1041cb0ef41Sopenharmony_ci           `${fraction(completedRunsForFile, runsPerFile)} runs | ` +
1051cb0ef41Sopenharmony_ci           `${fraction(completedConfig, scheduledConfig)} configs]: ` +
1061cb0ef41Sopenharmony_ci           `${caption} `;
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  updateProgress() {
1101cb0ef41Sopenharmony_ci    if (!process.stderr.isTTY || process.stdout.isTTY) {
1111cb0ef41Sopenharmony_ci      return;
1121cb0ef41Sopenharmony_ci    }
1131cb0ef41Sopenharmony_ci    readline.clearLine(process.stderr);
1141cb0ef41Sopenharmony_ci    readline.cursorTo(process.stderr, 0);
1151cb0ef41Sopenharmony_ci    process.stderr.write(this.getProgress());
1161cb0ef41Sopenharmony_ci  }
1171cb0ef41Sopenharmony_ci}
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_cimodule.exports = BenchmarkProgress;
120