...

Server CPU Benchmarking for PHP: Tests for Real-World Web Hosting Workloads

A single CPU score is not enough to evaluate a server's performance for PHP. Combine a reproducible PHP Microbenchmark With an HTTP test of your application: This allows you to compare a specific computational task while simultaneously monitoring response times, successful throughput, and errors under load. A web hosting benchmark also takes into account the database, cache, and PHP-FPM. Its process pool can limit requests without the CPU being the sole bottleneck. Comparable conditions and a subsequent diagnosis are crucial.

What a PHP benchmark is meant to answer

A PHP CPU benchmark can first show how long a system takes to complete a specific computational task. This is particularly useful when a single request spends a lot of time on PHP calculations. A higher Single-Core Performance can speed up the processing of such tasks; however, the response time of an entire website cannot be determined based on CPU performance alone.

A second question concerns the application's behavior under concurrent access: How many correct responses does it return per second, and how long do users have to wait? To answer this, a Web Hosting Benchmark via HTTP makes sense. It tracks the path through web servers and PHP, as well as the database, cache, and network, if applicable. It is precisely this combination that makes it practical, but it prevents any isolated conclusions about CPU performance.

The third question concerns the bottleneck. For example, if a request is waiting for a database query, a faster computation says little about its total execution time. A cache also affects the result: If a page is delivered in its entirety before PHP processes it, the request does not measure the execution of the dynamic application.

Under concurrent load, the PHP-FPM pool can also limit the number of requests processed simultaneously. Its status page provides information on, among other things, active processes and queued requests. A growing queue is therefore a reason to investigate the issue, not direct evidence of a CPU that is running too slowly.

When choosing a hosting provider, it helps to consider these questions separately: first, the comparable unit of work; then, performance under low and high loads; and finally, the resources that limit performance. The article on explains how CPU, RAM, and storage generally interact: Hardware for High-Performance Web Hosting.

Distinguishing Between CPU Scores and Application Tests

A Microbenchmark repeats a small, precisely defined task. With PHPBench, for example, you can analyze a data-processing function under specified conditions. The result helps you compare this function and its runtime environment; it does not automatically describe a complete request or the performance of a CMS or online store.

AI-generated stock image of a removed server processor on an antistatic mat
AI-generated stock image: A microbenchmark evaluates a specific task on the system being tested, not the entire web stack.

An HTTP application test answers a different question: How does the selected application respond via the web stack that is actually in use? It takes into account, for example, PHP-FPM, the database, and caches, to the extent that they are involved in the request being tested. This makes it suitable for evaluating a hosting service, but it cannot, on its own, determine which component is responsible for a particular difference.

SPEC CPU supplements such tests with standardized, computationally intensive workloads. SPEC CPU 2026 includes integer and floating-point suites, as well as "Speed" and "Rate" results. "Speed" refers to the time taken to complete tasks, while "Rate" refers to throughput. A “Speed” value is not automatically a pure single-core value: SPEC notes additional parallelism in the integer “Speed” tests of the 2026 suite.

For a reliable SPEC comparison, the suite, metric, and result type must base or peak match. The fully tested system is also important: In addition to the processor, factors such as memory, the compiler, and the configuration influence the result. Published values are therefore not an isolated characteristic of the CPU model and are no substitute for a PHP test.

SPEC CPU 2017 and CPU 2026 use different test suites; their scores are not on the same scale. Anyone making a preliminary selection should therefore compare the complete results report rather than an abridged ranking. Only a properly designed application test can then determine whether a candidate is suitable for your specific application.

Establish comparable test conditions

A fair comparison starts with the same application version and a comparable dataset. The chosen route and its expected response must also match: A product page with many database accesses answers a different question than a simple API function. Therefore, don’t just check whether a response is received, but also whether its content matches the intended task.

Record the PHP version and extensions, as well as the web server, PHP-FPM configuration, and database. The network path between the load generator and the application should also be included in the log. Different paths or database locations can affect the measured response time, even if PHP execution were equally fast on both systems.

It is particularly important to distinguish between CLI and PHP-FPM: A command-line test does not automatically use the same runtime configuration as an HTTP request. Document the OPcache and JIT settings actually used in both contexts. Their effects and default values depend, among other things, on the PHP version; a blanket assumption is not sufficient for the comparison.

The cache status must be comparable. A cold cache and a cache that has already been warmed up answer different questions; both can be relevant, but should be evaluated separately. The same applies to data volume and test data: If the scope of work changes, a difference in time can no longer be accurately attributed to the system.

Also note the CPU model, assigned vCPUs, and visible resource limits, as well as the selected load and the number of iterations. If two different hosting packages are intentionally compared, the result provides insight into their respective overall configurations. Differences in the processor, limits, database, or caching should not be interpreted solely as a CPU advantage without further analysis.

Select Appropriate Workloads and Metrics

The choice of test depends on the question you want to answer. A Microbenchmark examines a limited computational task; an HTTP test takes into account the path through the web stack. SPEC results supplement the comparison with standardized CPU-intensive system tests, but do not replace testing your own PHP application.

