Skip to documentation

    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-fpm

    Other 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 PECL

    When Excimer is working, the header shows a green Excimer on light.

    Live status in the header
    Live status in the header. Two live lights show whether Speed Up is recording and whether Excimer is installed.
    1. 1Recording status: green when measuring, amber when cron has stopped
    2. 2Excimer status: green means plugin names are available
    3. 3All reports opens the detailed reports
    4. 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.

    Free foreverA gift to the Moodle community from LMS Labs. No paid version, no limits.
    No AIRule-based measurement. No AI credits, nothing sent to ChatGPT.
    Stays on your serverStores page names and timings only, and never sends information about your site.
    Moodle 4.4 to 5.3PostgreSQL, MySQL and MariaDB. PHP 8.1 or later.

    Chapter 3

    Install

    1. Download Speed Up from the Moodle Marketplace or lms-labs.com.
    2. Go to Site administration > Plugins > Install plugins, drop in the ZIP and click Install plugin from the ZIP file.
    3. Click through the upgrade screens.
    4. Make sure Moodle cron runs every minute.
    5. 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.

    Install from a ZIP
    Install from a ZIP. Site administration > Plugins > Install plugins.

    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.

    Step 1 · Set up, with a problem to fix
    Step 1 · Set up, with a problem to fix. Anything not ready is marked amber and opens its own fix. Commands stay inside “Show me how”.
    1. 1The four steps. You can jump to any of them
    2. 2Recording is on
    3. 3Cron is not processing data yet, so its fix opens
    4. 4Plain instruction anyone can follow
    5. 5“Show me how” reveals the exact command
    Step 1 · Set up, all ready
    Step 1 · Set up, all ready. Recording, cron and Excimer are all green, so Speed Up can measure everything and name slow plugins.
    1. 1Recording
    2. 2Cron processing the data
    3. 3Plugin attribution (Excimer)
    4. 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.

    Step 2 · Quick Check
    Step 2 · Quick Check. A one-minute, safe test of your database, storage, cache and web server, rated good, fair or poor.
    1. 1Database round trip and commit
    2. 2Each Moodle folder is timed, including fsync
    3. 3Moodle's application cache
    4. 4Your login page over HTTP, with every redirect
    5. 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.

    Step 3 · Collect real traffic
    Step 3 · Collect real traffic. Speed Up times the pages real users open. Results are reliable after a day of normal use.
    1. 1Progress towards reliable results
    2. 2Hours and page loads measured
    3. 3Start fresh after a big change
    4. 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.

    Step 4 · Fix 1 of 7
    Step 4 · Fix 1 of 7. The most important problem first, ranked by how much waiting it causes your users each day.
    1. 1Where you are in the list
    2. 2How serious it is, and where it was found
    3. 3The problem in one line
    4. 4Numbered steps to fix it
    5. 5How to confirm it worked
    Step 4 · A slow plugin, named
    Step 4 · A slow plugin, named. Speed Up names the plugin, says how much time it adds to every page, and how many user-hours that costs per day.
    1. 1Measured impact on your users
    2. 2The plugin and the time it adds
    3. 3Step 1: check for an update
    4. 4“Show me how” opens the technical detail
    Step 4 · Finish the fix and move on
    Step 4 · Finish the fix and move on. Mark a fix as done, or go to the next one. Nothing else competes for your attention.
    1. 1How to confirm it worked
    2. 2Technical detail for developers
    3. 3Mark as done
    4. 4Next fix

    What Speed Up can find

    Slow pluginsTime each add-on adds to every page, and the function responsible.
    External callsPlugins that wait for another website while the page loads.
    Too many queriesPages that read the database one record at a time.
    Session waitsUsers' requests waiting for each other on the session lock.
    Server set-upOPcache, cache stores, sessions, debug settings and log size.
    Background tasksTasks that fail, run long or queue for hours.
    PHP securityMissing PHP security releases and end-of-life software.
    QueueingRequests waiting for a free PHP worker.
    Slow storageMoodle folders on slow or network disks.

    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.

    All reports · Overview
    All reports · Overview. Headline numbers and the response-time trend for the whole site.
    1. 1Back to your plan at any time
    2. 2Detailed reports
    3. 3Period: 24 hours, 7 days or 30 days
    4. 4Headline numbers
    All reports · Plugins
    All reports · Plugins. Every add-on ranked by the time it adds to an average page, split into database, external calls, cache, files, session and PHP code.
    1. 1The plugin
    2. 2Time it adds per request
    3. 3Where the time goes
    4. 4Where its code starts
    All reports · One plugin
    All reports · One plugin. The pages a plugin slows, and the exact function calls that cost the time.
    1. 1Headline cost of this plugin
    2. 2Pages where it costs the most
    3. 3Where it is called from
    All reports · Pages
    All reports · Pages. Every page ranked by total waiting time, with typical and slowest-5% times.
    1. 1Page
    2. 2Typical time
    3. 3Slowest 5%
    4. 4Share of all waiting
    All reports · One page
    All reports · One page. Response-time distribution and the components that own this page's time.
    1. 1Response time distribution
    2. 2Who uses the time on this page
    All reports · Call tree
    All reports · Call tree. A sampled call tree of one slow request: which functions ran, and for how long. File paths and function names only.
    1. 1The call tree
    All reports · Background tasks
    All reports · Background tasks. Scheduled and ad hoc tasks by total time, failures and queue age.
    1. 1Tasks ranked by total time
    2. 2Ad hoc task queue
    All reports · Software security
    All reports · Software security. Is your PHP missing security fixes, and are PHP, Moodle and your database still supported?
    All reports · Findings
    All reports · Findings. Every finding with its evidence grade. The plan shows the same items one at a time.
    1. 1The finding
    2. 2Evidence grade
    3. 3What the grades mean
    All reports · Quick Check results
    All reports · Quick Check results. Typical and slowest times for every probe, with thresholds and history.
    1. 1Run Quick Check
    2. 2One probe

    Chapter 9

    Settings

    Defaults suit almost every site. Site administration > Plugins > Admin tools > Speed Up settings.

    SettingDefaultWhat it does
    RecordingOnMeasure page loads.
    Record requests100%Share of page loads measured. Recording adds well under a millisecond.
    Profile requests5%Share of page loads whose code is sampled (needs Excimer).
    Sampling interval10 msHow often a profiled page is sampled.
    Skip profiling above this load per CPU4Automatic back-off on busy servers.
    Slow request threshold2000 msSlower page loads are kept individually with their call trees.
    Buffer limit100 MBDisk cap if cron stops.
    Keep statistics35 daysHow long statistics are kept.
    Keep slow request details7 daysHow long individual slow requests are kept.
    Daily security checkOnDownload public PHP release and end-of-life data.
    Show the LMS Labs bannerOnA small strip about other LMS Labs plugins.
    Settings
    Settings. Site administration > Plugins > Admin tools > Speed Up settings.
    1. 1Share of page loads measured
    2. 2Share of page loads profiled
    3. 3Buffer limit if cron stops

    Chapter 10

    In Moodle's own reports

    Speed Up adds checks to Reports > Performance overview and Reports > Security checks.

    Moodle's Performance overview
    Moodle's Performance overview. Speed Up adds checks for OPcache, cache stores, sessions, development settings and log size.
    Moodle's Security checks
    Moodle's Security checks. Speed Up adds a software support check: PHP security fixes and end-of-life dates.

    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

    What is storedPage paths (for example /course/view.php or a web service function name), timings, counts and a user group (guest or signed-in). Never user IDs, IP addresses, parameter values, cookies, form content or page content.
    External connectionsNone during page loads. The optional daily check downloads public files from php.net and endoflife.date. The banner uses images inside the plugin and loads nothing from outside.
    CapabilityAllowsDefault
    tool/speedup:viewView the plan and reportsSite administrators
    tool/speedup:manageRun Quick Check, refresh security data, mark fixes done, start freshSite 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

    Speed Up is free forever, from LMS Labs by LMS Hosting Services. Moodle™ is a registered trademark of Moodle Pty Ltd. LMS Labs is not affiliated with or endorsed by Moodle Pty Ltd.

    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