Skip to content

galpt/infinity-scheduler

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

260 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

infinity-scheduler (v4.6-gpu)

A fair-share CPU + GPU scheduler based on the limit concept in mathematics β€” every scheduling parameter approaches its bound asymptotically without discrete thresholds.

Project structure

.
β”œβ”€β”€ src/                    β˜… Reference implementation (kernel/sched/infinity_sched.[ch])
β”œβ”€β”€ patches/
β”‚   β”œβ”€β”€ arch/6.18/             6 patches β€” Vanilla kernel.org 6.18
β”‚   β”œβ”€β”€ arch/7.0/              6 patches β€” Vanilla kernel.org 7.0
β”‚   β”œβ”€β”€ arch/7.1/              6 patches β€” Vanilla kernel.org 7.1
β”‚   └── fedora/7.0/            6 patches β€” Fedora kernel-ark archived-7.0
β”œβ”€β”€ tools/                     Install script, build helpers, patch fixers
β”œβ”€β”€ CONTRIBUTING.md
└── LICENSE

Quick start

Note

The install script below is tested and working with the Limine bootloader. Support for GRUB and systemd-boot has been added but not yet tested on real hardware. If you encounter issues or have a working version for your bootloader, please send a pull request.

# 1. Clone the repo (v4.6-gpu has GPU scheduling; v4.5 is stable CPU-only baseline)
git clone -b v4.6-gpu https://github.com/galpt/infinity-scheduler.git
cd infinity-scheduler

# 2. Build and install (detects running kernel version automatically)
sudo bash tools/install-infinity-scheduler.sh

# 3. Reboot and select "Infinity scheduler kernel" at the boot menu
reboot

Tip

sudo bash tools/install-infinity-scheduler.sh --remove removes only Infinity scheduler boot entries β€” the default kernel is never touched.

# Verify it's running
uname -r                              # β†’ 7.1-infinity
sysctl kernel.infinity_running        # β†’ kernel.infinity_running = 1
sysctl kernel.infinity_version        # β†’ kernel.infinity_version = v4.6-gpu
sudo dmesg | grep Infinity            # β†’ Infinity scheduler active: smt_divisor=...

Tunables

Parameter Default Range Description
infinity_smt_divisor 2 [1, 16] SMT secondary slice divisor (1 = no halving)
infinity_running 1 (ro) β€” Active flag
infinity_version v4.6-gpu (ro) β€” Branch version string

Infinity uses EEVDF's native per-task weight as its control variable β€” no separate fair-share window is needed. The EMA climb time constant is approximately 0.5ms at the default alpha (3072), scaling from 0.38ms (alpha 4096 at max cpu_capacity) to 0.67ms (alpha 2048 at low capacity). This gives sub-millisecond reaction to CPU-bound threads on any hardware. No user tunable is needed beyond the SMT divisor.

CPU scheduling

Interactive tasks that sleep frequently naturally keep their budget while CPU-bound tasks converge toward a minimum, and real-time tasks get adaptive RR timeslices based on CPU burstiness. Built into CFS/EEVDF and RT with a focus on desktop interactivity.

