|
| 1 | +import { Logger } from '@ngtools/logger'; |
| 2 | +import * as fs from 'fs'; |
| 3 | +const mean = require('lodash/mean'); |
| 4 | +const toNumber = require('lodash/toNumber'); |
| 5 | + |
| 6 | + |
| 7 | +import { BenchmarkOptions } from './benchmark-options'; |
| 8 | +import { |
| 9 | + combine, |
| 10 | + makeMatchFn, |
| 11 | + matchSpawn, |
| 12 | + serialMultiPromise |
| 13 | +} from './utils'; |
| 14 | + |
| 15 | +export function benchmark(benchmarkOptions: BenchmarkOptions, logger: Logger) { |
| 16 | + const logIfDefined = (str: string, prop: any) => { |
| 17 | + if (Array.isArray(prop) && prop.length === 0) { |
| 18 | + prop = null; |
| 19 | + } |
| 20 | + return prop ? logger.info(str + prop) : null; |
| 21 | + }; |
| 22 | + |
| 23 | + const cwd = process.cwd(); |
| 24 | + |
| 25 | + // Build match function |
| 26 | + let matchFn: any = null; |
| 27 | + if (benchmarkOptions.match) { |
| 28 | + matchFn = makeMatchFn( |
| 29 | + logger, |
| 30 | + benchmarkOptions.match, |
| 31 | + benchmarkOptions.matchCount, |
| 32 | + benchmarkOptions.matchEditFile, |
| 33 | + benchmarkOptions.matchEditString, |
| 34 | + ); |
| 35 | + } |
| 36 | + |
| 37 | + let editedFileContents: string; |
| 38 | + if (benchmarkOptions.matchEditFile) { |
| 39 | + // backup contents of file that is being edited for rebuilds |
| 40 | + editedFileContents = fs.readFileSync(benchmarkOptions.matchEditFile, 'utf8'); |
| 41 | + } |
| 42 | + // combine flags commands |
| 43 | + let flagCombinations = combine(benchmarkOptions.extraArgs); |
| 44 | + flagCombinations.unshift([]); |
| 45 | + |
| 46 | + const startTime = Date.now(); |
| 47 | + logger.info(`Base command: ${benchmarkOptions.command}`); |
| 48 | + logger.info(`Iterations: ${benchmarkOptions.iterations}`); |
| 49 | + logIfDefined('Comment: ', benchmarkOptions.comment); |
| 50 | + logIfDefined('Extra args: ', benchmarkOptions.extraArgs); |
| 51 | + logIfDefined('Logging to: ', benchmarkOptions.logFile); |
| 52 | + if (benchmarkOptions.match) { |
| 53 | + logger.info(`Match output: ${benchmarkOptions.match}`); |
| 54 | + logIfDefined('Match count: ', benchmarkOptions.matchCount); |
| 55 | + logIfDefined('Match edit file: ', benchmarkOptions.matchEditFile); |
| 56 | + logIfDefined('Match edit string: ', benchmarkOptions.matchEditString); |
| 57 | + } |
| 58 | + if (benchmarkOptions.debug) { |
| 59 | + logger.debug('### Debug mode, all output is logged ###'); |
| 60 | + } |
| 61 | + logger.info(''); |
| 62 | + |
| 63 | + |
| 64 | + let promise = Promise.resolve(); |
| 65 | + let hasFailures = false; |
| 66 | + |
| 67 | + flagCombinations.forEach((flags) => |
| 68 | + promise = promise |
| 69 | + .then(() => serialMultiPromise( |
| 70 | + benchmarkOptions.iterations, |
| 71 | + matchSpawn, |
| 72 | + logger, |
| 73 | + cwd, |
| 74 | + matchFn, |
| 75 | + benchmarkOptions.command, |
| 76 | + flags |
| 77 | + ).then((results: any[]) => { |
| 78 | + const failures = results.filter(result => result.err && result.err !== 0); |
| 79 | + logger.info(`Full command: ${benchmarkOptions.command} ${flags.join(' ')}`); |
| 80 | + |
| 81 | + let times = results.filter(result => !result.err) |
| 82 | + .map((result) => result.time); |
| 83 | + logger.info(`Time average: ${mean(times)}`); |
| 84 | + logger.info(`Times: ${times.join()}`); |
| 85 | + |
| 86 | + if (benchmarkOptions.match) { |
| 87 | + let matches = results.filter(result => !result.err) |
| 88 | + .map((result) => result.match); |
| 89 | + |
| 90 | + let matchesAsNumbers = matches.map(toNumber); |
| 91 | + if (matches.every(match => match != NaN)) { |
| 92 | + logger.info(`Match average: ${mean(matchesAsNumbers)}`); |
| 93 | + } |
| 94 | + logger.info(`Matches: ${matches.join()}`); |
| 95 | + } |
| 96 | + |
| 97 | + if (failures.length > 0) { |
| 98 | + hasFailures = true; |
| 99 | + logger.info(`Failures: ${failures.length}`); |
| 100 | + logger.info(JSON.stringify(failures)); |
| 101 | + } |
| 102 | + logger.info(''); |
| 103 | + })) |
| 104 | + ); |
| 105 | + |
| 106 | + return promise.then(() => { |
| 107 | + logger.info(`Benchmark execution time: ${Date.now() - startTime}ms`); |
| 108 | + // restore contents of file that was being edited for rebuilds |
| 109 | + if (benchmarkOptions.matchEditFile) { |
| 110 | + fs.writeFileSync(benchmarkOptions.matchEditFile, editedFileContents, 'utf8'); |
| 111 | + } |
| 112 | + return hasFailures ? Promise.reject(new Error('Some benchmarks failed')) : Promise.resolve(); |
| 113 | + }); |
| 114 | +} |
0 commit comments