Three Types of Tests and Their Limitations
Test TypeStatement and ApplicationMost Important Border
PHP MicrobenchmarkCompares the execution of a specific PHP function under specified conditions.For now, the result applies only to the tested code and the runtime.
SPEC CPUCompares systems based on standardized computationally intensive tasks; speed and rate examine different aspects.This is not a PHP web hosting test; please note the suite and complete system configuration.
HTTP Application TestingTests an endpoint's response times and throughput using the selected web stack.The result consists of several components and does not isolate the CPU.

For a single dynamic request, choose a representative page or API route and start with a low level of parallelism. The route must actually execute PHP: While a response delivered entirely from an upstream page cache would be a valid cache test, it says little about PHP processing.

For concurrent visitors, you test the same endpoint at several specified load levels. This allows you to determine whether response times and successful throughput change as concurrency increases. For a database-intensive route, the data set, database location, and cache state should remain the same between comparison runs.

You can use PHPBench to analyze a CPU-intensive function from the application in isolation—for example, data processing without network access. A better result initially indicates only an advantage for that specific function under the selected runtime conditions. Whether this translates to a noticeable advantage for a complete page must be determined by application testing.

Run a staging test with wrk

Test only in an isolated staging environment with explicit permission. Set up a safe, representative read route and use appropriate test data. Before starting, define a maximum load and termination criteria, such as errors, timeouts, or disruption to other services.

The following command is intended for a terminal on a local staging instance set up specifically for this purpose. The prepared route must be accessible on port 8080; the command actually generates traffic and is not intended for an unknown or production system.

Terminal
wrk -t2 -c4 -d30s --latency http://127.0.0.1:8080/

The call uses two load generator threads, four open connections, and a runtime of 30 seconds. The option --latency Requests a detailed latency report. Four connections are a starting point chosen for this example; they are not a general recommendation regarding visitor numbers or server capacity.

However, the standard percentile output from wrk does not include a p95 value. To ensure a reproducible p95 analysis, save the following Lua script on the load generator as percentiles.lua. The p50 and p95 values from the latency statistics are given in microseconds; dividing by 1,000 yields milliseconds.

Code
function done(summary, latency, requests)
  io.write(string.format("p50: %.0f us\n", latency:percentile(50.0)))
  io.write(string.format("p95: %.0f us\n", latency:percentile(95.0)))
end

To perform the actual measurement, run the same local staging test using the script. The file path assumes you are in the directory containing the script file. This command also generates load; document the two percentiles displayed, along with any errors and the response quality, which was tested separately.

Terminal
wrk -t2 -c4 -d30s --latency -s percentiles.lua http://127.0.0.1:8080/

Plan a separate Warm-up phase before you begin recording the actual measurement runs. Then repeat each specified load level and, if possible, vary the order of the comparison systems. Note how long the warm-up took and whether the cache was in the desired state at the start of the measurement.

Increase the number of connections only within the agreed-upon limits, and check the termination criteria after each step. Also monitor the load generator: If it is operating at full capacity, it may limit the result. Additionally, check status codes and response content; an error page that loads quickly or an incorrect response does not count as a successful application request.

Document load levels and results

A measurement log links the numbers to the conditions under which they were generated. For each run, record the environment, endpoint, cache state, and load level along with the results. The following template uses, among other things, metrics provided by wrk or the FPM status page; you must supplement it with a review of the response content.

Test Report for an HTTP Run
FieldWhat Is Recorded
SurroundingsServer or hosting package, PHP and application versions, and relevant configuration
Workload and CacheRoute, Test Data, Response Verification, and Cache Status
Load stageLoad model, connection count, or specified query rate, duration, and warm-up phase
Successful InquiriesCorrect responses per second; check status codes and content separately
LatencyMedian and p95 for the same run; output via the Lua script shown when running wrk
ErrorError Responses and Timeouts
Resource ReferencesCPU utilization and, if available, FPM process status and queue

The median describes the middle value of the observed response times. The p95 is the value that 95 percent of the measured responses do not exceed. Together, these two metrics show whether, in addition to a typical request, the slower portion of the distribution is also changing. Always interpret them in conjunction with errors and timeouts.

Distinguish between a fixed number of connections and a specified request rate. In a connection-based test like the one in the example, slow responses can result in fewer new requests per second being generated over the same connections. The measured latency does not necessarily reflect the behavior under a consistently high arrival rate.

Therefore, compare only sufficiently similar load points: the same route and response validation, comparable cache states, and the same load model and load level. A low p95 with low parallelism is not directly comparable to a p95 under overload conditions. Report multiple runs and their variance, rather than presenting a single favorable value as the result.

Examine FPM and resource limits

If both the queue and the p95 response time increase as the load increases, it's worth taking a look at the PHP-FPM pool. Compare the current values for active processes, idle processes and listen queue with the configured upper limit pm.max_children. If all permitted processes are active, none are free, and requests are queued, this indicates a Pool Boundary or workers that have been busy for a long time, but not necessarily a CPU that's too slow.