flowchart TB
    classDef fair fill:#0000,stroke:#3b82f6,stroke-width:2
    classDef algo fill:#0000,stroke:#6366f1,stroke-width:2
    classDef wake fill:#0000,stroke:#14b8a6,stroke-width:2
    classDef rtN fill:#0000,stroke:#d97706,stroke-width:2
    classDef infra fill:#0000,stroke:#94a3b8,stroke-width:2

    subgraph FAIR["Fair tasks (SCHED_OTHER)"]
        TASK["Task"] --> GAUGE["EMA gauge\n───\n0 β†’ BUDGET_MAX\nΞ± = 2048–4096\n(scales with cpu_capacity)"]
        class GAUGE fair

        GAUGE --> WEIGHT["infinity_update_weight()\n───\nreweight_entity()\nweight = base Γ— (100 - pctΓ—98/100) / 100\nat EMA=100%: base Γ— 2%"]
        class WEIGHT algo

        WEIGHT --> EEVDF["EEVDF\n───\ndeadline = vruntime + slice/weight\nweight↑ β†’ earlier deadline"]

        TASK --> FUTEX["futex_do_wait()\n───\nsets futex_waiting = true\nβ†’ schedule() β†’ cleared on wakeup"]
        class FUTEX algo

        FUTEX --> PLACE["place_entity()\n───\nif futex_waiting:\nvslice >>= 1\nβ†’ earlier deadline on wakeup"]
        class PLACE algo

        PLACE --> GAUGE
        class EEVDF algo

        EEVDF --> RUN["Task runs\nuntil block or preempt"]
        class RUN fair

        subgraph WAKEUP["Wakeup path"]
            WQ["enqueue_task_fair()"]
            WQ --> DECAY["infinity_wakeup()\n───\nema = f(sleep_ns)\nperiod-shift bounds tracking\n& 128-bit math safety"]
            DECAY --> WAKE["Waking task\nhas higher weight β†’\nnaturally earlier deadline"]
            WAKE --> RUN
        end
        class DECAY wake

        RUN -. "block / preempt" .-> WAKEUP
        RUN --> GAUGE
    end

    subgraph RT["RT tasks (SCHED_RR / SCHED_FIFO)"]
        RT_T["SCHED_RR task runs"] --> RT_C["infinity_rt_consume()\n───\nrt_ema climbs with runtime"]
        class RT_C rtN

        RT_C --> RT_D["infinity_rt_wakeup()\n───\ntime-proportional decay\n2nd-order Taylor expansion\ndedicated rt_last_sleep_ns"]
        class RT_D rtN

        RT_D --> RT_S["infinity_rr_timeslice()\n───\nrt_ema↑ β†’ timeslice↓\n100ms β†’ 10ms"]
        class RT_S rtN

        RT_S --> RT_Q["Task stays in\noriginal priority queue\n(safety valve demotes\nrogue FIFO at >95% rt_ema)"]
    end

    subgraph INFRA["Scheduler infrastructure"]
        AC["Ξ± = 2048 + 2048 Γ— cap/1024\n───\nmax (1024) β†’ Ξ± = 4096\nmid  (512)  β†’ Ξ± = 3072\nlow  (256)  β†’ Ξ± = 2560"]
        OF["sleep decay\n───\n2nd-order Taylor expansion\n24ms shift half-life"]
        TU["tunables\n───\nsmt_divisor\nrunning (ro)"]
    end
    class AC,OF,TU infra
Loading

GPU scheduling

The Infinity GPU extension hooks into the DRM scheduler via the Infinity virtual time algorithm (sole policy β€” FIFO/RR removed). Each GPU context (entity) tracks its GPU time via EMA β€” climbing on job completion, decaying on idle. Virtual GPU time replaces the stock submit-timestamp sort key, scaled by entity priority and burstiness. The CPU-side interactivity signals (futex_waiting, CPU EMA) are resolved from the owning process via pid_task() under an RCU read lock and directly affect the entity's GPU vtime β€” no manual configuration needed.

No fallback to FIFO exists β€” the legacy policy module parameter and selectors have been removed.

