-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dramatically improve watch mode performance. #8201
Changes from 1 commit
5e16bdf
551f1d7
e0ec425
67ea28f
68c2c43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,10 +32,15 @@ export type SerializableModuleMap = { | |
}; | ||
|
||
export default class ModuleMap { | ||
public readonly uniqueID: number; | ||
private readonly _raw: RawModuleMap; | ||
private json: SerializableModuleMap | undefined; | ||
static DuplicateHasteCandidatesError: typeof DuplicateHasteCandidatesError; | ||
private static nextUniqueID = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Also, as mentioned somewhere else, start this at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. static above instance should be a lint rule / auto-fixable? done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yeah, probably 🙂 |
||
|
||
constructor(raw: RawModuleMap) { | ||
this.uniqueID = ModuleMap.nextUniqueID; | ||
ModuleMap.nextUniqueID++; | ||
this._raw = raw; | ||
} | ||
|
||
|
@@ -84,12 +89,15 @@ export default class ModuleMap { | |
} | ||
|
||
toJSON(): SerializableModuleMap { | ||
return { | ||
duplicates: Array.from(this._raw.duplicates), | ||
map: Array.from(this._raw.map), | ||
mocks: Array.from(this._raw.mocks), | ||
rootDir: this._raw.rootDir, | ||
}; | ||
if (!this.json) { | ||
SimenB marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.json = { | ||
duplicates: Array.from(this._raw.duplicates), | ||
map: Array.from(this._raw.map), | ||
mocks: Array.from(this._raw.mocks), | ||
rootDir: this._raw.rootDir, | ||
}; | ||
} | ||
return this.json; | ||
} | ||
|
||
static fromJSON(serializableModuleMap: SerializableModuleMap) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -134,6 +134,9 @@ class TestRunner { | |
Array.from(this._context.changedFiles), | ||
}, | ||
globalConfig: this._globalConfig, | ||
moduleMapUniqueID: watcher.isWatchMode() | ||
? test.context.moduleMap.uniqueID | ||
: null, | ||
path: test.path, | ||
serializableModuleMap: watcher.isWatchMode() | ||
? test.context.moduleMap.toJSON() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SimenB I've been thinking about this and I'm pretty sure we're still paying a serialization cost to send this to the worker for each test, just much less of one. Is this part of the public interface? Can I change it without it being considered a breaking change? Can always explore in further PRs since this one is obviously an improvement, but it would be nice if I was able to move the logic up into the main thread and not even send the haste map if it wasn't new. I'm not sure if it is a breaking change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure... That's more of a question for @rubennorte or @mjesun The less we have to send across ipc the better, so if we can change it I'm all for it 🙂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like external runners include both the worker and the orchestrator, so changing what we pass to the worker here should be safely in the realm of a non-breaking-change! Working to further optimize this. @rubennorte @mjesun Let me know if I'm incorrect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @SimenB Feel free to re-review, I've refactored this to approach it from a different angle and it's now even faster. On Jest's test suite, before Watch mode was a 6%~ performance cost (in my initial PR) and now it's about 1%~. The refactor matters even more for larger haste maps, like Facebook's. |
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was there any reason this was 1 less? @rogeliog do you know?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the rationale for cpus/2 was that watch mode is typically used while doing other things (mostly editing files) and this was to make it less likely that the editor becomes slow / freezes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to make it 1 less that's fine, but before it was halved! Just happened to be 1 less in this case.
On my machine, it was running 6 workers instead of 11.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, stumbled over the formula as well some time ago and wondered if there's any experimental basis for it ^^
I'm fine with using
cpus - 1
for watch mode as well. It's a good heuristic for what performs best when Jest is the only thing running, we can't really do much about sharing resources with other applications.If you want your editor to remain responsive while running an expensive task,
nice yarn jest --watch
is a good idea anyway.