Skip to content

Commit

Permalink
feat(async): Better parallelization
Browse files Browse the repository at this point in the history
Benchmark test 'input as glob pattern' fix
Better cross-platform process spawn handling in benchmarks
Npm test script refactor

fixes #10
  • Loading branch information
FRSgit committed Nov 14, 2018
1 parent 4494d43 commit da9722c
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 38 deletions.
12 changes: 11 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
dist: trusty
sudo: required
language: node_js
node_js:
- "node"
- "lts/*"
- "lts/*"
matrix:
include:
- name: "Standard linting"
script: yarn standard
- name: "Unit tests & coverage"
script: yarn test
- name: "Benchmark tests"
script: yarn test:benchmark
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,23 +228,22 @@ FRS-replace a b --content abcd -o foo_replaced.js
FRS-replace a b -i foo.js | <next-command>
```

## Benchmarks
## Benchmarks (Node v10.11.0)
#### input as glob pattern [1000 iterations x 100 repetitions]
| Library (best&nbsp;bolded) | Execution time [s] | Difference percentage (comparing&nbsp;to&nbsp;best&nbsp;time) |
| --- | --- | --- |
| **FRS-replace async** | 0.07656150 | 0.0000% |
| FRS-replace sync | 0.31196953 | 307.4757% |
| replace-in-file | 0.76240075 | 895.8017% |
| replace async | 0.11774627 | 53.7931% |
| replace sync | 0.91518713 | 1095.3620% |
| **FRS-replace async** | 0.15219495 | 0.0000% |
| FRS-replace sync | 0.62943626 | 313.5724% |
| replace-in-file | 1.80808213 | 1088.0040% |
| replace async | 0.21353394 | 40.3029% |
| replace sync | 1.53610279 | 909.2995% |
| replace-string | *N/A* | *N/A* |
#### input & replacement as strings [1000 iterations x 100 repetitions]
| Library (best&nbsp;bolded) | Execution time [s] | Difference percentage (comparing&nbsp;to&nbsp;best&nbsp;time) |
| --- | --- | --- |
| FRS-replace async | 0.00511845 | 77.4972% |
| **FRS-replace sync** | 0.00288368 | 0.0000% |
| FRS-replace async | 0.04848095 | 194.2632% |
| **FRS-replace sync** | 0.01647537 | 0.0000% |
| replace-in-file | *N/A* | *N/A* |
| replace async | *N/A* | *N/A* |
| replace sync | *N/A* | *N/A* |
| replace-string | 0.00292622 | 1.4752% |

| replace-string | 0.01843529 | 11.8961% |
38 changes: 21 additions & 17 deletions benchmark/replace.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ const testedLibraries = [

let dir, output, input

const readmeContent = fs.readFileSync('./README.md').toString()

let perfyResults = ''

{
Expand Down Expand Up @@ -133,13 +131,13 @@ tap.test(`input as glob pattern [${iterationsNo} iterations x ${repetitionsNo /
},
void 0
])
const sortedResults = results.slice().sort(sortByNanoseconds)

const result = outputPerfy(ct, results, results.slice().sort(sortByNumberVariable('fullNanoseconds'))[0])
const sortedResults = result.results.slice().sort(sortByNumberVariable('avgTime'))

ct.is((sortedResults[0].name.indexOf('FRS-replace') !== -1 || (sortedResults[1].name.indexOf('FRS-replace') !== -1 && sortedResults[1].avgPercentageDifference < 5)), true, 'FRS-replace should be the fastest or second, but at most with 5% difference to best')
ct.not(sortedResults[2].name.indexOf('FRS-replace sync'), -1, 'FRS-replace sync should be third (right after async replace)')

outputPerfy(ct, results, sortedResults[0])

ct.end()
})

Expand All @@ -165,17 +163,18 @@ tap.test(`input & replacement as strings [${iterationsNo} iterations x ${repetit
{ fn: () => replaceString(content, regex.source, replacement) }
])

const result = outputPerfy(ct, results, results.slice().sort(sortByNanoseconds)[0])

const sortedResults = result.results.slice().sort(sortByNanoseconds)
const result = outputPerfy(ct, results, results.slice().sort(sortByNumberVariable('fullNanoseconds'))[0])
const sortedResults = result.results.slice().sort(sortByNumberVariable('avgTime'))

ct.is((sortedResults[0].name.indexOf('FRS-replace') !== -1 || (sortedResults[1].name.indexOf('FRS-replace') !== -1 && sortedResults[1].avgPercentageDifference < 10)), true, 'FRS-replace should be the fastest or second, but at most with 10% difference to best')

ct.end()
})

tap.teardown(() => {
fs.writeFileSync('./README.md', readmeContent.replace(/(##\sBenchmarks\s\s)[\s\S]*?(?:$|(?:\s##\s))/, '$1' + perfyResults))
const readmeContent = fs.readFileSync('./README.md').toString()

fs.writeFileSync('./README.md', readmeContent.replace(/(##\sBenchmarks \(Node )(?:.*?)(\)\s\s)[\s\S]*?(?:$|(?:\s##\s))/, `$1${process.version}$2${perfyResults}`))
})

function outputPerfy (t, testResults, best) {
Expand Down Expand Up @@ -305,14 +304,19 @@ async function singleTest (name, test, n) {
return result
}

function sortByNanoseconds (a, b) {
if (a.fullNanoseconds === void 0) {
return b.fullNanoseconds === void 0 ? 0 : 1
}
function sortByNumberVariable (varName) {
return (a, b) => {
a = a[varName]
b = b[varName]

if (b.fullNanoseconds === void 0) {
return -1
}
if (a === void 0 || a === null) {
return b === void 0 || b === null ? 0 : 1
}

return a.fullNanoseconds - b.fullNanoseconds
if (b === void 0 || b === null) {
return -1
}

return a - b
}
}
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@
"prerelease": "standard --fix && yarn test",
"release": "standard-version",
"postrelease": "git push --follow-tags origin master && yarn publish",
"pretest": "standard",
"test": "yarn test:unit --100 --coverage-report=html && yarn test:benchmark",
"pretest:unit": "standard --fix",
"test:unit": "tap ./src/*.spec.js ./bin/*.spec.js -J",
"test:benchmark": "tap ./benchmark/*.spec.js --no-timeout"
"test": "yarn test:unit && tap --coverage-report=html",
"test:unit": "tap ./src/*.spec.js ./bin/*.spec.js -J --no-timeout",
"test:benchmark": "tap ./benchmark/*.spec.js --no-timeout",
"standard": "standard --fix"
},
"nyc": {
"exclude": "**/*.spec.js",
Expand Down
8 changes: 3 additions & 5 deletions src/replace.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ async function replaceAsync ({
const replaceFn = typeof regex === 'string' ? replaceString : replaceRegex

if (content !== void 0) {
result = replaceFn(content, regex, replacement)
result = new Promise(resolve => resolve(replaceFn(content, regex, replacement)))
} else if (input !== void 0) {
const fileStream = await require('fast-glob').stream(input, inputGlobOptions)
const fileStream = require('fast-glob').stream(input, inputGlobOptions)
let filesFound = false

result = ''
Expand All @@ -81,9 +81,7 @@ async function replaceAsync ({
fileStream.once('error', writeError)
})

await new Promise((resolve) => fileStream.once('end', () => {
return resolve(filesFound ? fileReaderPromise : void 0)
}))
await new Promise(resolve => fileStream.once('end', () => resolve(filesFound ? fileReaderPromise : void 0)))
} else {
writeError('at least one input source must be defined!')
}
Expand Down

0 comments on commit da9722c

Please sign in to comment.