AI-generated illustration of discs waiting in front of the limited openings of a process pool
AI-generated illustration: Busy workers can cause pending requests without the CPU being the root cause.

The Ad max children reached On the other hand, it indicates that the process limit was reached earlier, starting from the time the pool was launched. On its own, this does not prove that there is currently a queue, nor that all existing processes are currently busy. Similarly, the maximum number of existing processes does not mean that all of them are active.

Workers may also be waiting for database queries or other external services. Therefore, compare the pool status and CPU utilization with the observed response times: A full queue with low CPU utilization suggests that you should first investigate wait times and worker utilization. A larger pool size is not automatically the solution, because additional processes also consume resources.

The FPM status values apply to the respective pool; counters are reset upon a restart. Therefore, record the pool and the restart time in the measurement log, and compare counter readings only within an appropriate time frame. Protect an activated status page from unauthorized access, as it discloses operational information about the pool.

With VPS and shared hosting, an assigned vCPU does not necessarily correspond to an exclusive physical core. Where cgroup-v2 data is available, it shows cpu.max the configured CPU bandwidth limit; cpu.stat can include, among other things, counters for Throttling included. Changes to these counters during a run help diagnose an effective limit.

If possible, also check parent cgroups: A limit set there can affect the available compute time, even if the immediately visible configuration appears generous. Not every counter fully reflects inherited limits. If this information is missing from the hosting package, the limited visibility is explicitly considered a limitation of the analysis.

Detecting Variation and Measurement Errors

A single run may yield a randomly favorable or unfavorable result. Repeat the same load levels at documented time points and, if possible, vary the order of the systems being compared. Especially when resources are shared, available performance can fluctuate; therefore, in addition to a typical result, also report the observed dispersion and the number of runs.

Make sure that the test runs use the same cache state and the same dataset. A run with a warm page or database cache is not directly comparable to a cold run. If a seemingly faster response comes entirely from a page cache, it says little about how fast PHP performs the dynamic processing.

A CLI microbenchmark is also not an FPM result: It runs in a different execution context and may use different OPcache or JIT settings. Document the actual active settings for both runtimes separately, rather than inferring them from the PHP version. An advantage observed in the microtest may not be reflected to the same extent in the application’s HTTP test.

Count only content-accurate, successful responses toward the successful throughput. Otherwise, fast error pages or timeouts can significantly skew a comparison. If you notice significant deviations, also check database wait times, changes in the cache, and visible resource limits before attributing the difference solely to the CPU.

The Timing Behavior can also contribute to dispersion. The appropriate frequency control depends on the platform and load; a one-size-fits-all setting is no substitute for a comparison under the same conditions. The contribution to the CPU Governors on Hosting Servers explains the relationships involved for a more in-depth analysis.

Use the Results to Choose a Hosting Provider

For requests that are primarily CPU-intensive, the Time per work unit an important selection criterion. To do this, compare a representative PHP function under documented runtime conditions and then check whether the advantage is also evident with the dynamic HTTP route. A microbenchmark initially describes only the code being tested, not the entire hosting service.

If you expect a large number of concurrent visitors, a fast single request isn't enough. It's also crucial to consider how many correct responses per second the system delivers at a specified load level and how the p95 latency behaves within the acceptable error range. A system with higher throughput isn’t automatically better for your project if its slow responses exceed the requirements.

For database- or cache-dependent applications, weight the Application Test more than just a CPU score. A typical route with comparable data demonstrates how the stack interacts under the selected conditions. A SPEC result can supplement the initial selection, but it describes a tested system and is no substitute for a PHP web hosting test.

Before making your selection, determine which response times, error rates, and load levels are acceptable for the application. Then, compare only results with a matching load model and comparable cache state. Evaluate different hosting packages as complete configurations; the CPU’s contribution cannot be isolated from the differences between them without further diagnosis.

This decision applies to the current state as measured, not to any future application versions or traffic spikes. Repeat the relevant tests after making significant changes to PHP, the application, the database, the cache, or resource limits. This will help you determine whether the reserves that were previously sufficient still exist under the new conditions.

Sources and Current State of Knowledge

Status of the research:

Research and source information as of November 4, 2026. SPEC CPU 2017 and CPU 2026 are separate test suites; results apply specifically to the system tested and the documented conditions.

https://phpbench.github.io/phpbench/

https://www.php.net/install.fpm.configuration

https://www.php.net/manual/en/fpm.status.php

https://spec.org/cpu2026/

https://www.spec.org/cpu2026/results/

https://spec.org/cpu2017/Docs/runrules.html

https://www.php.net/manual/en/opcache.configuration.php

https://github.com/wg/wrk/blob/master/README.md

https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html?highlight=freezer

Current articles

AI-generated illustration of two similarly framed page layouts on different hosting platforms
Wordpress

WordPress Benchmark: Reproducible Testing of Hosting Performance

A meaningful WordPress benchmark separates browser experience, load behavior, and the impact of hosting. This allows you to plan comparable measurements, check cache states, and evaluate results without promising a "winner.".