Skip to content

Performance

Sascha Greuel edited this page Aug 2, 2026 · 1 revision

Bulk queries and performance

Home · Global options · Security

GameQ is designed to query several native sockets concurrently. Good performance comes from one well-configured GameQ instance, bounded batches, and avoiding optional data that the application does not use.

Use one instance for a list

$gameQ = new GameQ\GameQ();
$gameQ->addServers($servers);
$results = $gameQ->process();

Creating and processing one instance per server serializes network waits and loses most of the concurrency benefit.

Bound concurrency

max_servers_per_batch defaults to 50:

$gameQ->setOption('max_servers_per_batch', 25);

Lower values reduce simultaneous sockets, packet buffers, file descriptors, and peak memory. Higher values can improve throughput on a controlled network but increase resource usage and burst traffic. Values below one are treated as one.

Choose a limit that fits the PHP worker's memory, file-descriptor limit, upstream rate limits, and request deadline. For large public lists, process jobs in a queue and cache the results instead of tying them to a browser request.

Tune timeouts conservatively

$gameQ
    ->setOption('timeout', 3)
    ->setOption('stream_timeout', 200000)
    ->setOption('write_wait', 500);
  • timeout is the overall seconds-scale allowance for connection and response work.
  • stream_timeout is a microsecond polling/idle interval, not a replacement for the overall timeout.
  • write_wait spaces packet writes and protects CPU and remote servers from an avoidable burst.

Reducing stream_timeout or write_wait can increase CPU use and packet rate. A polling interval below the slowest expected response can also create unnecessary idle cycles. Measure with representative servers instead of copying aggressive values from a benchmark.

Skip optional protocol work

If only server status and player counts are needed, skip Source player and rules queries:

'options' => [
    'query_players' => false,
    'query_rules' => false,
],

Other protocols can have optional subqueries or paginated data of their own. Configure those only when the application consumes the additional fields; see protocol-specific options.

Bound follow-up rounds

Response-driven protocols can request challenges or additional pages. GameQ defaults to 64 follow-up rounds as a safety cap:

$gameQ->setOption('max_follow_up_rounds', 16);

Set this only when the application has a reason to limit large paginated responses. A value that is too low can return an incomplete player list.

Understand non-socket queries

Source, GameSpy, Quake, Unreal, RakNet, and many other families normally use the concurrent native socket path. TCP-based voice and Frostbite protocols can retain connections or buffered records for longer. A smaller set of protocols instead uses an HTTPS service, REST API, query plugin, or master list; that work does not have the same concurrency characteristics and can dominate processing time.

Cache status at the application boundary and query at a sensible interval. Do not poll public master services once per page view.

Keep production diagnostics off

debug adds exception work and can turn one bad server into a failed batch. Use it for diagnosis, then return to non-debug processing with logging and health metrics around the query job.

Measure the right things

Track:

  • total job time and time per batch;
  • online/offline/error counts by protocol;
  • peak memory and open file descriptors;
  • response sizes and player-list sizes;
  • cache age and query frequency;
  • upstream HTTP/master failures separately from direct server failures.

Avoid using a single LAN server as the only benchmark; internet latency, packet loss, large split packets, and master-service delays produce different behavior.

Clone this wiki locally