# HEAVY_OPS_SEMAPHORE in Worktrunk: Throttling Heavy Git Operations for Better Performance

> Discover how Worktrunk's HEAVY_OPS_SEMAPHORE throttles heavy Git operations, preventing I/O thrashing with a limit of four concurrent tasks for improved performance.

- Repository: [Maximilian Roos/worktrunk](https://github.com/max-sixty/worktrunk)
- Tags: performance
- Published: 2026-09-14

---

**Worktrunk's `HEAVY_OPS_SEMAPHORE` is a global async semaphore that limits concurrent heavy Git operations to four permits, preventing memory-mapped I/O thrashing when accessing large pack files.**

The `max-sixty/worktrunk` repository implements `HEAVY_OPS_SEMAPHORE` to solve performance bottlenecks caused by parallel Git commands. When multiple worktrees or background tasks run intensive operations like `git rev-list --count` or `git diff --shortstat` simultaneously, they compete for memory-mapped file access, causing significant CPU pressure and throughput degradation.

## Why Git Operations Need Concurrency Control

Heavy Git operations read large commit-graph and pack files via **memory-mapped I/O (mmap)**. When many of these operations execute in parallel across multiple worktrees, they trigger excessive mmap thrashing as the system repeatedly maps and unmaps the same large Git indices.

This thrashing creates two specific problems:

- **CPU contention** – The kernel spends cycles managing page tables instead of executing Git logic
- **Unpredictable latency** – Background status checks and diff calculations slow down unpredictably as worktree count increases

According to the source code analysis, profiling on typical developer machines (4–8 cores) revealed that unthrottled parallel access to pack files degraded performance by approximately 25% when working with four concurrent worktrees.

## How HEAVY_OPS_SEMAPHORE Works

The semaphore uses a **permit-based concurrency model** with four available slots. This limit was chosen after measuring real-world performance on multi-worktree repositories, balancing parallelism against mmap overhead.

The implementation follows the RAII (Resource Acquisition Is Initialization) pattern:

1. A task acquires a permit before invoking a heavy Git command
2. The permit holder (`_guard`) automatically releases the slot when it goes out of scope
3. Other tasks block until a permit becomes available

This ensures that only a handful of heavy Git processes run simultaneously, keeping memory pressure stable and throughput predictable.

## Implementation in the Codebase

### Declaration in src/git/mod.rs

The semaphore is declared as a global static in [`src/git/mod.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/mod.rs) (lines 23–34). This location centralizes the concurrency limiter alongside other process-wide Git configurations, making it accessible throughout the repository layer.

### Usage in Commit Counting and Diff Operations

The primary consumers reside in [`src/git/repository/diff.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/repository/diff.rs), specifically within `Repository::count_commits` and related diff functions. Before executing commands that read large pack files, the code acquires a guard:

```rust
// Acquire a permit before a heavy rev-list operation
let _guard = super::super::HEAVY_OPS_SEMAPHORE.acquire();
let stdout = self.run_command(&["rev-list", "--count", "--end-of-options", &range])?;

```

Similarly, diff operations follow the same pattern:

```rust
// Acquire a permit before a heavy diff operation
let _guard = super::super::HEAVY_OPS_SEMAPHORE.acquire();
let stdout = self.run_command(&["diff", "--shortstat", "--end-of-options", &range])?;

```

The `_guard` variable ensures the permit releases automatically via Rust's drop mechanics, preventing resource leaks even if the Git command fails or panics.

## Performance Impact

Limiting concurrency to four permits yielded measurable improvements in the Worktrunk codebase:

- **~25% speed-up** on repositories with four worktrees compared to unthrottled execution
- **Controlled parallelism** that scales appropriately with typical 4–8 core developer machines
- **Reduced mmap contention** by serializing access to large pack files without blocking lightweight Git operations

This approach distinguishes between heavy I/O operations (which use the semaphore) and lightweight commands that can run unthrottled, maximizing overall throughput.

## Summary

- **HEAVY_OPS_SEMAPHORE** limits heavy Git operations to four concurrent executions across the Worktrunk process.
- It prevents **mmap thrashing** on large pack files by serializing access to memory-mapped Git indices.
- The semaphore is defined in [`src/git/mod.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/mod.rs) and utilized in [`src/git/repository/diff.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/repository/diff.rs) for commit counting and diff calculations.
- The four-permit limit was determined through profiling on typical 4–8 core development machines.

## Frequently Asked Questions

### What specific Git operations does HEAVY_OPS_SEMAPHORE control?

The semaphore throttles commands that perform heavy I/O on pack files, specifically `git rev-list --count` and `git diff --shortstat`. These operations access large commit-graph structures via memory-mapped I/O, making them prone to contention when run in parallel across multiple worktrees.

### Why was the concurrency limit set to four permits?

The limit of four permits was chosen after profiling typical developer machines with 4–8 CPU cores. Testing showed that four concurrent heavy Git operations provided optimal throughput on multi-worktree repositories while preventing the mmap thrashing that occurs with higher parallelism.

### How does acquiring a semaphore permit improve performance?

By acquiring a permit before executing heavy Git commands, Worktrunk ensures that only a bounded number of processes simultaneously memory-map large pack files. This reduces kernel page table churn and prevents the CPU overhead associated with repeatedly mapping and unmapping the same Git indices, resulting in more predictable execution times.

### Where is HEAVY_OPS_SEMAPHORE defined in the Worktrunk source code?

The semaphore is declared as a global static in [`src/git/mod.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/mod.rs) (lines 23–34) and is referenced in [`src/git/repository/diff.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/repository/diff.rs) (lines 54–56) and related files. It appears alongside other process-wide singletons in the repository module structure.