# Reviving a 2013 Mac Pro "Trashcan" as an Ubuntu 26.04 VM Server: Install, the Hidden SSD Bottleneck, and Tuning for Raw Horsepower

**Machine:** Mac Pro 6,1 with a Xeon E5-1680 v2 (8 cores, 16 threads), 64 GB DDR3-1866, 2× FirePro D700 and a 1 TB Apple SSD (SM1024F).
**Goal:** a headless QEMU/KVM host running Incus, tuned for maximum performance.

| Result | Before | After |
|---|---|---|
| 4 KiB synced write | 1,250 ms | 3.4 ms |
| Boot time | 2 min 17 s | 14.7 s |
| Single-thread CPU (sysbench) | 318.7 | 453.5 (+42%) |
| Syscall (`perf bench syscall`) | 629 ns | 62 ns |

All numbers were measured on this machine.

## 1. Install

**Why Ubuntu 26.04:** it ships kernel 7.0, and since kernel 6.19 the D700s (GCN 1.0) use `amdgpu` by default, which gives Vulkan through RADV. Ethernet (`tg3`), fan control (`applesmc`) and audio work out of the box. Wi-Fi needs the proprietary `wl` driver (step 6). ROCm doesn't support these GPUs.

**1. Update the firmware.** The firmware only updates from macOS, so install Monterey 12.7.x once before wiping the drive.

**2. Make the USB installer** (on the Mac):

```bash
diskutil list                         # find the stick, e.g. /dev/disk4
diskutil unmountDisk /dev/disk4
sudo dd if=ubuntu-26.04-live-server-amd64.iso of=/dev/rdisk4 bs=4m status=progress
```

**3. Boot it.** Hold *Option* at power-on and choose **EFI Boot**. If you get a black screen, press `e` in GRUB and add `nomodeset` for the install only.

**4. Installer choices:** use the entire disk with LVM, install OpenSSH and import your keys, and skip the featured snaps.

**5. After the install:**

```bash
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y lm-sensors pciutils htop linux-tools-$(uname -r)
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
lspci -k | grep -A3 VGA        # both GPUs: Kernel driver in use: amdgpu
```

> **GPU flags.** On kernel 6.19+ you need none. I tested by removing them and rebooting, and both GPUs still loaded `amdgpu`. On older kernels (e.g. Debian 13), add `radeon.si_support=0 amdgpu.si_support=1` to `GRUB_CMDLINE_LINUX_DEFAULT` and run `sudo update-grub`.

**6. Wi-Fi (optional).** The BCM4360 needs Broadcom's `wl` driver. The open-source `b43` driver fails with "unsupported PHY". The DKMS package builds on kernel 7.0 and blacklists the conflicting drivers:

```bash
sudo apt install -y broadcom-sta-dkms wpasupplicant iw rfkill
sudo modprobe -r b43 ssb bcma && sudo modprobe wl
iw dev                                   # → wlp13s0
```

To connect, use [`wifi-connect.sh`](https://github.com/clearstackio/macpro-2013-ubuntu). It writes a netplan config with a hashed password, marks Wi-Fi `optional` so boot doesn't wait for it, and keeps Ethernet as the default route unless you pass `--primary`:

```bash
curl -fsSLO https://raw.githubusercontent.com/clearstackio/macpro-2013-ubuntu/main/wifi-connect.sh
sudo bash wifi-connect.sh "YourSSID" "your-password"
```

## 2. Optimize

Ordered by impact. Each step starts from a measurement.

### 2.1 TRIM the SSD (the big one)

**Symptom:** the CPU sat idle, yet `apt install` hung in `dpkg` for 12 minutes.

```bash
cat /proc/pressure/io                       # full avg10=85  → tasks stalled on I/O 85% of the time
dd if=/dev/zero of=t bs=1M count=512 oflag=direct   # 1.3 GB/s  (bulk is fine)
dd if=/dev/zero of=t bs=4k count=50 oflag=dsync     # 1.25 s per write (flushes are not)
```

`/sys/block/sda/stat` showed an average cache flush of **173 ms** and **0 discards ever sent**. The drive still held years of macOS data that had never been trimmed, so its controller had no free blocks to work with and had to clean up during every flush. Anything that calls `fsync` (dpkg, databases, VMs) stalled. The same thing was reported for the sibling SM0512F on the linux-ext4 list in 2015.

**Fix:** give `/` the whole disk, then trim it.

```bash
sudo lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv   # online; root went from 492 GB to 914 GB
sudo fstrim -av                                          # 901 GiB trimmed
```

A synced write went from **1,250 ms to 3.4 ms**. Turning NCQ off made no difference, so I left it on. The weekly `fstrim.timer` is enabled by default. SMART was clean.

### 2.2 Boot: 2 min 17 s → 15 s

`systemd-analyze blame` showed `systemd-networkd-wait-online` taking **2 minutes**: it waits for the second Ethernet port, which has no cable. Mark that port optional in `/etc/netplan/00-installer-config.yaml`:

```yaml
    enp11s0:
      optional: true
```

```bash
sudo netplan generate
```

### 2.3 CPU: maximum performance, mitigations off

> ⚠️ This is a single-user lab box on a private network. Don't turn mitigations off on shared or internet-facing hosts.

How the CPU behaves under full load: an all-core turbo of 3.4 GHz, about 100 W against a 130 W budget, 80 °C, and no throttling. All-core throughput is therefore capped by the turbo limit, not by heat. Two things were slowing it down:

- **Frequency policy:** the `schedutil` governor and energy bias 7 held back single-thread speed.
- **Kernel entry cost:** Ivy Bridge needs the Meltdown fix (PTI), MDS buffer clearing and retpolines on every syscall.

| | Baseline | + governor/EPB | + `mitigations=off` |
|---|---|---|---|
| Single-thread | 318.7 | 454.2 | 453.5 |
| 16-thread | 4,407 | 4,397 | 4,410 |
| Syscall | 629 ns | 319 ns | 62 ns |

`/etc/default/grub.d/99-macpro-perf.cfg`, then run `sudo update-grub`:

```bash
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT mitigations=off nowatchdog nmi_watchdog=0 cpufreq.default_governor=performance intel_iommu=on iommu=pt"
```

`/etc/systemd/system/macpro-perf.service`, then run `sudo systemctl enable --now macpro-perf`:

```ini
[Unit]
Description=Mac Pro max performance
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/bin/cpupower frequency-set -g performance
ExecStart=/usr/bin/x86_energy_perf_policy performance
# Raise the fan floor: CPU and GPUs share one heatsink
ExecStart=/bin/sh -c "echo 2000 > /sys/devices/platform/applesmc.768/fan1_min"
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
```

Also:
- Mount `/` with `noatime,commit=60`.
- Set `vm.swappiness=10`.
- Disable `unattended-upgrades` and `apt-daily-upgrade.timer`, so no background fsync storms (update by hand).

**What I skipped, and why:**
- Limiting C-states: idle cores sleeping deeply give the busy ones turbo headroom.
- `nobarrier` or turning the write cache off: corruption risk, or much slower writes.
- The `discard` mount option: the weekly trim is enough.

### 2.4 Headless KVM host with Incus

The CPU supports VT-x, EPT, APICv, nested virtualization and 1 GB pages, and the IOMMU is active.

```bash
sudo systemctl set-default multi-user.target
sudo usermod -aG incus-admin $USER
```

**Memory:** turn KSM off (it spends CPU deduplicating RAM, and 64 GB doesn't need that), and use transparent huge pages for guest RAM. Put this in `/etc/tmpfiles.d/99-vmhost.conf`:

```ini
w /sys/kernel/mm/ksm/run - - - - 2
w /sys/kernel/mm/transparent_hugepage/enabled - - - - always
w /sys/kernel/mm/transparent_hugepage/defrag - - - - defer+madvise
```

**Incus:**

```bash
cat <<EOF | sudo incus admin init --preseed
networks:
- {name: incusbr0, type: bridge, config: {ipv4.address: auto, ipv4.nat: "true", ipv6.address: none}}
storage_pools:
- {name: default, driver: dir}
profiles:
- name: default
  devices:
    root: {path: /, pool: default, type: disk}
    eth0: {name: eth0, network: incusbr0, type: nic}
EOF
```

**Disk cache mode.** Every guest `fsync` becomes a flush on the host's SSD. Measured in an Ubuntu 24.04 VM:

| `io.cache` | 4 KiB sync write | 1 GiB direct write |
|---|---|---|
| `none` (default) | 12.4 ms | 686 MB/s |
| `writeback` | 7.1 ms | 2.4 GB/s |
| `unsafe` | 0.34 ms | 3.4 GB/s |

`writeback` still honours guest flushes, so it's safe to make the default. `unsafe` ignores them, so use it only for throwaway CI or build VMs:

```bash
incus profile device set default root io.cache=writeback
incus profile create scratch
incus profile device add scratch root disk path=/ pool=default io.cache=unsafe
incus launch images:ubuntu/24.04 ci1 --vm -p default -p scratch
```

**Gotchas:**
- **`nvtop` says "No GPU" over SSH:** add yourself to the `video` and `render` groups. GPU utilisation still shows blank on GCN 1.0; use `radeontop` for that.
- **`sudo` fails with the `xterm-ghostty` terminal type:** install Ghostty's terminfo system-wide with `infocmp -x xterm-ghostty | ssh host -- sudo tic -x -o /usr/share/terminfo -`.
- **An `apple_gmux` WARNING at every boot:** it's harmless. The firmware advertises a GPU-switching chip this model doesn't have.

*Diagnosed and tuned with Claude Code over SSH.*

