Repository navigation
Windows: idle app makes the whole PC unusable, background git spawns stall the desktop 25% of the time #12498
Description
What happened
This is critical for me: T3 Code makes my whole PC unusable while it is open. With the app open and idle (no turn running), the entire Windows desktop lags: the mouse cursor moves in jerks and every application hitches, not just T3 Code. This is a powerful 16C/32T, 96 GB workstation sitting at about 12% total CPU, so nothing looks wrong in Task Manager. Closing T3 Code fixes it immediately, reopening it brings it back, and the first seconds after launch are the worst. The only workaround is not running the product, which is why I rank this above every other bug I have reported.
Diagnosis
The idle server starts 19 to 44 processes per second, all console programs (git.exe, a conhost.exe for each, taskkill.exe, gh.exe). Process start and exit on Windows contend for the win32k USER lock, which the input and window-manager path also needs. With that many short-lived console children the lock is unavailable often enough to drop frames system-wide.
A/B, same machine, same evening, only T3 Code closed in between (60 s probe each, probe in the repro section; the process rates were measured back to back):
| app open, idle | app closed | |
|---|---|---|
| new processes on the machine | 24.5/s | 0.3/s |
| wall-clock time with the lock stalled | 25.3% | 0.5% |
FindWindowW calls stalled over 4 ms |
21.1% | 0.3% |
FindWindowW p99 |
16.2 ms | 0.6 ms |
| control syscall p99 | 0.003 ms | 0.002 ms |
Same probe correlated with ETW process start/exit events, a separate 60 s run with the app open, in 100 ms buckets:
| process events in bucket | buckets | worst FindWindowW latency (median) |
control syscall (median) |
|---|---|---|---|
| 0 | 193 | 0.13 ms | 0.001 ms |
| 1-4 | 129 | 13.8 ms | 0.001 ms |
| 5-14 | 259 | 14.9 ms | 0.002 ms |
| 15+ | 19 | 15.3 ms | 0.002 ms |
- The control syscall never slows down (max 0.14 ms), so this is lock contention, not CPU starvation.
- In that run 19% of calls stalled for more than 4 ms, 14.6 s of the 60 s in total (24%, matching the A/B run), each stall 15-19 ms: two to three dropped frames at 143 Hz, every time. 68% of all buckets contained at least one process event.
- 10.7% of all busy CPU time on the machine was
git.exe+conhost.exeinsidewin32kfull.sys.
Where the processes come from. A 20 s ETW trace counted 876 process starts (44/s); a 120 s count gave 2,258. The server's own children in those 20 s were 236 git, 26 taskkill and 11 gh; everything else is multiplication on top of that:
| source | tracked in | share of the 876 starts |
|---|---|---|
| git command volume: PR sweeps, remote status, per-project identity probes | #11220, #8949 | 236 direct git spawns, the driver of everything below |
Git\cmd\git.exe launcher starts a second git.exe per command |
#11221 | +236 |
a conhost.exe per console child |
#2537 | roughly one per server spawn, ~270 |
taskkill /T /F on non-zero exits, each going through WMI |
#2537 | 26, plus WmiPrvSE.exe at 7.4% of busy CPU |
git-credential-manager, sh, git-remote-https under fetches |
#11220 | the remainder |
The server also performs ~4,500 file opens per second resolving git on PATH before every spawn (#11221), and Defender follows all of it (7.7% of busy CPU).
This includes #11405: the 8-permit semaphore bounds concurrency, not volume, so the rate did not change.
It also amplifies any other system problem. Per-process cost on Windows is not constant: while an unrelated third-party service on this machine was leaking handles, process creation slowed from ~45 ms to 130-190 ms, and the same background traffic then consumed 6-16 cores of kernel time and froze the desktop outright.
Steps to reproduce
- Windows 11, Git for Windows installed the default way, desktop app with a few dozen projects (34 here, 46 threads). Leave it idle.
- Run the probe below for 60 s with the app open, then again with the app fully closed (tray included).
- Compare the
stalledline and the process start rate.
Expected: an idle app is close to invisible to the rest of the machine. A measurable bar: with N projects and no turn running, under 1 process start per second on average, and the probe reports under 1% stalled.
Actual: 19-44 process starts per second, about 25% of wall-clock time stalled.
win32k-probe.ps1 (no admin, no dependencies, changes nothing)
param([int]$Seconds = 60)
Add-Type -TypeDefinition @'
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using System.Collections.Generic;
public static class Win32kProbe {
[DllImport("user32.dll", CharSet=CharSet.Unicode)] static extern IntPtr FindWindowW(string cls, string name);
[DllImport("ntdll.dll")] static extern int NtQueryTimerResolution(out uint a, out uint b, out uint c);
public static List<double[]> Run(int seconds) {
var rows = new List<double[]>(); Thread.CurrentThread.Priority = ThreadPriority.Highest;
double ms = 1000.0 / Stopwatch.Frequency; long end = Stopwatch.GetTimestamp() + (long)seconds * Stopwatch.Frequency; uint a, b, c;
while (Stopwatch.GetTimestamp() < end) {
long t0 = Stopwatch.GetTimestamp(); FindWindowW("NoSuchClass_probe", null);
long t1 = Stopwatch.GetTimestamp(); NtQueryTimerResolution(out a, out b, out c);
long t2 = Stopwatch.GetTimestamp();
rows.Add(new double[] { (t1 - t0) * ms, (t2 - t1) * ms }); Thread.Sleep(1);
}
return rows;
}
}
'@
$rows = [Win32kProbe]::Run($Seconds)
$u = $rows | % { $_[0] } | Sort-Object; $c = $rows | % { $_[1] } | Sort-Object
$stalls = @($u | ? { $_ -gt 4 }); $stalledMs = ($stalls | Measure-Object -Sum).Sum
"win32k call ms: p50={0:N3} p99={1:N2} max={2:N2}" -f $u[[int]($u.Count*.5)], $u[[int]($u.Count*.99)], $u[-1]
"control call ms: p50={0:N3} p99={1:N3} max={2:N2}" -f $c[[int]($c.Count*.5)], $c[[int]($c.Count*.99)], $c[-1]
"stalls over 4 ms: {0} ({1:N1}% of calls), stalled {2:N1} s of {3} s = {4:N1}%" -f $stalls.Count, (100*$stalls.Count/$u.Count), ($stalledMs/1000), $Seconds, ($stalledMs/10/$Seconds)Version
0.0.43-nightly.20260917.1851 (desktop). Relevant code unchanged on main @ 4d36142.
Environment
Windows 11 Pro 26200, 16C/32T, 96 GB, 143 Hz display, Defender real-time protection on, git 2.55 for Windows.
Evidence
OPEN: 24.5 new processes/s | stalls over 4 ms: 1313 (21.1% of calls), stalled 15.2 s of 60 s = 25.3%
CLOSED: 0.3 new processes/s | stalls over 4 ms: 26 ( 0.3% of calls), stalled 0.3 s of 60 s = 0.5%
busy CPU share, 30 s profile: git.exe 15.9%, conhost.exe 8.6%, WmiPrvSE.exe 7.4%,
server 4.6%, git-credential-manager 2.4%, taskkill 1.5%, gh 1.3%
Related issues
#11220, #8949, #11221 and #2537 each track one cause in the code. None of them describes the user-visible result, that an idle app degrades the entire desktop, or the win32k mechanism, and none can be closed against a machine-level bar. This issue is that bar: fixing any one cause reduces the rate, but the symptom stays until the idle spawn rate is near zero. It is not a duplicate of #11220, which is about sweep cadence and cache expiry and would be satisfied by a change that still leaves tens of spawns per second from the other paths.
Fix applied or workaround
Closing T3 Code. Nothing was changed on the machine.
Filed by
Claude Code (Claude Fable 5.1), following the t3 triage playbook.
Activity
juliusmarminge commentedon Sep 18, 2026
Triage
Confirmed against 0.0.43-nightly.20260917.1851 and current
main@4d36142c02(same SHA the report cites). Nothing since that nightly reduces idle spawn volume. The A/B + ETW numbers are enough to treat this as a real Windows desktop-wide input stall, not CPU starvation and not “T3 feels slow.”The control syscall never moves (p99 0.003 ms vs 0.002 ms).
FindWindowWdoes (p99 16.2 ms vs 0.6 ms; 25.3% vs 0.5% of wall-clock stalled). Process-start rate with the app idle is 24.5/s vs 0.3/s closed. That is win32k USER-lock contention from short-lived console children.What the code does today
Idle spawn demand is still on by default. The desktop being open (no turn running) is enough.
1. Background loops run without client demand.
ThreadPullRequestReactor.startis explicit: “Run without client demand,” thenSchedule.spaced("1 minute")after a one-minute delay.ThreadSettlementReactorandPullRequestSyncReactoruse the same spaced minute. None of the orchestration reactors consultBackgroundPolicy. VCS status polling does (shouldRunScopeWork({ type: "vcs-status" })), and with the desktop window open that lease is live, soVcsStatusBroadcasteralso ticks atDEFAULT_VCS_STATUS_REFRESH_INTERVAL= 30 s, andGitVcsDriverCorecan refresh upstream everySTATUS_UPSTREAM_REFRESH_INTERVAL= 15 s.2. The caches are sized to expire before the next pass.
mainPR_LOOKUP_CACHE_TTL(GitManager.ts)RepositoryIdentityResolverpositive TTLnullresultDuration.zeroVcsDriverRegistryDETECTION_CACHE_TTLrev-parse --is-inside-work-tree,--show-toplevel,--git-common-dirbranchPullRequeststill does uncachedgit remote+for-each-refbefore the 60 s PR cache, andreadConfigValue/git config --getis still uncached. Settlement can also callbranchPullRequest(..., { refresh: true }), which drops the PR cache and talks toghagain.3. Windows multiplies every spawn.
processRunner.runProcessCorealways goes throughresolveSpawnCommand. On win32 that usesresolveSpawnExecutableWithNode: a synchronousPATH × PATHEXTstatSyncwalk. The 30 sCommandResolutionCacheis only onresolveCommandPath/isCommandAvailable, not on the spawn path. Default Git for Windows putsGit\cmd\git.exefirst; that launcher starts a secondmingw64\bin\git.exe.processRunnerdoes not passwindowsHide. Console children still get aconhost.exe. Timeouts and scoped teardown go through Effect’s Windows kill path (taskkill /T /Fviaexec), which is [Bug]: Frequent cmd.exe / conhost flashes on Windows from provider probe & VCS process kill paths #2537.git-credential-manager/sh/git-remote-httpson top.So “236 git + 26 taskkill + 11 gh in 20 s → 876 process starts (44/s)” is the expected shape: demand from the loops, then ×2 for the launcher, then ×1
conhostper console child, thentaskkill/WMI on teardown.4. #11405 does not change this ticket.
GitVcsDriverCore(Semaphore.makeUnsafe(8)) andVcsProcess(VCS_PROCESS_CONCURRENCY = 8) only cap in-flight short commands. They do not cap starts per second. The 8-permit pool is why the rate survived that PR.Related, not duplicates
conhostGit\cmdlauncherstatSync/ picking mingw64 git does not stop the demandconhost/taskkillflashesThose tickets stay open as the implementation slices. This one is the machine-level bar they cannot be closed against: with N projects and no turn running, idle process-start rate near zero, probe stalled time under 1%.
Workaround
Quit T3 Code completely, tray included. There is no in-app idle/pause switch that stops the orchestration loops.
Decision
Accept. Keep #11220, #8949, #11221, and #2537 open. Do not close this as a duplicate of #11220.
A change is not done for this issue until an idle Windows desktop with a few dozen projects is close to invisible on the probe in the report (
< 1process start/s,< 1%stalled). Fixing one cause is not enough if the remaining paths still stallFindWindowW.davea38 commentedon Sep 19, 2026
Also getting this - there is some crazy lag going on making the app intermittently freeze
SkiTee3000 commentedon Sep 19, 2026
Pull requests are open for three of the causes in the triage above. They touch different files and can merge in any order.
git remote/for-each-ref/config --get/rev-parsecalls (triage item 2). These read-only commands are answered from the repository files, everything else still goes to git. Measurements are in the PR.PR_LOOKUP_CACHE_TTLexpiring before the next sweep (item 2). It becomes a Background Activity setting.PATH × PATHEXTwalk on every spawn (item 3). The spawn path now uses the existingCommandResolutionCache.Written by Claude Code (Claude Fable 5.1).
CountMyBands commentedon Oct 2, 2026
Same here it's really annoying when you're typing and the window just freezes and text just appears...
Merge pingdotgg#12602: answer cheap git metadata from repository files
christopher-buss commentedon Oct 14, 2026
Still present on nightly
0.0.46-nightly.20261008.2819(includes #12600). Windows 11, 32 threads, 94 GB.Event-based process-start trace (
Win32_ProcessStartTrace), 75 s window, app open with normal use:git, 130taskkillapp-serverunder T3 CodePeak 105 starts in one second. A 1 s polling logger running at normal priority stalled 4–9 s repeatedly in the same window while CPU stayed at 20–57% and 40+ GB RAM was free, so this is not CPU or memory pressure.
The direct git commands repeat the same per-worktree reads:
git config --get branch.t3/<id>.remote,git config --get remote.origin.url,git for-each-ref ... refs/heads/t3/,git symbolic-ref refs/remotes/origin/HEAD,git remote. About 1 in 3 git spawns is followed bytaskkill /pid <n> /T /F, which looks like timeouts that grow when the machine is busy, so the load feeds itself.Looking forward to #12602.
Kocakayaa commentedon Oct 14, 2026
Still reproducing on the latest Nightly (0.0.46-nightly.20261014.3118, Windows 11 Pro 26200): console windows keep flashing frequently while T3 Code is open, even after the #2537 fix. Adding this as a data point.