Skip to content

Commit

Permalink
Reduce micromatch overhead in jest-haste-map HasteFS
Browse files Browse the repository at this point in the history
I was profiling some Jest runs at Airbnb and noticed that on my
MacBook Pro, we can spend over 30 seconds after running Jest with code
coverage as the coverage reporter adds all of the untested files. I
believe that this will grow as the size of the codebase increases.

Looking at the call stacks, it appears to be calling micromatch
repeatedly, which calls picomatch, which builds a regex out of the
globs. It seems that the parsing and regex building also triggers the
garbage collector frequently.

Since this is in a tight loop and the globs won't change between
checks, we can greatly improve the performance here by using our new
and optimized globsToMatcher function, which avoids re-parsing globs
unnecessarily.

This optimization reduces the block of time here from about 30s to
about 10s. The aggregated total time of coverage reporter's
onRunComplete goes from 23s to 600ms.
  • Loading branch information
lencioni committed Jun 8, 2020
1 parent 793c8c6 commit f51fd34
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -22,7 +22,7 @@

### Performance

- `[jest-core, jest-transform]` Improve Jest startup time and test runtime, particularly when running with coverage, by caching micromatch and avoiding recreating RegExp instances ([#10131](https://github.com/facebook/jest/pull/10131))
- `[jest-core, jest-transform, jest-haste-map]` Improve Jest startup time and test runtime, particularly when running with coverage, by caching micromatch and avoiding recreating RegExp instances ([#10131](https://github.com/facebook/jest/pull/10131))

## 26.0.1

Expand Down
7 changes: 4 additions & 3 deletions packages/jest-haste-map/src/HasteFS.ts
Expand Up @@ -5,8 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import micromatch = require('micromatch');
import {replacePathSepForGlob} from 'jest-util';
import {globsToMatcher, replacePathSepForGlob} from 'jest-util';
import type {Config} from '@jest/types';
import type {FileData} from './types';
import * as fastPath from './lib/fast_path';
Expand Down Expand Up @@ -84,9 +83,11 @@ export default class HasteFS {
root: Config.Path | null,
): Set<Config.Path> {
const files = new Set<string>();
const matcher = globsToMatcher(globs);

for (const file of this.getAbsoluteFileIterator()) {
const filePath = root ? fastPath.relative(root, file) : file;
if (micromatch([replacePathSepForGlob(filePath)], globs).length > 0) {
if (matcher(replacePathSepForGlob(filePath))) {
files.add(file);
}
}
Expand Down

0 comments on commit f51fd34

Please sign in to comment.