PHP Performance Optimization

This document describes the PHP performance optimizations implemented in wprint3d-core for systems running on hard-disk or SD-card storage.

Overview

The optimization system uses a layered approach:

  1. Hardware Detection - Automatically detects storage type (HDD/SSD/SD-card/microSD) and available RAM

  2. PHP OPcache - Caches compiled bytecode in shared memory with JIT compilation

  3. Full Ramdisk - Mirrors entire /var/www to tmpfs for eligible roles on slow storage

  4. Optional Application Caching - Primes config and route caches

Environment Variables

Variable

Default

Description

WPRINT3D_FORCE_RAMDISK

auto

Set to 1 to force ramdisk (even on SSD or in dev mode), 0 to disable

WPRINT3D_APP_CACHE_ENABLED

false

Enable application-level caching

DEVELOPER_MODE

false

When true, skips ramdisk (unless forced) and enables faster OPcache revalidation

Performance Improvements

On hard-disk systems, expect:

  • 70-80% faster cold starts (2-5s → 0.5-1s)

  • 70-80% faster subsequent requests (200-500ms → 50-100ms)

  • 70-80% faster scheduler execution (500ms-1s → 100-200ms)

Memory Requirements

The ramdisk self-sizes based on the actual size of /var/www (excluding persistent data). It adds 25% headroom (to cover tar/filesystem overhead) and requires at least 2x the ramdisk size in available RAM.

/var/www size

Ramdisk size (1.25x)

Min RAM required (2x)

120MB

150MB

300MB

150MB

188MB

376MB

200MB

250MB

500MB

300MB

375MB

750MB

If available RAM is below the 2x threshold, the ramdisk is skipped and the app runs from disk with OPcache only.

Development Notes

In development mode (DEVELOPER_MODE=true):

  • OPcache revalidates files every 2 seconds

  • Code changes take effect quickly

  • Run php artisan clear-compiled if changes don’t appear

In production mode:

  • OPcache never revalidates (maximum performance)

  • Code changes require container restart

  • This is the correct pattern for containerized applications

Ramdisk Behavior

The ramdisk mirrors the entire /var/www directory to tmpfs at container startup. This eliminates all disk I/O for PHP file loading on slow storage (HDD, SD card, microSD). The ramdisk persists for the container’s lifetime and is automatically cleaned up by the kernel when the container stops.

Role-Based Eligibility

Most PHP-based roles benefit from a ramdisk. Even long-running processes like Octane benefit because cold start on HDD requires reading ~116MB of vendor files before classes go resident:

Role

Ramdisk

Reason

server (Octane)

Enable

Cold start reads all vendor files from disk

concurrency-scheduler

Enable

Supervisor respawns queue:work workers

ws-server

Enable

Crash-restart loop spawns fresh PHP

scheduler

Enable

Each cron job is a fresh PHP process

mapper

Skip

Long-running udev monitor, not PHP-heavy

streamer

Skip

Native binaries, not PHP

Multi-role mode: When ROLE contains a comma-separated list (e.g., ROLE=server,scheduler,concurrency-scheduler,ws-server), all processes run under supervisord in a single container sharing one ramdisk. The default docker-compose.yml uses this mode via the backend service, which runs all four PHP-based roles in a single container with one shared ramdisk (~116MB).

What’s on Ramdisk vs. Disk

On ramdisk (entire /var/www minus exclusions):

  • vendor/ — PHP dependencies (~116MB, the main I/O bottleneck)

  • app/, config/, routes/, lang/ — application code

  • bootstrap/cache/, storage/framework/ — ephemeral caches

  • public/, internal/ — static assets and scripts

Excluded (kept on disk for persistence/debugging):

  • storage/app/gcode/ — user-uploaded G-code files

  • storage/app/recordings/ — camera recordings

  • storage/app/public/ — user-uploaded media

  • storage/app/plugins/ — plugin state

  • storage/logs/ — application logs

  • .env — application secrets (only when it’s a regular file, not a symlink)

  • .external-configs/ — external secret volume mount

How It Works

  1. run.sh creates all required directories (including persistent subdirectories)

  2. detect-hardware.sh identifies storage type and available RAM

  3. ramdisk-setup.sh measures /var/www size, adds 10% headroom

  4. If available RAM >= 2x ramdisk size, a tmpfs is mounted

  5. /var/www is copied to the ramdisk (excluding persistent dirs)

  6. Persistent directories are stashed via bind mounts before the overlay

  7. The ramdisk is bind-mounted over /var/www

  8. Persistent directories are bound back from the stash onto the overlay

If any step fails, a full rollback restores the original /var/www.

Storage Type Detection

Storage

Detection

Ramdisk

HDD

/sys/block/*/queue/rotational=1

Enabled

SSD

/sys/block/*/queue/rotational=0 (non-mmcblk)

Skipped (unless forced)

microSD/eMMC

Device name starts with mmcblk

Enabled

SD card

/proc/mounts contains mmcblk or sdcard

Enabled

Unknown

Fallback

Enabled

Troubleshooting

Verify OPcache is working

php internal/test-opcache.php

Check hardware detection

source internal/detect-hardware.sh
echo "Storage: $WPRINT3D_STORAGE_TYPE"
echo "Memory: ${WPRINT3D_AVAILABLE_MEMORY_MB}MB"

Force ramdisk on SSD systems

export WPRINT3D_FORCE_RAMDISK=1

Disable ramdisk on low-memory systems

export WPRINT3D_FORCE_RAMDISK=0