Skip to content

Commit

Permalink
Allow configuring the number of threads
Browse files Browse the repository at this point in the history
  • Loading branch information
XhmikosR committed Oct 14, 2021
1 parent e3a5e19 commit e964c7d
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 8 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ When combined with a watching task (such as [grunt-contrib-watch][watch]), even

## Options

### `threads`

* Type: `String`, `Boolean`, `Number`
* Default: `auto`, which is the number of threads -1

Use this option to control the number of threads that grunt-htmllint will use when validating a big number of files. This will spawn as many Java processes as the number of threads.

### `ignore`

* Type: `Array`, `String`, or `RegExp`
Expand Down
34 changes: 34 additions & 0 deletions lib/getThreads.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

const os = require('os');

// eslint-disable-next-line unicorn/explicit-length-check
const CPUS = os.cpus() && os.cpus().length;
const THREADS = CPUS > 2 ? CPUS - 1 : 1;

function getThreads(config) {
const { threads } = config;

const defaultCheck = threads === 'auto' ||
threads === -1 ||
threads === '' ||
threads === true ||
threads === null ||
typeof threads === 'undefined';

if (defaultCheck) {
return THREADS;
}

if (threads === 0 || threads === 1 || threads === false) {
return 1;
}

if (threads > 1) {
return threads;
}

throw new Error(`Invalid threads option! (${threads})`);
}

module.exports = getThreads;
11 changes: 4 additions & 7 deletions lib/htmllint.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use strict';

const os = require('os');
const path = require('path');
const { execFile } = require('child_process');
const async = require('async');
const chunkify = require('./chunkify.js');
const javaDetect = require('./javaDetect.js');
const getThreads = require('./getThreads.js');
const javaArgs = require('./javaArgs.js');
const javaDetect = require('./javaDetect.js');
const parseErrorMessages = require('./parseErrorMessages.js');
const processErrorMessages = require('./processErrorMessages.js');

Expand All @@ -20,10 +20,6 @@ const MAX_CHARS = 5000;
*/
const MAX_BUFFER = 20_000 * 1024;

// eslint-disable-next-line unicorn/explicit-length-check
const CPUS = os.cpus() && os.cpus().length;
const THREADS = CPUS > 2 ? CPUS - 1 : 1;

function htmllint(config, done) {
if (config.files.length === 0) {
return done(null, []);
Expand All @@ -42,8 +38,9 @@ function htmllint(config, done) {

const files = config.files.map(file => path.normalize(file));
const chunks = chunkify(files, MAX_CHARS);
const threads = getThreads(config);

async.mapLimit(chunks, THREADS, (chunk, cb) => {
async.mapLimit(chunks, threads, (chunk, cb) => {
const args = javaArgs(java, chunk, config);

execFile('java', args, { maxBuffer: MAX_BUFFER, shell: true }, (error, stdout, stderr) => {
Expand Down
3 changes: 2 additions & 1 deletion tasks/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ module.exports = grunt => {
force: false,
absoluteFilePathsForReporter: false,
errorlevels: ['info', 'warning', 'error'],
noLangDetect: false
noLangDetect: false,
threads: 'auto'
});
const { force } = options;
let { reporterOutput } = options;
Expand Down
67 changes: 67 additions & 0 deletions test/threads_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

const assert = require('assert').strict;
const os = require('os');
const getThreads = require('../lib/getThreads.js');

// eslint-disable-next-line unicorn/explicit-length-check
const CPUS = os.cpus() && os.cpus().length;
const THREADS = CPUS > 2 ? CPUS - 1 : 1;

describe('getThreads', () => {
it('should use the number of available threads -1', done => {
const config = {};

for (const option of ['auto', true, -1, '', null, undefined]) {
config.threads = option;
const expected = THREADS;
const actual = getThreads(config);

assert.equal(actual, expected, `"thread: ${option}" failed!`);
}

done();
});

it('threads: false', done => {
const config = {
threads: false
};
const expected = 1;
const actual = getThreads(config);

assert.equal(actual, expected);
done();
});

it('threads: 4', done => {
const config = {
threads: 4
};
const expected = 4;
const actual = getThreads(config);

assert.equal(actual, expected);
done();
});

it('threads: -2', done => {
const config = {
threads: -2
};
const expected = () => getThreads(config);

assert.throws(expected, /^Error: Invalid threads/);
done();
});

it('threads: "foo"', done => {
const config = {
threads: 'foo'
};
const expected = () => getThreads(config);

assert.throws(expected, /^Error: Invalid threads/);
done();
});
});

0 comments on commit e964c7d

Please sign in to comment.