# bore-scheduler: a burstiness score for the Linux EEVDF scheduler

> BORE is a C patch set for the Linux kernel that layers a burstiness score onto EEVDF so interactive tasks keep CPU under mixed load. The mechanism is a bit count of a task's CPU time since it last yielded, exposed through six sysctl tunables.

**firelzrd/bore-scheduler** — BORE (Burst-Oriented Response Enhancer) CPU Scheduler

- Repository: https://github.com/firelzrd/bore-scheduler
- Stars: 883 · Forks: 38
- Language: C
- License: GPL-2.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/firelzrd-bore-scheduler

## What BORE changes about EEVDF's fairness assumption

BORE, the Burst-Oriented Response Enhancer, is a set of Linux kernel scheduler changes written in C. The description calls it an enhanced version of the EEVDF (Earliest Eligible Virtual Deadline First) schedulers, and the stated aim is to keep that family's performance while delivering resilient responsiveness to user input under a wide range of load mixes.

The idea it departs from is CFS's inherent principle of complete fairness. CFS treats every task as equally deserving of CPU regardless of behaviour, which is a poor fit when a build running in the background and a desktop session compete for the same cores. BORE introduces a per-task dimension called burstiness so that the scheduler can tell a task that frequently hands the CPU back from one that hoards it.

This is aimed at people who compile their own kernel, and at distributions that ship patched kernels for specific hardware. It is not a userspace daemon, a service, or a configuration file that a package manager installs. The repository root holds a patches/ directory, tests/, a README, and images of the scoring relationships, which places it squarely in the kernel patch category rather than the application category.

## Burst time, bit count, and a score between 0 and 39

The mechanism has four moving parts, and the documentation describes each of them.

Burst time is the amount of CPU time a task has consumed since it last yielded, slept, or waited for I/O. While the task is active, its burst score is calculated continuously by counting the bit count of its normalized burst time, then adjusting that count with a pre-configured offset and coefficient.

The resulting burst score sits between 0 and 39 and behaves much like niceness. For each decrease in the value by 1, the task can consume approximately 1.25x longer timeslice. The documentation frames the computation as a radix conversion from a binary logarithm to a common logarithm, moving from a nanoseconds-to-minutes timescale to roughly a 0.01 to 100x scale, without units.

The practical effect is that less greedy tasks receive more timeslice and more aggressive wakeup preemption, while greedy tasks that yield less frequently are weighted less. The score is a function of behaviour rather than of a user assigned priority, which is the whole point: a task that sleeps often looks interactive whether or not anyone told the scheduler so.

## Six sysctl knobs and what each one actually changes

The tunables are read and written through the kernel parameter namespace, and the documentation lists six of them with ranges and defaults.

kernel.sched_bore ranges from 0 to 1 with a default of 1, and it is the on/off switch for the whole mechanism. kernel.sched_burst_penalty_offset ranges from 0 to 63, default 24, and controls how many bits are removed from the burst time bit count, so raising it keeps short-burst tasks from being too strong and lengthens the effective burst time range. kernel.sched_burst_penalty_scale ranges from 0 to 4095, default 1536, and sets how strongly tasks are discriminated by burst time ratio in units of 1/1024 of its precursor value; raising it makes the score grow fast as burst time grows, so long-running tasks lose power against short ones.

kernel.sched_burst_smoothness ranges from 0 to 3 with a default of 1, which the documentation says means no smoothing. Where smoothing is enabled, the effective score is the larger of the latest calculated score and a historical score inherited from past updates, mixed with an exponential moving average every time the score is recomputed on dequeue or yield. kernel.sched_burst_cache_lifetime, default 75000000 nanoseconds, is how long the on-fork calculated average burst time of child tasks is held as a cache, trading recalculation frequency for coarser adjustments. The last one, kernel.sched_burst_inherit_type, ranges from 0 to 2 with a default of 2, and picks how child burst time is inherited, which is where the process tree handling lives.

## The on-fork problem and the three inheritance modes

Newly spawned processes get their burst score computed in a special way, and the reason is stated plainly: to prevent tasks like make from overwhelming interactive tasks by forking many CPU hungry children.

That is the hardest case for any scheduler that infers interactivity from behaviour, because a fresh child has no history to infer from. The answer here is to inherit, and kernel.sched_burst_inherit_type offers three choices. Value 0 disables inheritance of the average child burst time from ancestor processes. Value 1 enables inheritance from parent processes, the traditional parent-to-child style. Value 2, the default, enables inheritance of the average child burst time from ancestor processes using a topological hub or stub style hierarchy tree rather than the direct parent chain. In that mode, nodes with only one child process are ignored when finding and calculating ancestor and descendant processes for inheritance, which the documentation says may improve responsiveness in situations with massive process forking such as kernel builds.

The inheritance value is a tree walk over the process hierarchy, and the cache lifetime tunable sits directly beside it. With a long lifetime, a fork storm inherits a coarse average instead of a fresh computation for every child. The trade-off is resolution: the documentation is explicit that a larger value means less frequent recalculation in exchange for lower time resolution.

## Enabling BORE on a kernel that already carries the patches

The README does not document a build procedure, a kernel configuration fragment, or a package to install, so there is nothing here to copy for compiling the scheduler in. What it does give is the runtime control, and the mechanism has to be present in the running kernel before that control means anything.

The example in the documentation is a single sysctl write that turns the mechanism on:

```bash
sudo sysctl -w kernel.sched_bore=1
```

