# `bustd`: Available memory or bust!

`bustd` is a lightweight process killer daemon for out-of-memory scenarios for Linux!

## Features

### Small memory usage!

`bustd` seems to use less memory than some other lean daemons such as `earlyoom`:

```console
$ ps -F -C bustd
UID          PID    PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
vrmiguel  353609  187407  5   151     8   2 01:20 pts/2    00:00:00 target/x86_64-unknown-linux-musl/release/bustd -V -n

$ ps -F -C earlyoom
UID          PID    PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
vrmiguel  350497    9498  0   597   688   6 01:12 pts/1    00:00:00 ./earlyoom/
```

¹: RSS stands for resident set size and represents the portion of RAM occupied by a process.

²: Compared when bustd was in [this commit](https://github.com/vrmiguel/bustd/commit/61beb097b3631afb231a76bb9187b802c9818793) and earlyoom in [this one](https://github.com/rfjakob/earlyoom/commit/509df072be79b3be2a1de6581499e360ab0180be).
`bustd` compiled with musl libc and earlyoom with glibc through GCC 11.1. Different configurations would likely change these figures.


### Small CPU usage

Much like `earlyoom` and `nohang`, `bustd` uses adaptive sleep times during its memory polling. Unlike these two, however, `bustd` does not read from `/proc/meminfo`, instead opting for the `sysinfo` syscall.

This approach has its up- and downsides. The amount of free RAM that `sysinfo` reads does not account for cached memory, while `MemAvailable` in `/proc/meminfo` does.

The `sysinfo` syscall is one order of magnitude faster, at least according to [this kernel patch](https://sourceware.org/legacy-ml/libc-alpha/2015-08/msg00512.html) (granted, from 2015).

As `bustd` can't solely rely on the free RAM readings of `sysinfo`, we check for memory stress through [Pressure Stall Information](https://www.kernel.org/doc/html/v5.8/accounting/psi.html).

### `bustd` will try to lock all pages mapped into its address space

Much like `earlyoom`, `bustd` uses [`mlockall`](https://www.ibm.com/docs/en/aix/7.2?topic=m-mlockall-munlockall-subroutine) to avoid being sent to swap, which allows the daemon to remain responsive even when the system memory is under heavy load and susceptible to [thrashing](https://en.wikipedia.org/wiki/Thrashing_(computer_science)).

### Checks for Pressure Stall Information

The Linux kernel, since version 4.20 (and built with `CONFIG_PSI=y`), presents canonical new pressure metrics for memory, CPU, and IO.
In the words of [Facebook Incubator](https://facebookmicrosites.github.io/psi/docs/overview):

```
PSI stats are like barometers that provide fair warning of impending resource 
shortages, enabling you to take more proactive, granular, and nuanced steps 
when resources start becoming scarce.
```

More specifically, `bustd` checks for how long, in microseconds, processes have stalled in the last 10 seconds. By default, `bustd` will kill a process when processes have stalled for 25 microseconds in the last ten seconds.

## Building

Requirements:
* [Rust toolchain](https://rustup.rs/)
* Any C compiler
* Linux 4.20+ built with `CONFIG_PSI=y`

```shell
git clone https://github.com/vrmiguel/bustd
cd bustd && cargo run --release
```

The `-n, --no-daemon` flag is useful for running `bustd` through an init system such as `systemd`.

## Prebuilt binaries

Binaries are generated at every commit through [GitHub Actions](https://github.com/vrmiguel/bustd/actions)

## TODO

- [x] Allow for customization of the critical scenario (PSI cutoff)
- [x] Command-line argument for disabling daemonization (useful for runnning `bustd` as a systemd service)
- [x] Command-line argument to enable killing the entire process group, not just the chosen process itself
- [x] Allow the user to setup a list of software that `bustd` should never kill
- [ ] Notification sending and general notification customization settings
