LMS LABS · MOODLE ADMIN TOOL
Speed Up for Moodle
Find out exactly what is slowing your Moodle down, see which plugin is responsible, and fix it one step at a time. Free forever, from LMS Labs.
Chapter 1
Before you start: one server requirement
Speed Up works on any Moodle 4.4 to 5.3 site straight away. To see which plugin is slowing a page, your server also needs the free Excimer PHP extension. Your host installs it with one command.
- Excimer is part of PHP, not a Moodle plugin, so it works with every Moodle version.
- It is free and open source, made by the Wikimedia Foundation and used on Wikipedia's live servers.
- Without it, Speed Up still measures pages, the database, sessions, tasks, security and Quick Check. It just cannot name the plugin.
Show me how to install Excimer
Ubuntu or Debian (match the number to your PHP version):
sudo apt install php8.3-excimersudo systemctl restart php8.3-fpmOther Linux: sudo pecl install excimer then add extension=excimer.so to php.ini and restart PHP. On managed hosting, ask your host to “install the Excimer PHP extension and restart PHP-FPM”.
Remember to restart PHP-FPM (or Apache): command-line PHP sees the extension straight away, but web pages only do after the restart.
Excimer on mediawiki.org · Excimer on PECLWhen Excimer is working, the header shows a green Excimer on light.
- 1Recording status: green when measuring, amber when cron has stopped
- 2Excimer status: green means plugin names are available
- 3All reports opens the detailed reports
- 4Settings
Chapter 2
What Speed Up does
Speed Up finds out exactly what is slowing your Moodle down, names the plugin responsible, and walks you through the fix, one step at a time.
Chapter 3
Install
- Download Speed Up from the Moodle Marketplace or lms-labs.com.
- Go to Site administration > Plugins > Install plugins, drop in the ZIP and click Install plugin from the ZIP file.
- Click through the upgrade screens.
- Make sure Moodle cron runs every minute.
- Open Site administration > Reports > Speed Up. You start on step 1.
Installing by hand
Unzip into admin/tool/speedup (public/admin/tool/speedup on Moodle 5.1 and later), then visit Site administration > Notifications.
Chapter 4
Step 1 · Set up
Speed Up checks three things: recording is on, cron is processing the data, and Excimer is installed. Anything not ready opens its own fix, written so anyone can follow it.
- 1The four steps. You can jump to any of them
- 2Recording is on
- 3Cron is not processing data yet, so its fix opens
- 4Plain instruction anyone can follow
- 5“Show me how” reveals the exact command
- 1Recording
- 2Cron processing the data
- 3Plugin attribution (Excimer)
- 4One button moves you on
Chapter 5
Step 2 · Quick Check
Quick Check is a one-minute, safe test of the things every page depends on. Run it now, and again after each change. Any result rated fair or poor shows how to fix it.
- 1Database round trip and commit
- 2Each Moodle folder is timed, including fsync
- 3Moodle's application cache
- 4Your login page over HTTP, with every redirect
- 5Run it again after every change
Chapter 6
Step 3 · Collect
Benchmarks test fake traffic. Speed Up times the pages your real users open, so busy pages count more than quiet ones. A day of normal use covers the morning rush, cron jobs and quiet hours.
- 1Progress towards reliable results
- 2Hours and page loads measured
- 3Start fresh after a big change
- 4On to your fixes
Chapter 7
Step 4 · Fix
One fix per screen, ranked by how many hours of waiting it costs your users each day. Each fix says why it matters, gives numbered steps, and tells you how to confirm it worked.
- 1Where you are in the list
- 2How serious it is, and where it was found
- 3The problem in one line
- 4Numbered steps to fix it
- 5How to confirm it worked
- 1Measured impact on your users
- 2The plugin and the time it adds
- 3Step 1: check for an update
- 4“Show me how” opens the technical detail
- 1How to confirm it worked
- 2Technical detail for developers
- 3Mark as done
- 4Next fix
What Speed Up can find
Chapter 8
All reports
The plan is built from detailed reports. Open them with All reports in the header, and return with Back to your plan.
- 1Back to your plan at any time
- 2Detailed reports
- 3Period: 24 hours, 7 days or 30 days
- 4Headline numbers
- 1The plugin
- 2Time it adds per request
- 3Where the time goes
- 4Where its code starts
- 1Headline cost of this plugin
- 2Pages where it costs the most
- 3Where it is called from
- 1Page
- 2Typical time
- 3Slowest 5%
- 4Share of all waiting
- 1Response time distribution
- 2Who uses the time on this page
- 1The call tree
- 1Tasks ranked by total time
- 2Ad hoc task queue
- 1The finding
- 2Evidence grade
- 3What the grades mean
- 1Run Quick Check
- 2One probe
Chapter 9
Settings
Defaults suit almost every site. Site administration > Plugins > Admin tools > Speed Up settings.
| Setting | Default | What it does |
|---|---|---|
| Recording | On | Measure page loads. |
| Record requests | 100% | Share of page loads measured. Recording adds well under a millisecond. |
| Profile requests | 5% | Share of page loads whose code is sampled (needs Excimer). |
| Sampling interval | 10 ms | How often a profiled page is sampled. |
| Skip profiling above this load per CPU | 4 | Automatic back-off on busy servers. |
| Slow request threshold | 2000 ms | Slower page loads are kept individually with their call trees. |
| Buffer limit | 100 MB | Disk cap if cron stops. |
| Keep statistics | 35 days | How long statistics are kept. |
| Keep slow request details | 7 days | How long individual slow requests are kept. |
| Daily security check | On | Download public PHP release and end-of-life data. |
| Show the LMS Labs banner | On | A small strip about other LMS Labs plugins. |
- 1Share of page loads measured
- 2Share of page loads profiled
- 3Buffer limit if cron stops
Chapter 10
In Moodle's own reports
Speed Up adds checks to Reports > Performance overview and Reports > Security checks.
Chapter 11
How it works
Simple on the surface, careful underneath. Each card explains one technique in plain words. Open a card for the developer detail.
A stopwatch on every pageSpeed Up starts a stopwatch the moment Moodle loads its settings and stops it when the page is finished. It notes how long each stage took, how many database calls the page made and how long it waited for the user's session.Developer detail
Hooks into \core\hook\after_config (Moodle 4.5+) and the legacy tool_speedup_after_config() callback on 4.4. The request start comes from $_SERVER['REQUEST_TIME_FLOAT']; an optional X-Request-Start header adds queue time before PHP.
At shutdown it reads counters Moodle already keeps: $DB->perf_get_reads(), perf_get_writes() and perf_get_queries_time(), the session lock wait and hold times Moodle keeps in $PERF->sessionlock, memory_get_peak_usage(), getrusage() CPU time and http_response_code(). No extra queries are made.
Speed Up's own admin pages and Quick Check's test requests (header X-Speedup-Probe) are not recorded.
Sampling which code is runningOn a small share of pages (5% by default) Speed Up takes a snapshot of the running code every 10 milliseconds. Adding up the snapshots shows where the time really went, without slowing the page.Developer detail
Uses the Excimer PHP extension (Wikimedia): new ExcimerProfiler() with EXCIMER_REAL and a 10 ms period. Excimer interrupts PHP on a timer and records the stack, so cost scales with time, not with the number of function calls, unlike tracing profilers.
Stacks are compacted to file paths relative to the Moodle code plus class::function names, never line numbers, arguments or values. Long requests keep every Nth sample with weight N (cap 3,000 samples, depth 120), so the whole request is covered.
Profiling is skipped when the 1-minute load per CPU is above the configured limit (cgroup cpu.max quotas are respected in containers).
Write later, never during the pageMeasurements are saved after the page has already been sent to the browser and the user's session released. Each one is a single line added to a small file. A background task does the database work later.Developer detail
The shutdown callback only builds the record. It then calls register_shutdown_function() during shutdown, which PHP runs after Moodle's own shutdown manager has closed the session. On PHP-FPM, fastcgi_finish_request() sends the response first.
Lines are appended to one of 16 shard files per web server in $CFG->tempdir/tool_speedup/buffer using fopen('a') + flock(LOCK_EX|LOCK_NB). If the lock is busy it tries one neighbour shard, then drops the record rather than wait. fstat() on every write caps each file at 8 MB.
Circuit breaker: if a write takes over 50 ms (for example a stalled NFS share), a marker in $CFG->localcachedir pauses recording on that server for 5 minutes. Single-server sites can set $CFG->tool_speedup_bufferdir to local disk.
Two-phase processingEvery minute a scheduled task renames the files that were being written and processes the ones renamed a minute earlier, so a file is never read while a page might still be writing to it.Developer detail
buf-*.jsonl files are renamed to proc-*; files renamed in the previous run are read, aggregated in memory and written in one delegated transaction (a new transaction every 50,000 records). Files are deleted only after commit, so a database error never loses or double counts data.
Existing rows are preloaded with one SELECT … WHERE period IN (…) per table, new rows go in with insert_records(), and each existing row is updated once per run, so query counts depend on distinct pages, not files or web servers.
Charging time to the right pluginEach snapshot is charged to the plugin closest to the code that was running. If a block asks the database for data, that database time counts against the block, not against Moodle.Developer detail
A directory map built from core_component::get_plugin_types() and plugin lists maps each file to its component (longest prefix, Moodle 5.1 public/ aware). Walking from the innermost frame outwards, the owner is the nearest non-core frame; cache stores, cache locks and log stores are transparent and charge their caller.
The innermost frame classifies the time as database, external call (curl), cache, file, session or PHP code. Each plugin also records its entry point as "caller → function", which is what a developer needs to find the code.
Percentiles that add upTypical and slowest-5% times are worked out from a fixed set of time buckets, so hours, days and pages can be added together and still give the right answer.Developer detail
Every page row keeps a histogram with fixed bucket bounds from 50 ms to 34 s. Histograms merge by simple addition, so p50 and p95 can be computed for any period and any group of pages without storing individual requests.
One site-wide row per hour holds totals and the site histogram, so totals and trends read about 840 rows for 35 days. Page rows older than two days are rolled up to one row per page per day.
Ranking by impact on peopleFixes are ranked by how much waiting they cause your users each day, in user-hours. A small delay on the dashboard can matter more than a big delay on a page nobody opens.Developer detail
Impact = time attributable to the cause per request × requests per day, expressed in user-seconds per day. For a plugin it is its owned time per profiled request × total requests; for a page, waiting above a healthy baseline × that page's traffic.
Rules have minimum sample sizes and only fire when the evidence is strong enough (for example 200 profiled requests before a plugin cost is "strongly supported").
Honest evidence gradesEvery finding says how sure Speed Up is: observed, possible cause, strongly supported, or verified. Anything it cannot see is listed as "not observable", never as healthy.Developer detail
An hourly analyser runs rules for plugin cost, external calls, slow pages, heavy queries, server errors, memory, session lock waits, start-up time, PHP-FPM queueing, task failures and backlogs, data loss and software support.
Findings are stored by rule and scope. They update while the problem continues, resolve automatically when it stops, reopen if it comes back, and stay hidden if an admin marks them done. Plugins that are uninstalled disappear at once.
Built not to slow your siteMeasured on Moodle 5.3, Speed Up adds about 1 to 2 milliseconds to a typical page. It never writes to the database during a page, and it backs off by itself if anything looks unhealthy.Developer detail
Every hook is wrapped in try/catch (\Throwable) and silent. Recording stops if the buffer has not been processed for two hours (cron stopped), pauses for 15 minutes if the buffer passes its limit (100 MB by default), and the oldest data is dropped first.
Admin pages read cached results keyed by the last processing time and the plugin list hash, so large statistics tables are not re-read on every view. Quick Check has a 60 s overall budget and a 20 s cap on its HTTP test.
A/B test on Moodle 5.3, 800 requests each way: median +1.85 ms (1.3%), mean +0.3%.
Quick Check probesQuick Check times the things every page depends on: a database round trip and commit, a small file write in each Moodle folder, the cache, and your login page.Developer detail
100 single-row reads; 20 write-and-commit transactions on Speed Up's own probe table; a 4 KB write with fsync, read and delete in dataroot, tempdir, cachedir and localcachedir (file system type from /proc/mounts, network shares flagged); a set/get on the application cache definition; and the login page fetched anonymously, following redirects manually with Moodle's cURL security rules applied first.
It holds a lock so only one run happens at a time, and releases the admin's session so other tabs keep working.
PHP security feedsOnce a day Speed Up downloads PHP's official release list and public end-of-life dates, then checks your versions on your own server. Nothing about your site is sent.Developer detail
Sources: php.net/releases/index.php?json=1&version=X.Y (security-tagged releases) and endoflife.date/api/{product}.json for PHP, Moodle and your database. Each source is stored with its own timestamp; a failed download keeps the last good data until it is 8 days old.
The PHP that serves web pages is recorded separately from command-line PHP. Ubuntu, Debian and Red Hat builds receive fixes without changing the version number, so for those Speed Up asks you to confirm updates instead of declaring the site vulnerable.
Part of Moodle's own reportsSpeed Up adds its checks to Moodle's Performance overview and Security checks, so the results also appear where administrators already look.Developer detail
Implements tool_speedup_performance_checks() (recorder, OPcache, cache stores, sessions, production settings, log table size) and tool_speedup_security_checks() (software support) with the Check API. Log size uses database statistics (pg_class.reltuples, information_schema) instead of COUNT(*).
Privacy by designSpeed Up stores page names and timings only. No names, no user IDs, no IP addresses, no page content.Developer detail
Pages are recorded as scripts (plus a web service function name, checked against installed functions). Parameter values, cookies and form data are never read. Users fall into two groups, guest and signed-in, so no record can point to one person. The Privacy API provider declares that no personal data is stored.
Chapter 12
Privacy, permissions and data
| Capability | Allows | Default |
|---|---|---|
tool/speedup:view | View the plan and reports | Site administrators |
tool/speedup:manage | Run Quick Check, refresh security data, mark fixes done, start fresh | Site administrators |
Uninstalling removes Speed Up's tables, its buffer folder and its security data file.
Chapter 13
Questions
Will Speed Up slow my site down?
No noticeable amount. On Moodle 5.3 it added about 1 to 2 ms to a typical page in an 800-request A/B test. It writes after the page has been sent, never waits for a lock, and pauses itself if storage is slow or cron stops.
It says Excimer is not installed, but my host installed it.
PHP-FPM (or Apache) must be restarted to load a new extension. Command-line PHP sees it straight away; web pages only after the restart. Ask your host to run sudo systemctl restart php8.3-fpm (use your PHP version).
Do I need the "Excimer Profiler" Moodle plugin?
No. That is a different plugin. Speed Up uses the Excimer PHP extension directly.
I removed a plugin. Why do I still see it?
Speed Up hides uninstalled plugins and their tasks, and refreshes its fixes the next time an administrator opens it. After a bigger change, use Start fresh on step 3.
Does it work on a cluster with several web servers?
Yes. Each web server writes its own buffer files in Moodle's shared temp folder, and one cron run processes them all in a single transaction.
Is it really free?
Yes, free forever, with no paid version and no limits. It is a gift to the Moodle community from LMS Labs.
Chapter 14
Changelog
v2.0.0 · 1 November 2026
- Guided plan as the home page: Set up, Quick Check, Collect, Fix, one screen at a time.
- Fixes one at a time with plain steps, "Show me how" detail and a way to confirm each fix.
- Fix steps for server set-up problems and every fair or poor Quick Check result.
- Live Excimer status, Start fresh, auto-scroll, uninstalled plugins hidden.
- Faster and safer: writes after the response, non-blocking locks, a circuit breaker, batched processing, site totals, daily roll-up and cached reports.
v1.0.0 · 1 November 2026
- First release: always-on recording, plugin attribution, reports, findings, Quick Check and PHP security checks.
Chapter 15
Every screen
LMS LABS · MOODLE ADMIN TOOL
Speed Up · release and access
Find what slows your Moodle site, see which plugin is responsible with the free Excimer extension, and work through fixes one step at a time. Free forever, with no AI-credit costs.
Free forever. No site unlock, paid version, limits, AI or credits. Declared support: Moodle 4.4–5.3, PostgreSQL, MySQL and MariaDB, PHP 8.1+.
Back to Documentation