-
Notifications
You must be signed in to change notification settings - Fork 185
Speedhack
Speedhack lets you speed up or slow down a game by scaling the time functions it reads. This is useful for games where animations, physics or timers are tied to the system clock. You can make them run faster for speedrunning or slower for precision work.
PINCE has two separate speedhack backends: one for native Linux processes and one for WINE/Proton processes. The right backend is selected automatically based on the attached process.
The speedhack controls are in the scan area of the main window:
-
Enable Speedhack: checkbox that turns the speedhack on and off - Speed value spinbox: appears next to the checkbox, disabled until speedhack is enabled
To use speedhack:
- Attach to a process
- Check
Enable Speedhack - Set the speed multiplier in the spinbox (range 0.2 to 10.0, step 0.1, default 1.0)
- Uncheck
Enable Speedhackto disable it
Values above 1.0 speed the game up. Values below 1.0 slow it down. For example, 2.0 makes the game run twice as fast, 0.5 makes it run at half speed.
Changing the spinbox value while speedhack is active applies the new speed immediately. You don't need to toggle it off and on again.
When you uncheck Enable Speedhack, the speed resets to 1.0 but the hooks stay installed. This avoids re-patching if you toggle it rapidly. The hooks are fully removed when you detach from the process, launch a new process, or close PINCE.
If speedhack fails to enable, you'll see Speedhack couldn't be enabled for this process. and the widgets reset to their default state.
Speedhack has three global hotkeys that work even when PINCE is not the focused window:
- Ctrl+Shift+S: toggle speedhack on/off
- Ctrl+Shift+Up: increase speed by 0.1
- Ctrl+Shift+Down: decrease speed by 0.1
The increase and decrease hotkeys automatically enable speedhack if it's not already on. They do nothing if no process is attached.
Hotkey bindings can be changed in the hotkey settings.
Speedhack works by hooking time functions in the target process and injecting assembly code that scales the returned values. The scaling formula is:
fake_time = fake_base + (real_time - real_base) * numerator / denominator
The speed value is converted to a fraction (numerator/denominator) for precision. For example, 1.5 becomes 3/2, so the returned time advances 1.5x faster than real time.
The hooks are installed by:
- Allocating a code cave in the target process's memory
- Writing assembly code into the cave that reads the real time and scales it before returning the fake value
- Overwriting the first few bytes of the target function with a jump to the cave
- Verifying the write by reading back the patched bytes
All of this happens while the target process is paused via ptrace, so there's no race condition with threads executing the patched code mid-install.
For native Linux processes, speedhack hooks three functions in libc:
-
clock_gettime: scaled for CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW and CLOCK_BOOTTIME. CPU clocks (CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID) and coarse clocks are passed through unchanged -
gettimeofday: always scaled -
nanosleep: inversely scaled (sleep duration is divided by the speed multiplier, so sleeping at 2x speed takes half the real time)
The hooks try to call the original function through the vDSO first. If the vDSO can't be resolved, they fall back to raw syscalls.
Both x86_64 and i386 processes are supported.
For WINE and Proton processes, speedhack hooks a single function:
-
RtlQueryPerformanceCounterin ntdll.dll
This is the only clock that can be safely scaled in WINE. Scaling system time or sleep deadlines would cause hangs because the kernel would wait against a drifted clock.
What this means in practice:
- Games that pace themselves using QPC (most games) will speed up or slow down correctly
- Games that use Sleep, GetTickCount, or system time for pacing won't be affected
- Real-time waits like frame pacing and vsync won't scale
- QPC will drift from system time while speedhack is active
The Wine speedhack requires a trampoline to relocate the overwritten prologue of RtlQueryPerformanceCounter and jump back into the original function. If the prologue contains relative branches, calls, returns, or RIP-relative operands that can't be safely relocated, the installation fails.
The Wine speedhack also single-steps threads out of the patch site before overwriting, since QPC is called so frequently that a thread could be mid-prologue when the patch lands.
Start with small changes (0.1 increments) and work your way up. Some games break at very high or very low speeds because their physics engines can't handle the time delta. If a game crashes or behaves strangely, try a lower speed.
Speedhack is especially useful when combined with scanning. If you're searching for a timer or countdown value, slow the game down so you have more time to scan between changes. If you're searching for an animation frame counter, speed the game up to see more values in less time.
Speedhack only scales time functions. It doesn't change CPU speed, GPU rendering, or network timing. Games that use frame-based timing instead of time-based timing won't be affected. Games that read the system clock through mechanisms other than the hooked functions (like direct CPU timestamp counter reads) also won't be affected.
Unchecking Enable Speedhack resets the speed to 1.0 but leaves the hooks in place. This is by design as it avoids the overhead of re-patching if you toggle speedhack frequently. The hooks are fully removed when you detach from the process, launch a new process, or close PINCE.
If speedhack fails to enable, check the logs for details. Common failure reasons include:
- No time functions could be located (Linux)
- ntdll.dll export couldn't be resolved (WINE)
- Memory allocation failed
- The function prologue couldn't be safely relocated (WINE)