From f3e1f027728801a3e8165cac0776d9244cdc26a9 Mon Sep 17 00:00:00 2001 From: Joe Lencioni Date: Mon, 8 Jun 2020 11:01:46 -0500 Subject: [PATCH] Reduce micromatch overhead in jest-haste-map HasteFS 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. --- CHANGELOG.md | 2 +- packages/jest-haste-map/src/HasteFS.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 099ba311f489..c5bc375a45fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/packages/jest-haste-map/src/HasteFS.ts b/packages/jest-haste-map/src/HasteFS.ts index 358eee2e3676..bdad6f292a82 100644 --- a/packages/jest-haste-map/src/HasteFS.ts +++ b/packages/jest-haste-map/src/HasteFS.ts @@ -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'; @@ -84,9 +83,11 @@ export default class HasteFS { root: Config.Path | null, ): Set { const files = new Set(); + 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); } }