The parameter is documented as enabled by default, so a kernel carrying the patches needs no action to have BORE active, and the write matters mainly when you want to compare behaviour on the same machine. Turning kernel.sched_bore to 0 disables the mechanism, which makes it the fastest way to tell whether a responsiveness problem is coming from BORE or from the workload.

The remaining parameters are written the same way, under the same kernel.sched_burst_ prefix, and every one of them accepts values in the ranges listed earlier. A sensible first pass on a machine you are evaluating is to change one parameter at a time, since the offset and the scale interact with each other and with the smoothness setting.

## What the repository does not tell you

Several things a reader would reasonably want are absent, and knowing which ones matters before committing a kernel build to this.

There is no GitHub release, so there is no versioned artifact to pin and no changelog to read beyond the commit history. The repository is not archived and the last push was on 2026-10-06, but the documentation does not publish a support policy for older kernel versions, and it does not say which upstream kernel releases the patches are rebased onto. A kernel that does not match the target series is where most of the work of carrying such a patch set actually lives.

The tests/ directory exists in the repository root, but the README does not document how to run it or what the tests cover. There is also no benchmark harness, no performance numbers and no reproduction script in the documentation, so claims about relative speed have to be measured by you on your own hardware. The performance claims in the project are qualitative: the aim is to keep EEVDF's performance while improving responsiveness under mixed load.

On the licence side, the project is GPL-2.0. For a kernel patch that is the normal choice, but it means the same obligations that apply to any GPL-2.0 code apply to a distribution that ships the patched kernel, and a vendor that ships the kernel as proprietary firmware or as a closed appliance needs to read the terms against that specific model. The README also names several people who hosted BORE powered kernels for Fedora and for a Clear Linux based build, which is a practical signal about where the patch set gets exercised, though those are community builds rather than a supported distribution channel.

## Where the alternatives sit

The closest alternative to a patched EEVDF kernel is the scheduler the distribution already ships, and the difference is architectural rather than a matter of tuning. A distribution kernel uses the upstream scheduler as shipped, which is CFS and its EEVDF successor, both of which keep the complete fairness assumption. BORE deliberately moves away from that assumption by deriving priority from observed behaviour instead of treating every task as equal.

Within the same space, the documentation credits Hamad Al Marri, the developer of the Cachy, CacULE, Baby, TT and ECHO schedulers, as the person whose work inspired BORE and who helped with its development. It also credits Andrea Righi, the developer of sched-ext and of several schedulers built on that framework, for inspiring the futex boost feature. That is a meaningful difference in approach: BORE is a modification of an existing scheduling algorithm in the classic kernel scheduler code, while the framework approach rethinks how scheduling decisions are made rather than adding a scoring dimension to them.

The practical consequence for an adopter is the cost of carrying the patch. A scoring dimension is small, self contained and tunable at runtime through sysctl. A different scheduling framework is a larger change with a different maintenance model. Which one fits depends on whether you want a responsiveness tweak on top of the scheduler you already have or a different scheduler entirely.

## Conclusion

Adopt bore-scheduler when you build your own kernel and the machine mixes CPU bound batch work with interactive work, and you want the interactive side to keep its share without hand tuning niceness. Do not adopt it on a distribution kernel where you cannot patch, on a machine that only runs one kind of workload, or in a product where the GPL-2.0 terms of a kernel patch are a problem. Verify first that the burst score and the timeslice ratio in your build match the 0 to 39 range and the roughly 1.25x step described in the documentation, and that kernel.sched_bore can be toggled at runtime so you can turn the mechanism off if a workload regresses.

## FAQ

### What does the bore-scheduler actually change in the Linux kernel?

It adds a per-task burstiness score to the EEVDF schedulers, derived from the CPU time a task has consumed since it last yielded, slept or waited for I/O. The score takes a value between 0 and 39 and works like niceness, with each decrease of 1 giving roughly 1.25x longer timeslice.

### How do I enable or disable BORE at runtime?

The mechanism is controlled by the kernel.sched_bore parameter, which ranges from 0 to 1 with a default of 1, so it is on in a kernel carrying the patches. The documentation shows it being switched on with sudo sysctl -w kernel.sched_bore=1, and setting it to 0 disables the mechanism.

### What are the main tunables of bore-scheduler?

The documentation lists kernel.sched_bore, kernel.sched_burst_cache_lifetime, kernel.sched_burst_inherit_type, kernel.sched_burst_penalty_offset, kernel.sched_burst_penalty_scale and kernel.sched_burst_smoothness, each with a documented range and default value.

### How does bore-scheduler handle a build forking many child processes?

Newly spawned processes get their burst score computed in a special way so that a task such as make cannot overwhelm interactive tasks by forking many CPU hungry children. Child burst time can be inherited from ancestors, and the default inheritance mode uses a topological hub or stub style hierarchy tree in which nodes with a single child are ignored.

### Is bore-scheduler available as a package I can install?

The repository contains a patches/ directory, tests/ and documentation, and the README gives a sysctl example rather than an installation or build procedure. The project is a Linux kernel scheduler patch set written in C and licensed GPL-2.0, so it is carried through a kernel you build rather than installed as a package.

## Sources

- [firelzrd/bore-scheduler on GitHub](https://github.com/firelzrd/bore-scheduler)
- [Issues](https://github.com/firelzrd/bore-scheduler/issues)
- [License: GPL-2.0](https://github.com/firelzrd/bore-scheduler/blob/main/LICENSE)
- [README](https://github.com/firelzrd/bore-scheduler/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/firelzrd-bore-scheduler
