[pve-devel] [PATCH v2 3/3] use worker_threads for linting
Dominik Csapak
d.csapak at proxmox.com
Mon Jul 19 12:31:49 CEST 2021
instead linting all files in the main thread, use worker threads
for that (4 by default) and add the '-t' switch to able to control that
a basic benchmark of eslint of pve-manager showed some performance
gains:
Benchmark #1: Current
Time (mean ± σ): 6.468 s ± 0.116 s [User: 9.803 s, System: 0.333 s]
Range (min … max): 6.264 s … 6.647 s 10 runs
Benchmark #2: 2Threads
Time (mean ± σ): 4.509 s ± 0.106 s [User: 12.706 s, System: 0.530 s]
Range (min … max): 4.335 s … 4.674 s 10 runs
Benchmark #3: 4Threads
Time (mean ± σ): 3.471 s ± 0.033 s [User: 16.390 s, System: 0.630 s]
Range (min … max): 3.431 s … 3.542 s 10 runs
Benchmark #4: 8Threads
Time (mean ± σ): 2.880 s ± 0.044 s [User: 22.454 s, System: 0.938 s]
Range (min … max): 2.813 s … 2.964 s 10 runs
Summary
'8Threads' ran
1.21 ± 0.02 times faster than '4Threads'
1.57 ± 0.04 times faster than '2Threads'
2.25 ± 0.05 times faster than 'Current'
after 8 threads, there were no real performance benefits since the
overhead to load the module seems to be the biggest factor.
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
src/bin/app.js | 35 +++++++++++++++++++++++++++++------
src/index.js | 2 ++
src/lib/worker.js | 27 +++++++++++++++++++++++++++
src/package.json | 3 ++-
4 files changed, 60 insertions(+), 7 deletions(-)
create mode 100644 src/lib/worker.js
diff --git a/src/bin/app.js b/src/bin/app.js
index 8a28923..10e7e6a 100644
--- a/src/bin/app.js
+++ b/src/bin/app.js
@@ -6,6 +6,7 @@
const path = require('path');
const color = require('colors');
const program = require('commander');
+const worker = require('worker_threads');
const eslint = require('pve-eslint');
program
@@ -14,6 +15,7 @@ program
.option('-e, --extend <configfile>', 'uses <configfile> ontop of default eslint config.')
.option('-f, --fix', 'if set, fixes will be applied.')
.option('-s, --strict', 'if set, also exit uncleanly on warnings')
+ .option('-t, --threads <threads>', 'how many worker_threads should be used (default=4)')
.option('--output-config', 'if set, only output the config as JSON and exit.')
;
@@ -42,6 +44,11 @@ if (!paths.length) {
paths = [process.cwd()];
}
+let threadCount = 4;
+if (program.threads) {
+ threadCount = program.threads;
+}
+
const defaultConfig = {
parserOptions: {
ecmaVersion: 2020,
@@ -283,20 +290,36 @@ if (program.outputConfig) {
process.exit(0);
}
-const cli = new eslint.CLIEngine({
+const cliOptions = {
baseConfig: config,
useEslintrc: true,
fix: !!program.fix,
cwd: process.cwd(),
-});
+};
+
+let promises = [];
+let filesPerThread = Math.round(paths.length / threadCount);
+for (let i = 0; i < (threadCount - 1); i++) {
+ let files = paths.splice(0, filesPerThread);
+ promises.push(eslint.createWorker({
+ cliOptions,
+ files
+ }));
+}
+
+// the remaining paths
+promises.push(eslint.createWorker({
+ cliOptions,
+ files: paths
+}));
-const report = cli.executeOnFiles(paths);
+let results = (await Promise.all(promises)).map(res => res.results).flat(1);
let exitcode = 0;
let files_err = [], files_warn = [], files_ok = [];
let fixes = 0;
console.log('------------------------------------------------------------');
-report.results.forEach(function(result) {
+results.forEach(function(result) {
let filename = path.relative(process.cwd(), result.filePath);
let msgs = result.messages;
let max_sev = 0;
@@ -348,7 +371,7 @@ report.results.forEach(function(result) {
console.log('------------------------------------------------------------');
});
-if (report.results.length > 1) {
+if (results.length > 1) {
console.log(`${color.bold(files_ok.length + files_err.length)} files:`);
if (files_err.length > 0) {
console.log(color.red(` ${color.bold(files_err.length)} files have Errors`));
@@ -367,7 +390,7 @@ console.log('------------------------------------------------------------');
if (program.fix) {
if (fixes > 0) {
console.log(`Writing ${color.bold(fixes)} fixed files...`);
- eslint.CLIEngine.outputFixes(report);
+ eslint.CLIEngine.outputFixes({ results });
console.log('Done');
} else {
console.log("No fixable Errors/Warnings found.");
diff --git a/src/index.js b/src/index.js
index 01b9a1d..311ae38 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,3 +1,5 @@
const eslint = require('./lib/eslint.js');
+const createWorker = require('./lib/worker.js');
module.exports = eslint;
+module.exports.createWorker = createWorker;
diff --git a/src/lib/worker.js b/src/lib/worker.js
new file mode 100644
index 0000000..9a8c955
--- /dev/null
+++ b/src/lib/worker.js
@@ -0,0 +1,27 @@
+'use strict';
+
+const worker = require('worker_threads');
+
+if (!worker.isMainThread) {
+ const eslint = require('pve-eslint');
+ const data = worker.workerData;
+ const cli = new eslint.CLIEngine(data.cliOptions);
+ const report = cli.executeOnFiles(data.files);
+ worker.parentPort.postMessage(report);
+} else {
+ module.exports = async function createWorker(workerData) {
+ return new Promise((resolve, reject) => {
+ const child = new worker.Worker(__filename,
+ {
+ workerData,
+ },
+ );
+ child.on('message', resolve);
+ child.on('error', reject);
+ child.on('exit', (code) => {
+ if (code !== 0) {reject(new Error(`Worker stopped with exit code ${code}`));}
+ });
+ });
+ }
+}
+
diff --git a/src/package.json b/src/package.json
index b08184b..e912069 100644
--- a/src/package.json
+++ b/src/package.json
@@ -4,6 +4,7 @@
"files": [
"index.js",
"bin/app.js",
- "lib/eslint.js"
+ "lib/eslint.js",
+ "lib/worker.js"
]
}
--
2.30.2
More information about the pve-devel
mailing list