flowchart TB
    classDef ent fill:#0000,stroke:#818cf8,stroke-width:2
    classDef algo fill:#0000,stroke:#14b8a6,stroke-width:2
    classDef dec fill:#0000,stroke:#d97706,stroke-width:2
    classDef sig fill:#0000,stroke:#ef4444,stroke-width:2

    subgraph GPU["GPU scheduling (DRM + Infinity)"]
        ENTITY["drm_sched_entity
─────────────────
gpu_time_total  (cumulative ns)
gpu_time_ema    (burstiness EMA)
cached_gpu_vtime(snapshotted sort key)
last_user_pid   (owning process)"]
        class ENTITY ent

        ENTITY --> VTIME["drm_sched_entity_calc_vtime()
─────────────────────────────
1. normalize:    max(gpu_time_total,
                 min_gpu_vtime - catchup_bonus)
2. priority:     HIGH=1x, NORMAL=1.5x, LOW=3x
3. EMA boost:    vtime += ema_pct/2
──► cached_gpu_vtime (immutable in rbtree)"]
        class VTIME algo

        VTIME --> QUEUE["drm_sched_rq.unified rbtree
────────────────────────
sorted by cached_gpu_vtime
O(log n) insertion  |  O(1) selection
min_gpu_vtime advances on each pick"]
        class QUEUE dec

        KERNEL["KERNEL priority jobs
(VM page tables, buffer evictions)
4x vtime boost via >>= 2"]
        USER["HIGH / NORMAL / LOW priority jobs
(rendering, compute, compositing)"]
        class KERNEL sig
        class USER ent

        KERNEL --> QUEUE
        USER --> QUEUE

        SELECT["drm_sched_select_entity()
───────────────────────────
Single unified Infinity rbtree
First ready entity wins
KERNEL gets >>= 2 vtime boost
(FIFO/RR removed β€” no fallback)"]
        class SELECT algo

        QUEUE --> SELECT
    end

    subgraph CPU["CPU Infinity scheduler (signals)"]
        TASK["task_struct.infinity_ctx
───────────────────
futex_waiting    (IPC round-trip)
ema              (CPU burstiness)"]
        class TASK sig
    end

    TASK -. "pid_task(last_user_pid)
    under rcu_read_lock()
    futex_waiting?  β†’ vtime >>= 1
    ema == 0?       β†’ vtime >>= 1" .-> VTIME

    SELECT --> HW["GPU hardware ring β†’ job submitted"]
    class HW ent

    HW --> DONE["drm_sched_job_done()
─────────────────
gpu_time_total += job_delta
gpu_time_ema  += climb(delta)
(EMA decay on next submission via
 drm_sched_rq_update_vtime_locked)"]
    class DONE algo

    DONE -. "credit_count -= credits" .-> SELECT
Loading

Feature comparison

Feature scx_flow 3.1.0 infinity-scheduler
Fair-share slice Yes Yes
Budget model Linear consumption EMA (Limitless)
SMT halving No Yes
EEVDF Invariant Assert N/A (BPF) Yes (WARN_ON_ONCE)
Wakeup deadline boost N/A Asymptotic vslice
Work stealing Yes (BPF) No (not needed β€” EEVDF + kernel load balancer)
Adaptive RR timeslice No Yes (rt_ema-based, 10–100ms)
Hardware-adaptive alpha No Yes (2048–4096 via cpu_capacity)
Futex IPC wakeup boost No Yes (vslice halved on futex wakeup)
Migration hysteresis No Yes (EMA-driven cache pinning)
Cgroup defense shield No Yes (aggregate group EMA)
RT cross-class safety No Yes (native requeue throttling)
Asymmetric core placement No Yes (EMA-guided P/E core bias)
GPU time tracking No Yes (EMA per DRM entity)
Virtual GPU time scheduling No Yes (sole Infinity policy, FIFO/RR removed)
Soft priority (anti-starvation) No Yes (proportional vtime scaling)
Cross-scheduler interactivity No Yes (CPU EMA feeds GPU vtime)

License

GPL-2.0

Credits

  • EEVDF β€” Earliest Eligible Virtual Deadline First scheduling algorithm by Ion Stoica and Hussein Abdel-Wahab (1995), implemented in the Linux kernel by Peter Zijlstra and the kernel community. EEVDF serves as the foundation that the Infinity scheduler modifies.
  • scx_flow 3.1.0 β€” BPF sched-ext fair-share scheduler by the sched-ext community. The budget model and interactive floor logic are adapted from this implementation.
  • BORE β€” Burst-Oriented Response Enhancer scheduler by Masahito S (firelzrd). BORE's approach to CPU-bound task suppression through burst scoring provided a reference point for Infinity's accelerating consumption design.
  • BMQ / PDS / LF-BMQ β€” BitMap Queue schedulers by Alfred Chen (Project C). Research into BMQ's complete scheduler replacement approach validated the decision to keep Infinity within EEVDF rather than replacing it entirely.
  • Tvrtko Ursulin β€” Fair(er) DRM GPU scheduler β€” Igalia blog post demonstrating a CFS-inspired fair scheduler for the DRM GPU scheduler. The approach to unified virtual time scheduling and priority de-strictification directly informs Infinity's GPU extension.
  • LINUX DO β€” Chinese Linux community where the Infinity scheduler is discussed and promoted. Feedback from the community helps shape the project's development direction.
  • CachyOS community β€” Testers and early adopters who provided real-world feedback during development, helping validate the scheduler's behavior under diverse workloads.
  • u3z05en β€” Jonathan, for helping with the code review, addressing several subtle issues that made Infinity more correct and robust.
  • lostf1sh β€” Bug reports and code review, helping identify issues and improve the scheduler's correctness.
  • RiverOnVenus β€” Bug report and root cause analysis of the cgroup EMA idle-decay path where group_ema_sleep_start was checked before nr_queued was decremented, leaving the cgroup weight reduction stuck permanently.

About

Limit-inspired asymptotic EMA CPU-GPU scheduler

Topics

Resources

License

Code of conduct

Contributing

Stars

43 stars

Watchers

2 watching

Forks

Contributors