337 lines
10 KiB
Markdown
337 lines
10 KiB
Markdown
---
|
|
title: "Taming the KDE Plasma Beast: Desktop Responsiveness on Arch Linux"
|
|
date: 2026-01-04
|
|
lastmod: 2026-01-04
|
|
categories: ["Blog"]
|
|
tags: ["linux", "kde", "performance"]
|
|
---
|
|
When your beefy Ryzen 9 system locks up during a simple `pacman -Syu`, something
|
|
is very wrong. Here's how to stop Baloo, ClamAV, and poor IO scheduling from
|
|
hijacking your desktop.
|
|
|
|
<!--more-->
|
|
|
|
# The Problem
|
|
|
|
Picture this: you're running system updates on a Ryzen 9 7945HX3D with 62GB of
|
|
RAM and dual NVMe drives. DKMS starts compiling the nvidia module and suddenly
|
|
your entire desktop freezes. Mouse cursor? Frozen. Keyboard? Unresponsive. The
|
|
only option is reaching for the power button.
|
|
|
|
**This should not happen.** A modern system with this kind of hardware should
|
|
handle background compilation without breaking a sweat. Time to investigate.
|
|
|
|
# The Culprits
|
|
|
|
After some digging, three major offenders emerged:
|
|
|
|
## 1. Baloo File Indexer
|
|
|
|
KDE's file indexer was the worst offender:
|
|
|
|
```bash
|
|
$ balooctl6 status
|
|
Total files indexed: 845,512
|
|
Files waiting for content indexing: 103,138
|
|
Current size of index is 24.27 GiB
|
|
```
|
|
|
|
**Twenty-five gigabytes** of index data, with over 100,000 files still queued.
|
|
Worse, checking mounted filesystems revealed the real problem:
|
|
|
|
```bash
|
|
$ mount | grep cifs
|
|
//truenas.localdomain/share on /mnt/share type cifs ...
|
|
```
|
|
|
|
Baloo was trying to index a network share. Every file access over the network
|
|
was blocking IO and competing with the desktop for resources. Classic.
|
|
|
|
## 2. ClamAV Daemon
|
|
|
|
The antivirus daemon was consuming 1.2GB of RAM just sitting there:
|
|
|
|
```bash
|
|
$ systemctl status clamav-daemon
|
|
Memory: 1.2G (peak: 2.1G)
|
|
```
|
|
|
|
On Linux, ClamAV is honestly overkill for a desktop system. It's designed for
|
|
mail servers and file shares, not personal workstations where you control what
|
|
gets executed.
|
|
|
|
## 3. Wrong IO Scheduler
|
|
|
|
Both NVMe drives were using the BFQ scheduler:
|
|
|
|
```bash
|
|
$ cat /sys/block/nvme*/queue/scheduler
|
|
[bfq]
|
|
[bfq]
|
|
```
|
|
|
|
BFQ is great for HDDs and SATA SSDs where the kernel needs to optimize head
|
|
movement and queue depth. NVMe drives have their own hardware schedulers with
|
|
massive parallel queue support. Adding kernel-level scheduling just creates
|
|
overhead.
|
|
|
|
# The Fixes
|
|
|
|
## Step 1: Kill Baloo
|
|
|
|
If you don't use KDE's file search (and let's be honest, most terminal users
|
|
don't), just disable it:
|
|
|
|
```bash
|
|
# Disable the indexer
|
|
balooctl6 disable
|
|
|
|
# Delete the bloated database
|
|
rm -rf ~/.local/share/baloo
|
|
```
|
|
|
|
The config file at `~/.config/baloofilerc` will now show:
|
|
|
|
```ini
|
|
[Basic Settings]
|
|
Indexing-Enabled=false
|
|
```
|
|
|
|
This persists across reboots. Done.
|
|
|
|
## Step 2: Remove or Throttle ClamAV
|
|
|
|
> **Security Consideration:** Removing antivirus software is a trade-off
|
|
> between performance and security. While Linux desktops are less targeted than
|
|
> Windows, threats do exist — especially if you download software from untrusted
|
|
> sources, open email attachments, or share files with Windows users. **Proceed
|
|
> at your own risk.**
|
|
|
|
For a personal desktop where you're not scanning incoming mail or shared files,
|
|
you have a few options:
|
|
|
|
### Option A: Remove ClamAV entirely (at your own risk)
|
|
|
|
```bash
|
|
sudo systemctl disable --now clamav-daemon clamav-freshclam
|
|
sudo pacman -Rns clamav
|
|
```
|
|
|
|
### Option B: Keep ClamAV but throttle it
|
|
|
|
If you want to keep real-time protection but prevent it from impacting system
|
|
responsiveness, create a systemd override:
|
|
|
|
```bash
|
|
sudo mkdir -p /etc/systemd/system/clamav-daemon.service.d
|
|
sudo tee /etc/systemd/system/clamav-daemon.service.d/override.conf << 'EOF'
|
|
[Service]
|
|
Nice=19
|
|
IOSchedulingClass=idle
|
|
IOSchedulingPriority=7
|
|
CPUSchedulingPolicy=idle
|
|
CPUQuota=30%
|
|
MemoryMax=1G
|
|
EOF
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl restart clamav-daemon
|
|
```
|
|
|
|
This forces ClamAV to only use idle CPU/IO time and caps its resource usage.
|
|
|
|
### Option C: Manual scans only
|
|
|
|
Disable the daemon but keep the package for on-demand scanning:
|
|
|
|
```bash
|
|
sudo systemctl disable --now clamav-daemon clamav-freshclam
|
|
# Scan manually when needed:
|
|
# clamscan -r /path/to/scan
|
|
```
|
|
|
|
### Alternatives to ClamAV
|
|
|
|
If you remove ClamAV, consider these complementary security measures:
|
|
|
|
- **[Firejail](https://wiki.archlinux.org/title/Firejail)** — Sandbox untrusted
|
|
applications with minimal effort
|
|
- **[AppArmor](https://wiki.archlinux.org/title/AppArmor)** — Mandatory access
|
|
control for limiting application capabilities
|
|
- **[USBGuard](https://wiki.archlinux.org/title/USBGuard)** — Protect against
|
|
rogue USB devices
|
|
- **Common sense** — Don't run random binaries from the internet, verify
|
|
checksums, use official repositories
|
|
|
|
For most Linux desktop users who stick to official repos and don't open
|
|
suspicious attachments, the risk is manageable. But if you're handling sensitive
|
|
data or files from untrusted sources, keep some form of scanning available.
|
|
|
|
## Step 3: Fix the IO Scheduler
|
|
|
|
Create a udev rule to set the correct scheduler per drive type:
|
|
|
|
```bash
|
|
sudo tee /etc/udev/rules.d/60-ioschedulers.rules << 'EOF'
|
|
# NVMe drives have hardware schedulers - use none
|
|
ACTION=="add|change", KERNEL=="nvme[0-9]*n[0-9]*", ATTR{queue/scheduler}="none"
|
|
# HDDs benefit from BFQ
|
|
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
|
|
# SATA SSDs - none is fine
|
|
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none"
|
|
EOF
|
|
|
|
# Apply immediately
|
|
echo none | sudo tee /sys/block/nvme*/queue/scheduler
|
|
```
|
|
|
|
## Step 4: Install ananicy-cpp
|
|
|
|
This is the real game-changer. [Ananicy-cpp](https://gitlab.com/ananicy-cpp/ananicy-cpp)
|
|
automatically adjusts process priorities based on what's running:
|
|
|
|
```bash
|
|
sudo pacman -S ananicy-cpp
|
|
yay -S cachyos-ananicy-rules-git # Community rules
|
|
sudo systemctl enable --now ananicy-cpp
|
|
```
|
|
|
|
Now add custom rules. First, demote background tasks that shouldn't freeze your
|
|
desktop:
|
|
|
|
```bash
|
|
sudo tee /etc/ananicy.d/package-managers.rules << 'EOF'
|
|
# Package managers and compilers - lowest priority
|
|
{"name": "pacman", "type": "BG_CPUIO"}
|
|
{"name": "yay", "type": "BG_CPUIO"}
|
|
{"name": "makepkg", "type": "BG_CPUIO"}
|
|
{"name": "dkms", "type": "BG_CPUIO"}
|
|
{"name": "mkinitcpio", "type": "BG_CPUIO"}
|
|
{"name": "gcc", "type": "BG_CPUIO"}
|
|
{"name": "cc1", "type": "BG_CPUIO"}
|
|
{"name": "cc1plus", "type": "BG_CPUIO"}
|
|
{"name": "rustc", "type": "BG_CPUIO"}
|
|
{"name": "cargo", "type": "BG_CPUIO"}
|
|
{"name": "ninja", "type": "BG_CPUIO"}
|
|
{"name": "make", "type": "BG_CPUIO"}
|
|
|
|
# Coredump processing - can churn through 100MB+ dumps
|
|
{"name": "systemd-coredump", "type": "BG_CPUIO"}
|
|
{"name": "coredumpctl", "type": "BG_CPUIO"}
|
|
EOF
|
|
```
|
|
|
|
The `BG_CPUIO` type sets `nice=16`, `ioclass=idle`, and `sched=idle`. These
|
|
processes will only get CPU and disk time when nothing else needs it.
|
|
|
|
Next, boost interactive desktop applications that need to stay responsive:
|
|
|
|
```bash
|
|
sudo tee /etc/ananicy.d/99-desktop-priority.rules << 'EOF'
|
|
# Desktop apps that need high priority for responsiveness
|
|
|
|
# Terminal emulators
|
|
{"name": "warp", "type": "LowLatency_RT"}
|
|
{"name": "kitty", "type": "LowLatency_RT"}
|
|
{"name": "alacritty", "type": "LowLatency_RT"}
|
|
|
|
# Plasma desktop - boost higher than defaults
|
|
{"name": "plasmashell", "nice": -5, "ioclass": "best-effort", "ionice": 0, "latency_nice": -5}
|
|
|
|
# Browsers - boost for snappier UI
|
|
{"name": "vivaldi-bin", "nice": -3, "ioclass": "best-effort", "ionice": 2, "latency_nice": -3}
|
|
{"name": "firefox", "nice": -3, "ioclass": "best-effort", "ionice": 2, "latency_nice": -3}
|
|
EOF
|
|
```
|
|
|
|
The `LowLatency_RT` type sets `nice=-12` — these apps get CPU priority over
|
|
almost everything else. The `99-` prefix ensures this file loads last and
|
|
overrides any conflicting defaults.
|
|
|
|
## Step 5: Tune VM Dirty Page Handling
|
|
|
|
The kernel's default dirty page settings are tuned for servers, not desktops.
|
|
With 62GB of RAM, the defaults would allow gigabytes of dirty pages to
|
|
accumulate before flushing — causing massive IO storms that freeze everything.
|
|
|
|
```bash
|
|
sudo tee /etc/sysctl.d/99-desktop-responsiveness.conf << 'EOF'
|
|
# Use absolute byte limits instead of percentages
|
|
vm.dirty_ratio = 0
|
|
vm.dirty_background_ratio = 0
|
|
|
|
# Start background writeback at 256MB
|
|
vm.dirty_background_bytes = 268435456
|
|
# Force sync at 1GB max
|
|
vm.dirty_bytes = 1073741824
|
|
|
|
# Flush dirty pages faster
|
|
vm.dirty_expire_centisecs = 1000
|
|
vm.dirty_writeback_centisecs = 100
|
|
|
|
# Keep 256MB always free
|
|
vm.min_free_kbytes = 262144
|
|
|
|
# Desktop-friendly swappiness
|
|
vm.swappiness = 10
|
|
vm.vfs_cache_pressure = 50
|
|
EOF
|
|
|
|
sudo sysctl --system
|
|
```
|
|
|
|
# The Results
|
|
|
|
| Before | After |
|
|
|:-------|:------|
|
|
| System freezes during updates | Desktop stays responsive |
|
|
| 25GB Baloo database | 0 bytes |
|
|
| 1.2GB ClamAV RAM usage | 0 bytes |
|
|
| BFQ overhead on NVMe | Direct hardware scheduling |
|
|
| Compilation starves desktop | Compilation yields to UI |
|
|
| Coredump processing freezes system | Runs at idle priority |
|
|
| All processes equal priority | Desktop apps prioritized |
|
|
|
|
The final priority hierarchy looks like this:
|
|
|
|
| Process | Nice | Notes |
|
|
|:--------|-----:|:------|
|
|
| warp, kitty, kwin | -12 | `LowLatency_RT` — always responsive |
|
|
| plasmashell | -5 | Boosted from default -1 |
|
|
| vivaldi, firefox | -3 | Snappier than default |
|
|
| _normal processes_ | 0 | Default |
|
|
| pacman, dkms, gcc | +16 | `BG_CPUIO` — idle only |
|
|
| systemd-coredump | +16 | Won't freeze on crash dumps |
|
|
|
|
DKMS can now compile nvidia modules while I continue working. Package updates
|
|
run in the background without the mouse cursor freezing. Even when an app
|
|
crashes and generates a 100MB+ coredump, the desktop stays smooth. The system
|
|
finally behaves like it should on modern hardware.
|
|
|
|
# Diagnostic Commands
|
|
|
|
When things go wrong, these help identify the culprit:
|
|
|
|
```bash
|
|
# What's causing IO wait?
|
|
iotop -oPa
|
|
|
|
# System IO-bound?
|
|
vmstat 1 5
|
|
|
|
# Processes stuck in disk wait (D state)?
|
|
ps auxf | grep " D "
|
|
|
|
# Current dirty page status
|
|
grep -E "^(Dirty|Writeback):" /proc/meminfo
|
|
```
|
|
|
|
# The Takeaway
|
|
|
|
A powerful system shouldn't freeze during routine operations. The defaults in
|
|
most Linux distributions are tuned for servers or general compatibility, not
|
|
desktop responsiveness. A few targeted tweaks — killing unnecessary indexers,
|
|
fixing IO schedulers, and prioritizing interactive processes — make all the
|
|
difference.
|
|
|
|
No more hard resets during system updates :^)
|