A load test against a running server: players and watchers joining its arenas over
the wire, the frames they get measured against the steps the server runs, and the
server's own numbers (Cauldron2D.Net.Api's /stats) alongside.
Cauldron2D.Net.Load.run(url: "http://arcade:2280/api", actions: ["left", "right", "fire"], players: 40, watchers: 100, seconds: 60)
Cauldron2D.Net.Load.run(url: "http://arcade:2280/api", actions: [], players: 10, ramp: 10, every: 5, seconds: 120)Sessions are accounts load_1, load_2… (password load test), registered on the
server if they are not there, and spread over the arenas in turn. A report goes out
every :every seconds: a line with the sessions joined, the frames a second they
got (mean and least) against the ticks a second the server's worlds are set to, the
longest gap between frames, and the node (how busy its schedulers were since the
last report, the run queue, processes, memory); then a line for each of the three
arenas with the longest ticks — the mean, the 95th percentile and the longest against
the tick's budget, and the share of the last ticks that ran more than one step
(behind; a little is timer jitter, more is a world that cannot keep up).
A run is degraded when, over one report, any world's 95th-percentile tick is
longer than its budget (1 / hz), any world ran behind on more than a fifth of its
ticks (a few double steps are the timer firing late on a busy node, not a world that
cannot keep up — its ticks say which), the least frame rate any session saw fell
under 80% of the tick rate, or a session waited over a second for a frame. The
report says so and why. With
:ramp, that many more sessions join at every report until the run is degraded —
the sessions before the last addition are the capacity in the summary — or the
time is up.
stop/0 from another process ends a run early, after the interval in progress,
with the summary of what was measured; a mix task can call it on a key press.
Options
:url— the server's API, defaulthttp://localhost:2280/api:actions— the action names a player holds at random. Required:topic— the channel's topic prefix, default"world":players,:watchers— how many of each to start with, default 10 and 0:arenas— the ids of the arenas to use, default every arena the server lists:seconds— how long the run lasts, default 30:every— seconds between reports (and ramp steps), default 5:ramp— sessions to add at every report, default none; they are players and watchers in the same proportion as the start:audio—:personal(default) for a session that takes the server's sound as a browser would,:offfor one that asks for none:password— the sessions' password, defaultload test:report— a function given each report, defaultIO.puts/1:out— a file every report and the summary are appended to as JSON, one object a line, as the run goes, so a run cut short still leaves its record. Default none
Returns the summary: sessions, joined, refused, refusals (reasons with their
counts), fps (mean, min over the whole run), gap_ms (max), join_ms
(mean, max), server (the last arenas and node stats, hz and
steps_per_second), degraded (%{sessions, why} for the first degraded report,
else nil), capacity and stopped (:time, :degraded or :asked).
Summary
Types
@type summary() :: %{ sessions: non_neg_integer(), joined: non_neg_integer(), refused: non_neg_integer(), refusals: %{required(term()) => pos_integer()}, fps: %{mean: float(), min: float()}, gap_ms: %{max: non_neg_integer()}, join_ms: %{mean: non_neg_integer(), max: non_neg_integer()}, server: %{ arenas: [map()], node: map(), hz: number(), steps_per_second: float() }, degraded: %{sessions: non_neg_integer(), why: [String.t()]} | nil, capacity: non_neg_integer() | nil, stopped: :time | :degraded | :asked }
Functions
Why an interval counts as degraded, as run/1 judges it: [] when it does not.
Run a load test; see the module documentation for the options and the summary.
@spec stop() :: :ok
End the run in progress after the interval it is measuring; nothing when none is running.