Skip to content

Source snapshot capture blocks the main thread for ~2 s after each script compile in a large project #3222

Description

@nyoro-wrl

Summary

After a domain reload that follows a script compile, HotReloadEditorStartup.CaptureOnFirstUpdateTick runs HotReloadSourceSnapshotter.CaptureAfterDomainReload() synchronously on the main thread. In my project it takes about 1.9–2.3 s, which is added to every script compile even when hot reload is not used.

Environment

  • uloop package 3.12.0 (also observed on 3.6.2), dispatcher 3.8.0, runner 3.6.2
  • Unity 6000.6.4f1, Windows 11
  • Storage: NVMe SSD
  • Project: 2,599 scripts; the edited assembly (Main) has 825 source files

How to reproduce

  1. In a project with a large assembly (several hundred source files), enable editor profiling (ProfilerDriver.profileEditor = true; ProfilerDriver.enabled = true;).
  2. Change one line in a method body of that assembly and run uloop compile.
  3. In the first frame after the domain reload, look at EditorApplication.update: HotReloadEditorStartup.<Initialize>g__CaptureOnFirstUpdateTick.

Measurement

Sample Time
EditorApplication.update: HotReloadEditorStartup.<Initialize>g__CaptureOnFirstUpdateTick 1,916 ms (3.12.0, Release code optimization) / 2,272 ms (3.6.2, Debug code optimization)
  • Each compile writes a new Library/UloopHotReload/SourceSnapshot/Main-<MVID>/ with 781 files (3.3 MB).
  • For reference, the whole uloop compile takes about 17.5 s (Bee build ~4.9 s, domain reload ~5.1 s), so this capture is a noticeable part of the wait.

Suggestion

I understand from #3195 that the first-update hook was kept so a capture still happens early when no request comes, and that the pause point path reads the snapshot without going through the new gate. With that in mind, one of these might be worth considering:

  • make the eager capture opt-in (or skippable), so projects that do not use hot reload or pause points do not pay for it on every compile; or
  • run the file copy off the main thread, with the gate waiting for it to finish before a snapshot is read. I have not checked whether every step of the capture can run off the main thread.

Activity

  1. hatayama commented on Oct 11, 2026

    @hatayama
    Owner

    Thank you for the detailed report and the profiler measurements. They make the cost very clear.

    We are treating this as our top priority and will follow up here as the fix lands.

  2. hatayama commented on Oct 11, 2026

    @hatayama
    Owner

    Thanks again for the report. A first mitigation has been merged into main (#3278) and will ship in the next package release. This issue stays open, because the capture still runs on the main thread.

    What the mitigation does:

    • Only the changed sources are rewritten. The capture after a compile now keeps the previous build's copies of unchanged sources instead of copying every source of the assembly into a new Main-<MVID>/ directory each time. In our measurements on a large project, the capture went from about 1.5 s to about 1.0 s after a one-line edit in a method body, and from about 5.4 s to about 1.4 s after adding or removing files.
    • The capture can be turned off. If you do not use hot reload or pause points, disable both hot-reload and pause-point under Tool Settings in Window > Unity CLI Loop > Settings. With both disabled, the capture and the hot reload warm-up are skipped after a domain reload, so a compile no longer pays for them. With only one of them disabled the capture still runs, because the other tool reads the snapshot.

    What we are working on now is the root fix: moving the capture off the main thread, so that a domain reload no longer waits for it. The goal is to bring the main-thread cost of the capture close to zero. We will follow up here when it lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions