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):
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:
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), addradeon.si_support=0 amdgpu.si_support=1toGRUB_CMDLINE_LINUX_DEFAULTand runsudo 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:
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. 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:
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.
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.
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:
enp11s0:
optional: true
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
schedutilgovernor 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:
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:
[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
/withnoatime,commit=60. - Set
vm.swappiness=10. - Disable
unattended-upgradesandapt-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.
nobarrieror turning the write cache off: corruption risk, or much slower writes.- The
discardmount 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.
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:
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:
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:
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:
nvtopsays "No GPU" over SSH: add yourself to thevideoandrendergroups. GPU utilisation still shows blank on GCN 1.0; useradeontopfor that.sudofails with thexterm-ghosttyterminal type: install Ghostty's terminfo system-wide withinfocmp -x xterm-ghostty | ssh host -- sudo tic -x -o /usr/share/terminfo -.- An
apple_gmuxWARNING 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.