From c1b643e6c684d8bb245be763e20826c809cbd955 Mon Sep 17 00:00:00 2001 From: bigjakk Date: Mon, 30 Mar 2026 14:55:25 +0000 Subject: [PATCH] Add Linux build support and fix test argv handling - BUILD-GUIDE.md: Add full Linux build instructions alongside Windows (system deps, depot_tools setup, gn/ninja paths for both platforms) - README.md: Update downloads section and usage examples for Linux - test/cdp-test.js: Fix argv parsing to handle --no-sandbox and other Electron flags that shift argument positions Verified with successful Linux x64 build (Electron v43.0.0-nightly) and automated stress test: p99 20ms, 0% messages >50ms. Co-Authored-By: Claude Opus 4.6 (1M context) --- BUILD-GUIDE.md | 297 +++++++++++++++++++++++++++++++++++++++-- README.md | 33 ++++- test/cdp-test.js | 7 +- test/package-lock.json | 36 +++++ 4 files changed, 351 insertions(+), 22 deletions(-) create mode 100644 test/package-lock.json diff --git a/BUILD-GUIDE.md b/BUILD-GUIDE.md index b7f8441..8f60772 100644 --- a/BUILD-GUIDE.md +++ b/BUILD-GUIDE.md @@ -4,6 +4,10 @@ This guide documents how to build a patched Electron binary that fixes a Chromiu regression where continuous mouse input (e.g., shooting in an FPS game) starves WebSocket and Worker message dispatch when `--disable-frame-rate-limit` is active. +Build instructions are provided for both **Windows** and **Linux**. The patch +itself is platform-agnostic (pure Chromium C++), so the same `.diff` file works +on both platforms. + ## Problem When an Electron app uses `--disable-frame-rate-limit` and `--disable-gpu-vsync` @@ -50,6 +54,8 @@ Test results (12-second automated stress test with continuous mouse input): ## Prerequisites +### Windows + - **Windows 11** (10 may work, untested) - **250GB+ free disk space** (source is ~30GB, build output ~41GB) - **16GB+ RAM** (64GB recommended) @@ -61,8 +67,25 @@ Test results (12-second automated stress test with continuous mouse input): - **Node.js** LTS (v20+) - **Python 3.11+** +### Linux + +- **Ubuntu 22.04+** / **Debian 12+** / **Fedora 38+** (or equivalent) +- **250GB+ free disk space** (source is ~30GB, build output ~41GB) +- **16GB+ RAM** (64GB recommended) +- **Build toolchain**: GCC/G++ or Clang (Chromium provides its own Clang, but + system compilers are needed for bootstrapping) +- **Git** 2.x+ +- **Node.js** LTS (v20+) +- **Python 3.11+** +- **System libraries** (see Linux setup below) + +--- + ## Step 0: Environment Setup +
+Windows Setup + ### Install depot_tools ```bash @@ -160,17 +183,112 @@ npm install -g @electron/build-tools mkdir C:\git_cache ``` +
+ +
+Linux Setup + +### Install system dependencies + +**Ubuntu/Debian:** + +```bash +sudo apt update +sudo apt install -y build-essential clang lld gperf pkg-config \ + libdbus-1-dev libgtk-3-dev libnotify-dev libgnome-keyring-dev \ + libgconf2-dev libasound2-dev libcap-dev libcups2-dev libxtst-dev \ + libxss1 libnss3-dev gcc-multilib g++-multilib curl libcurl4-openssl-dev \ + libdrm-dev libgbm-dev mesa-common-dev libpango1.0-dev libpci-dev \ + libx11-xcb-dev libxcomposite-dev libxdamage-dev libxrandr-dev \ + libxkbcommon-dev +``` + +**Fedora:** + +```bash +sudo dnf groupinstall -y "Development Tools" "C Development Tools and Libraries" +sudo dnf install -y clang lld gperf pkgconf-pkg-config dbus-devel gtk3-devel \ + libnotify-devel gnome-keyring-devel alsa-lib-devel libcap-devel cups-devel \ + libXtst-devel nss-devel libcurl-devel libdrm-devel mesa-libgbm-devel \ + pango-devel pciutils-devel libxcb-devel libXcomposite-devel libXdamage-devel \ + libXrandr-devel libxkbcommon-devel +``` + +**Note:** Chromium's build also runs `build/install-build-deps.sh` during sync, +which installs additional packages. The list above covers the main requirements. + +### Install depot_tools + +```bash +cd ~ +git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +``` + +### Configure environment + +Add to your `~/.bashrc` or `~/.zshrc`: + +```bash +export PATH="$HOME/depot_tools:$PATH" +export GIT_CACHE_PATH="$HOME/git_cache" +``` + +Then reload: + +```bash +source ~/.bashrc # or ~/.zshrc +``` + +### Configure Git + +```bash +git config --global core.autocrlf false +git config --global branch.autosetuprebase always +``` + +### Install Node.js + +Use your package manager or nvm: + +```bash +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash +nvm install 20 +``` + +### Install @electron/build-tools + +```bash +npm install -g @electron/build-tools +``` + +### Create git cache directory + +```bash +mkdir -p ~/git_cache +``` + +
+ --- ## Step 1: Initialize and Sync Source ### Initialize Electron source +**Windows:** + ```bash mkdir C:\electron && cd C:\electron e init --root=C:\electron krunker-patch --import release ``` +**Linux:** + +```bash +mkdir -p ~/electron && cd ~/electron +e init --root=$HOME/electron krunker-patch --import release +``` + This creates the directory structure and `.gclient` file. ### Sync source (downloads ~30GB) @@ -182,14 +300,24 @@ e sync This takes 1-3 hours depending on network speed. It downloads Chromium, Node.js, and all dependencies. +**Linux note:** During sync, Chromium may run `build/install-build-deps.sh` which +requires sudo to install additional system packages. If it doesn't run +automatically, execute it manually: + +```bash +cd ~/electron/src +./build/install-build-deps.sh +``` + --- ## Step 2: Apply the Patch The file to modify is: -``` -C:\electron\electron\src\third_party\blink\renderer\platform\scheduler\main_thread\main_thread_scheduler_impl.cc -``` + +**Windows:** `C:\electron\electron\src\third_party\blink\renderer\platform\scheduler\main_thread\main_thread_scheduler_impl.cc` + +**Linux:** `~/electron/src/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc` ### Patch 1: Input Priority (in `ComputePriority()` function) @@ -292,18 +420,36 @@ TaskPriority MainThreadSchedulerImpl::ComputeCompositorPriority() const { Alternatively, if you have the `.diff` file, apply it from the Chromium src root: +**Windows:** + ```bash cd C:\electron\electron\src git apply /path/to/ws-priority-patch.diff ``` +**Linux:** + +```bash +cd ~/electron/src +git apply /path/to/ws-priority-patch.diff +``` + ### Verify the patch +**Windows:** + ```bash cd C:\electron\electron\src grep -n "kNormalPriority" third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc | grep -E "(kInput|std::max)" ``` +**Linux:** + +```bash +cd ~/electron/src +grep -n "kNormalPriority" third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc | grep -E "(kInput|std::max)" +``` + You should see the `kInput` case returning `kNormalPriority` and the `std::max` cap at the end of `ComputeCompositorPriority()`. @@ -313,11 +459,19 @@ cap at the end of `ComputeCompositorPriority()`. ### Set up args.gn +**Windows:** + ```bash mkdir -p C:\electron\electron\src\out\Release ``` -Create/edit `C:\electron\electron\src\out\Release\args.gn`: +**Linux:** + +```bash +mkdir -p ~/electron/src/out/Release +``` + +Create/edit `out/Release/args.gn`: ```gn import("//electron/build/args/release.gn") @@ -328,31 +482,58 @@ use_reclient = false ### Generate build files +**Windows:** + ```bash cd C:\electron\electron\src buildtools/win/gn.exe gen out/Release ``` +**Linux:** + +```bash +cd ~/electron/src +buildtools/linux64/gn gen out/Release +``` + You should see: `Done. Made XXXXX targets from XXXX files` ### Clean stale state (if needed) If you see an error about Siso state files: +**Windows:** + ```bash buildtools/win/gn.exe clean out/Release buildtools/win/gn.exe gen out/Release ``` +**Linux:** + +```bash +buildtools/linux64/gn clean out/Release +buildtools/linux64/gn gen out/Release +``` + --- ## Step 4: Build +**Windows:** + ```bash cd C:\electron\electron\src ninja -C out/Release electron ``` +**Linux:** + +```bash +cd ~/electron/src +ninja -C out/Release electron +``` + This is a full rebuild -- **expect 6-10+ hours** depending on CPU cores and speed. On a 24-core machine with 64GB RAM it takes approximately 8-9 hours (~45,000 build steps). @@ -365,7 +546,9 @@ After the main build completes: ninja -C out/Release electron:electron_dist_zip ``` -The dist zip will be at `C:\electron\electron\src\out\Release\dist.zip` (~137MB). +**Windows:** The dist zip will be at `C:\electron\electron\src\out\Release\dist.zip` (~137MB). + +**Linux:** The dist zip will be at `~/electron/src/out/Release/dist.zip` (~130MB). --- @@ -375,10 +558,18 @@ The dist zip will be at `C:\electron\electron\src\out\Release\dist.zip` (~137MB) Run your app directly with the built electron: +**Windows:** + ```bash C:\electron\electron\src\out\Release\electron.exe /path/to/your/app ``` +**Linux:** + +```bash +~/electron/src/out/Release/electron /path/to/your/app +``` + ### Option B: Replace in node_modules Extract `dist.zip` and replace the Electron binary in your project: @@ -703,12 +894,24 @@ app.whenReady().then(async () => { ### Running the test +**Windows:** + ```bash # Test the patched build C:\electron\electron\src\out\Release\electron.exe cdp-test.js 8085 PATCHED # Compare against a stock Electron (download from https://github.com/electron/electron/releases) -path/to/stock/electron.exe cdp-test.js 8086 BASELINE +path\to\stock\electron.exe cdp-test.js 8086 BASELINE +``` + +**Linux:** + +```bash +# Test the patched build +~/electron/src/out/Release/electron cdp-test.js 8085 PATCHED + +# Compare against a stock Electron (download from https://github.com/electron/electron/releases) +path/to/stock/electron cdp-test.js 8086 BASELINE ``` **Expected results:** @@ -727,6 +930,8 @@ compositor thread input handler). To build the patch against a different Electron version (e.g., upgrading to a newer stable release): +**Windows:** + ```bash cd C:\electron\electron\src\electron @@ -751,6 +956,32 @@ ninja -C out/Release electron ninja -C out/Release electron:electron_dist_zip ``` +**Linux:** + +```bash +cd ~/electron/src/electron + +# List available stable versions +git tag --list 'v*' --sort=-version:refname | grep -v -E '(nightly|alpha|beta)' | head -10 + +# Check out the desired version +git checkout v40.6.1 + +# Sync dependencies (30-60+ minutes) +cd ~/electron/src +gclient sync --with_branch_heads --with_tags + +# Re-apply the patch (line numbers may differ between versions) +# Edit main_thread_scheduler_impl.cc as described in Step 2 +# Or try: git apply ws-priority-patch.diff + +# Clean, generate, and build +buildtools/linux64/gn clean out/Release +buildtools/linux64/gn gen out/Release +ninja -C out/Release electron +ninja -C out/Release electron:electron_dist_zip +``` + **Note:** The patch modifies Chromium source (not Electron source), so line numbers may shift between versions. The function names and structure should remain the same across Chromium versions. Search for `PrioritisationType::kInput` and @@ -768,25 +999,63 @@ to all recent versions. ## Troubleshooting -### "Python was not found" during build +### Windows + +#### "Python was not found" during build Disable Windows Store Python aliases (see Step 0). Ensure real Python 3.12 is in PATH before `C:\Users\\AppData\Local\Microsoft\WindowsApps`. -### "Siso state file" error when running ninja -Run `buildtools/win/gn.exe clean out/Release` then `gn gen` again. - -### "gn not found" +#### "gn not found" Use the full path: `buildtools/win/gn.exe` from the Chromium src directory. -### Build fails with missing Windows SDK +#### Build fails with missing Windows SDK Install SDK 10.0.26100.0: `winget install "Microsoft.WindowsSDK.10.0.26100"` -### gclient sync fails with SSH errors +### Linux + +#### Missing system libraries during build +Run the Chromium dependency installer: + +```bash +cd ~/electron/src +./build/install-build-deps.sh +``` + +This installs all required system packages. You may need `--no-prompt` for +non-interactive use. + +#### "gn not found" +Use the full path: `buildtools/linux64/gn` from the Chromium src directory. + +#### Build fails with "file not found" errors for system headers +Ensure you have the development packages installed. On Ubuntu/Debian: + +```bash +sudo apt install -y libgtk-3-dev libnss3-dev libasound2-dev libxtst-dev +``` + +#### Electron binary doesn't launch (missing shared libraries) +Check which libraries are missing: + +```bash +ldd ~/electron/src/out/Release/electron | grep "not found" +``` + +Install the missing packages with your system package manager. + +### Both Platforms + +#### "Siso state file" error when running ninja +Clean and regenerate: +- **Windows:** `buildtools/win/gn.exe clean out/Release` then `gn gen` again +- **Linux:** `buildtools/linux64/gn clean out/Release` then `gn gen` again + +#### gclient sync fails with SSH errors The sync uses Git cache. If SSH keys aren't set up for GitHub, the repos should still sync via HTTPS through the cache. If errors persist, check `GIT_CACHE_PATH` is set correctly. -### Patch doesn't apply cleanly to a different version +#### Patch doesn't apply cleanly to a different version Apply manually -- search for `PrioritisationType::kInput` returning `kHighestPriority` and change it to `kNormalPriority`. Then find `ComputeCompositorPriority()` and add the `std::max` cap. The surrounding code diff --git a/README.md b/README.md index 417d6ca..7d98a63 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,20 @@ This is critical for competitive browser-based games (like [Krunker](https://kru ## Downloads -Pre-built patched binaries (Windows x64) are available on the [Releases page](https://gitea.crjlab.net/bigjakk/Electron-Websocket-Fix/releases/tag/v1.0.0): +Pre-built patched binaries are available on the [Releases page](https://gitea.crjlab.net/bigjakk/Electron-Websocket-Fix/releases): + +### Windows x64 | File | Electron Version | Size | |------|-----------------|------| | `electron-v40.6.1-release-patched-win32-x64.zip` | v40.6.1 (latest stable) | 133MB | | `electron-v42.0.0-nightly-release-patched-win32-x64.zip` | v42.0.0-nightly | 137MB | -Both are full release builds (`is_official_build = true`) with maximum optimizations. +### Linux x64 + +Linux binaries can be built from source using the same patch -- see [`BUILD-GUIDE.md`](BUILD-GUIDE.md) for full instructions. The patch is platform-agnostic (pure Chromium C++) and applies identically on Linux. + +All builds are full release builds (`is_official_build = true`) with maximum optimizations. ## The Problem @@ -64,10 +70,18 @@ The patch not only eliminates starvation but actually **improves** both input th Extract the zip and run your app: +**Windows:** + ```bash electron.exe path/to/your/app ``` +**Linux:** + +```bash +./electron path/to/your/app +``` + ### Option B: Replace in node_modules ```bash @@ -112,7 +126,12 @@ An automated stress test is included in the [`test/`](test/) directory: ```bash cd test npm install + +# Windows path/to/patched/electron.exe cdp-test.js 8085 PATCHED + +# Linux +path/to/patched/electron cdp-test.js 8085 PATCHED ``` The test uses CDP `Input.dispatchMouseEvent` to simulate continuous mouse input (the only reliable automated method -- Electron's `sendInputEvent` API bypasses the compositor thread and doesn't trigger the bug). @@ -126,9 +145,10 @@ Full build instructions are in [`BUILD-GUIDE.md`](BUILD-GUIDE.md). Quick summary: ```bash -# 1. Set up environment (depot_tools, VS Build Tools, Python, etc.) +# 1. Set up environment (depot_tools, build toolchain, Python, etc.) # 2. Initialize and sync Electron source -e init --root=C:\electron my-build --import release +e init --root=$HOME/electron my-build --import release # Linux +e init --root=C:\electron my-build --import release # Windows e sync # 3. Check out desired version @@ -145,7 +165,8 @@ mkdir -p out/Release # is_official_build = true # use_remoteexec = false # use_reclient = false -buildtools/win/gn.exe gen out/Release +buildtools/linux64/gn gen out/Release # Linux +buildtools/win/gn.exe gen out/Release # Windows ninja -C out/Release electron ninja -C out/Release electron:electron_dist_zip ``` @@ -154,7 +175,7 @@ Expect 6-10+ hours for a full build on a modern machine (24 cores, 64GB RAM). ## Patch Details -The patch modifies Chromium source (not Electron source), so it applies to any Electron version. Line numbers may shift between versions but the function names remain the same: +The patch modifies Chromium source (not Electron source), so it applies to any Electron version since Electron 10 (Chromium 84+) on any platform (Windows, Linux, macOS). Line numbers may shift between versions but the function names remain the same: - `ComputePriority()` -- search for `PrioritisationType::kInput` - `ComputeCompositorPriority()` -- search for that function name diff --git a/test/cdp-test.js b/test/cdp-test.js index bc9293c..4a62996 100644 --- a/test/cdp-test.js +++ b/test/cdp-test.js @@ -4,8 +4,11 @@ const fs = require('fs'); const path = require('path'); const { WebSocketServer } = require('ws'); -const PORT = parseInt(process.argv[2] || '8085'); -const LABEL = process.argv[3] || 'TEST'; +// Filter out Electron/Chromium flags (e.g. --no-sandbox) from argv to find app args +const appArgs = process.argv.slice(1).filter(a => !a.startsWith('-')); +// appArgs[0] is the script path, rest are user arguments +const PORT = parseInt(appArgs[1] || '8085'); +const LABEL = appArgs[2] || 'TEST'; const TEST_DURATION_MS = 12000; const WARMUP_MS = 3000; diff --git a/test/package-lock.json b/test/package-lock.json new file mode 100644 index 0000000..6f574da --- /dev/null +++ b/test/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "ws-starvation-test", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ws-starvation-test", + "version": "1.0.0", + "dependencies": { + "ws": "^8.0.0" + } + }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +}