Skip to content

axcherednikov/php-websocket-bench

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

php-websocket-bench

Benchmarks for ext-websocket against PHP WebSocket libraries.

These benchmarks compare the current native protocol helpers and native server runtime with PHP WebSocket libraries. The protocol AMPHP entry point installs amphp/websocket-server and measures the RFC 6455 parser/compiler it uses through amphp/websocket. The protocol OpenSwoole entry point measures OpenSwoole\WebSocket\Server::pack() and OpenSwoole\WebSocket\Server::unpack(). OpenSwoole is optional because it is a PHP extension installed outside Composer.

The protocol suite measures hot paths:

  • server-side text frame encoding
  • masked client text frame decoding

The server runtime suite measures WebSocket HTTP Upgrade close paths.

The message runtime suite measures complete WebSocket server scenarios:

  • upgraded idle connections
  • pipelined echo messages
  • broadcast fanout deliveries
  • direct ws:// transport and wss:// through the same local TLS terminator

Results

Protocol

Environment: PHP 8.4.21, xdebug.mode=off, zend.assertions=-1, Apple Silicon macOS, 100,000 iterations for 64B payloads and 20,000 iterations for 1024B payloads. Results from May 18, 2026. AMPHP WebSocket Server v4.0.0, Ratchet v0.4.0, and Workerman v5.2.0 were installed from Composer. OpenSwoole v26.2.0 was installed from PECL.

Benchmark amphp/websocket-server ratchet/rfc6455 workerman/workerman openswoole ext-websocket
encode text 64B 3,102,715 ops/sec 1,493,649 ops/sec 4,406,847 ops/sec 2,679,178 ops/sec 15,134,317 ops/sec
decode masked text 64B 592,968 ops/sec 566,960 ops/sec 1,776,096 ops/sec 4,058,675 ops/sec 7,020,335 ops/sec
encode text 1024B 2,467,892 ops/sec 1,323,974 ops/sec 3,537,032 ops/sec 6,056,783 ops/sec 12,041,548 ops/sec
decode masked text 1024B 358,676 ops/sec 278,047 ops/sec 846,768 ops/sec 3,694,837 ops/sec 5,155,027 ops/sec

Server Runtime

Environment: PHP 8.4.21, xdebug.mode=off, zend.assertions=-1, Apple Silicon macOS, 1,000 connections, average of 3 runs. Results from May 23, 2026. ext-websocket used the native kqueue driver; OpenSwoole was built with kqueue enabled.

Benchmark amphp/websocket-server workerman/workerman openswoole cboden/ratchet ext-websocket
websocket upgrade/close 3,244 connections/sec 10,525 connections/sec 10,158 connections/sec 6,364 connections/sec 10,959 connections/sec
client upgrade loop 2,510 connections/sec 5,594 connections/sec 3,135 connections/sec 4,548 connections/sec 6,174 connections/sec
websocket subprotocol upgrade/close 3,245 connections/sec 9,342 connections/sec 9,212 connections/sec 6,333 connections/sec 10,468 connections/sec
client subprotocol upgrade loop 2,543 connections/sec 5,189 connections/sec 2,831 connections/sec 4,544 connections/sec 6,016 connections/sec

This starts a fresh server process, then measures the current server runtime surface up to the last accepted connection. All rows perform real HTTP Upgrades. Application message throughput lives in the message-runtime table below. ratchet/rfc6455 is not listed here because the benchmarked package exposes protocol helpers, not a server runtime.

Real ws/wss Message Runtime

Environment: PHP 8.4.21, xdebug.mode=off, zend.assertions=-1, Apple Silicon macOS, 50 upgraded connections, 1,000 pipelined echo/broadcast source messages, 1024B text payloads, average of 3 runs. Results from May 18, 2026. The wss rows use the same local TLS terminator in front of each server, so the comparison isolates WebSocket runtime behavior under encrypted transport rather than comparing different TLS implementations.

ws://

Benchmark amphp/websocket-server workerman/workerman openswoole ext-websocket
idle upgraded connections 2,785 connections/sec 5,363 connections/sec 4,783 connections/sec 5,082 connections/sec
echo pipelined messages 45,502 messages/sec 51,332 messages/sec 50,515 messages/sec 70,059 messages/sec
broadcast fanout deliveries 186,907 deliveries/sec 227,944 deliveries/sec 229,098 deliveries/sec 818,959 deliveries/sec

wss:// with the shared local TLS terminator:

Benchmark amphp/websocket-server workerman/workerman openswoole ext-websocket
idle upgraded connections 356 connections/sec 428 connections/sec 412 connections/sec 442 connections/sec
echo pipelined messages 24,783 messages/sec 29,501 messages/sec 31,391 messages/sec 29,735 messages/sec
broadcast fanout deliveries 105,500 deliveries/sec 163,485 deliveries/sec 210,075 deliveries/sec 610,215 deliveries/sec

Install Dependencies

composer install

OpenSwoole is optional and is installed as a PHP extension:

pecl install openswoole-26.2.0

On Homebrew macOS, if pcre2.h is not found during compilation:

CPPFLAGS="-I/opt/homebrew/include" LDFLAGS="-L/opt/homebrew/lib" pecl install -f openswoole-26.2.0

Run

From the repository root, build the extension in the sibling php-websocket checkout first, then run the benchmark with the same PHP binary. If the extension lives elsewhere, pass WEBSOCKET_EXTENSION=/path/to/websocket.so for server and message runtime benchmarks.

# ext-websocket
php -d xdebug.mode=off -d zend.assertions=-1 -d extension="../php-websocket/modules/websocket.so" protocol/websocket.php [iterations]
php -d xdebug.mode=off -d zend.assertions=-1 -d extension="../php-websocket/modules/websocket.so" server-runtime/websocket.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 -d extension="../php-websocket/modules/websocket.so" server-runtime/websocket-subprotocol.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 -d extension="../php-websocket/modules/websocket.so" message-runtime/websocket.php [connections] [messages] [rounds] [ws|wss|both] [payload-bytes]

# PHP libraries
php -d xdebug.mode=off -d zend.assertions=-1 protocol/amphp.php [iterations]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/amphp.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/amphp-subprotocol.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 message-runtime/amphp.php [connections] [messages] [rounds] [ws|wss|both] [payload-bytes]
php -d xdebug.mode=off -d zend.assertions=-1 protocol/ratchet.php [iterations]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/ratchet.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/ratchet-subprotocol.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 protocol/workerman.php [iterations]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/workerman.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/workerman-subprotocol.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 message-runtime/workerman.php [connections] [messages] [rounds] [ws|wss|both] [payload-bytes]

# Native OpenSwoole extension, when installed
php -d xdebug.mode=off -d zend.assertions=-1 protocol/openswoole.php [iterations]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/openswoole.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 server-runtime/openswoole-subprotocol.php [connections] [rounds]
php -d xdebug.mode=off -d zend.assertions=-1 message-runtime/openswoole.php [connections] [messages] [rounds] [ws|wss|both] [payload-bytes]

With Homebrew PHP 8.3:

cd ../php-websocket
/opt/homebrew/opt/php@8.3/bin/phpize
./configure --enable-websocket --with-php-config=/opt/homebrew/opt/php@8.3/bin/php-config
make -j"$(sysctl -n hw.ncpu)"

cd ../php-websocket-bench
/opt/homebrew/opt/php@8.3/bin/php \
  -d zend.assertions=-1 \
  -d extension="../php-websocket/modules/websocket.so" \
  protocol/websocket.php

Default: 100,000 protocol iterations, 1,000 server-runtime connections over 3 rounds, or 50 message-runtime connections with 1,000 messages, 3 rounds, ws, and 64B payloads.

What is measured

Protocol

Benchmark What it tests
encode text 64B Server-side text frame encoding for a small payload
decode masked text 64B Masked client text frame decoding for a small payload
encode text 1024B Server-side text frame encoding for a larger payload
decode masked text 1024B Masked client text frame decoding for a larger payload

Server Runtime

Benchmark What it tests
websocket upgrade/close Native WebSocket\Server::run() HTTP Upgrade path and connection cleanup
websocket subprotocol upgrade/close Native HTTP Upgrade path with Sec-WebSocket-Protocol selection and connection cleanup
client upgrade loop Client-side loop overhead while opening and upgrading benchmark WebSocket connections
client subprotocol upgrade loop Client-side loop overhead while opening, upgrading, and validating negotiated subprotocols

Message Runtime

Benchmark What it tests
idle upgraded connections Open and hold upgraded WebSocket connections
echo pipelined messages Receive many outstanding text messages, dispatch onMessage, send replies, and read them client-side
broadcast fanout deliveries One incoming message fanned out to all connected clients

File Structure

File Description
protocol/common.php Shared RFC 6455 encode/decode benchmark logic
protocol/websocket.php ext-websocket protocol benchmark
protocol/amphp.php amphp/websocket-server protocol benchmark
protocol/ratchet.php ratchet/rfc6455 protocol benchmark
protocol/workerman.php workerman/workerman protocol benchmark
protocol/openswoole.php OpenSwoole protocol benchmark
server-runtime/common.php Shared HTTP Upgrade benchmark runner
server-runtime/websocket.php ext-websocket HTTP Upgrade benchmark
server-runtime/websocket-subprotocol.php ext-websocket HTTP Upgrade benchmark with subprotocol negotiation
server-runtime/amphp.php AMPHP WebSocket Server HTTP Upgrade benchmark
server-runtime/amphp-subprotocol.php AMPHP WebSocket Server HTTP Upgrade benchmark with subprotocol negotiation
server-runtime/ratchet.php cboden/ratchet HTTP Upgrade benchmark
server-runtime/ratchet-subprotocol.php cboden/ratchet HTTP Upgrade benchmark with subprotocol negotiation
server-runtime/workerman.php Workerman HTTP Upgrade benchmark
server-runtime/workerman-subprotocol.php Workerman HTTP Upgrade benchmark with subprotocol negotiation
server-runtime/openswoole.php OpenSwoole HTTP Upgrade benchmark
server-runtime/openswoole-subprotocol.php OpenSwoole HTTP Upgrade benchmark with subprotocol negotiation
server-runtime/servers/*.php Isolated server processes used by the runtime benchmarks
message-runtime/common.php Shared WebSocket message-runtime benchmark runner
message-runtime/tls_proxy.php Local TLS terminator used by wss message-runtime benchmarks
message-runtime/websocket.php ext-websocket message-runtime benchmark
message-runtime/amphp.php AMPHP WebSocket Server message-runtime benchmark
message-runtime/workerman.php Workerman message-runtime benchmark
message-runtime/openswoole.php OpenSwoole message-runtime benchmark
message-runtime/servers/*.php Isolated server processes used by the message-runtime benchmarks

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages