@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
119 lines • 5.17 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const assert_1 = require("../util/assert");
const files_1 = require("../util/files");
const log_1 = require("../util/log");
const parallel_1 = require("../util/parallel");
const script_1 = require("./common/script");
const options = (0, script_1.processCommandLineArgs)('benchmark', [], {
subtitle: 'Slice given files with additional benchmark information',
examples: [
'{italic example-folder/}',
'{bold --help}'
]
});
if (options.input.length === 0) {
console.error('No input files given. Nothing to do. See \'--help\' if this is an error.');
process.exit(0);
}
const numberRegex = /^\d+$/;
(0, assert_1.guard)(options.slice === 'all' || options.slice === 'no' || numberRegex.test(options.slice), 'slice must be either all, no, or a number');
(0, assert_1.guard)(options.runs === undefined || options.runs > 0, 'runs must be greater than zero');
function removeIfExists(summarizedRaw) {
if (fs_1.default.existsSync(summarizedRaw)) {
console.log(`Removing existing ${summarizedRaw}`);
try {
fs_1.default.rmSync(summarizedRaw, { recursive: true });
}
catch {
log_1.log.error('failure in cleanup');
}
}
}
async function benchmark() {
removeIfExists(options.output);
fs_1.default.mkdirSync(options.output, { recursive: true });
console.log(`Storing output in ${options.output}`);
console.log(`Using ${options.parallel} parallel executors`);
// we do not use the limit argument to be able to pick the limit randomly
const files = [];
const firstFile = options.input[0];
// Check whether input is single JSON file containing a list of paths
if (options.input.length === 1 && fs_1.default.statSync(firstFile).isFile() && firstFile.endsWith('.json')) {
console.log('Input is a single JSON file. Assuming it contains a list of files to process');
const content = fs_1.default.readFileSync(firstFile, 'utf8');
const paths = JSON.parse(content);
const baseDir = findCommonBaseDir(paths);
await collectFiles(files, paths, () => baseDir);
}
else {
await collectFiles(files, options.input, (p) => p);
}
if (options.limit) {
log_1.log.info(`limiting to ${options.limit} files`);
// shuffle and limit
files.sort(() => Math.random() - 0.5);
}
const limit = options.limit ?? files.length;
const verboseAdd = options.verbose ? ['--verbose'] : [];
const args = files.map((f, i) => [
'--input', f.request.content,
'--file-id', `${i}`,
'--output', path_1.default.join(options.output, path_1.default.relative(f.baseDir, `${f.request.content}.json`)),
'--slice', options.slice, ...verboseAdd,
'--parser', options.parser,
...(options['enable-pointer-tracking'] ? ['--enable-pointer-tracking'] : []),
'--max-slices', `${options['max-file-slices']}`,
...(options.threshold ? ['--threshold', `${options.threshold}`] : []),
'--sampling-strategy', options['sampling-strategy'],
]);
const runs = options.runs ?? 1;
for (let i = 1; i <= runs; i++) {
console.log(`Run ${i} of ${runs}`);
const pool = new parallel_1.LimitedThreadPool(`${__dirname}/benchmark-helper-app`,
// we reverse here "for looks", since the helper pops from the end, and we want file ids to be ascending :D
args.map(a => [...a, '--run-num', `${i}`]).reverse(), limit, options.parallel, options['per-file-time-limit']);
await pool.run();
const stats = pool.getStats();
console.log(`Run ${i} of ${runs}: Benchmarked ${stats.counter} files, skipped ${stats.skipped.length} files due to errors`);
}
}
/**
* Collect all R files from the given paths.
*
* @param files - list of files to append to
* @param paths - list of paths to search for R files
* @param getBaseDir - function to get the base directory of a path
*/
async function collectFiles(files, paths, getBaseDir) {
for (const input of paths) {
for await (const file of (0, files_1.allRFiles)(input)) {
files.push({ request: file, baseDir: getBaseDir(input) });
}
}
}
/**
* Find the common base directory of a list of paths.
*
* @param paths - list of paths
* @returns the common base directory
*/
function findCommonBaseDir(paths) {
const baseDirs = paths.map(f => path_1.default.dirname(f));
return baseDirs.reduce((acc, dir) => {
const split = dir.split(path_1.default.sep);
const accSplit = acc.split(path_1.default.sep);
let i = 0;
while (i < split.length && i < accSplit.length && split[i] === accSplit[i]) {
i++;
}
return split.slice(0, i).join(path_1.default.sep);
}, baseDirs[0]);
}
void benchmark();
//# sourceMappingURL=benchmark-app.js.map