Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Performance

Every Yuneta release is measured before it is tagged, and every release ships a performance report. This page keeps the history: the trend of the main figures, release after release, and a link to the report of each release.

Two kinds of figures are kept:

A figure that got slower is never left out. It is shown with its reason, as the CHANGELOG states it: most are the price of a guarantee (a file that survives a power cut, a record that reaches the disk before a command runs), kept by decision.

Reports

ReleaseAgainstReportRenderedRaw figures
7.25.57.25.47.25.5.htmlview7.25.5.json

The report is one self-contained page (no script, no external file). GitHub shows it as source code; the “view” link renders it. How a report is made, and the schema of its .json, are in performance/reports/README.md.

The trend

Ten small charts, one per figure, each from 7.25.4 to 7.25.5: appends per second 220,120 to 221,588; open of a store as master 92.5 to 80.8 ms; a tm query of one minute 12.7 to 7.4 ms; a treedb update in memory 3.92 to 2.92 us; a saved treedb update 11.75 to 10.81 us; link or unlink 11.27 to 11.09 us; the open of 40 treedbs with an unchanged schema 1.84 to 0.649 s; one agent audit record 6194 to 554 ns; the event loop echo 152.2 to 150.5 K messages per second; the gobj TCP echo 38,706 to 39,344 round trips per second.

The main A/B figures, one panel each, on their own scale from zero. The first report (7.25.5) gives two points: 7.25.4, its baseline, and 7.25.5. Each new report adds one point.

The C_TREEDB open compares two separate runs: 7.25.4 (medians of an earlier run) and 7.25.5 as shipped (the tag-time run). Every other point of the table comes from one alternated A/B run.

FigureUnit7.25.47.25.5
Appends per second (test_topic_pkey_integer, 4 link layouts)appends/s220,120221,588
Open a store as master, 20 000 md2 files (perf_timeranger2)ms92.580.8
A tm query of one minute of a keyms12.77.4 (migrated)
treedb: update a node in memory (perf_tr_treedb)us3.922.92
treedb: update a node and save itus11.7510.81
treedb: link or unlink two nodesus11.2711.09
C_TREEDB: open 40 treedbs whose schema did not change (perf_c_treedb)s1.840.649
One agent audit record of 300 bytes (perf_rotatory)ns6,194554
Event loop echo, 1 KB messages (perf_yev_ping_pong)K msg/s152.2150.5
TCP echo through the gobj stack (perf_tcp_test4)round trips/s38,70639,344

What each figure means

FigureWhat it tells a user
Appends per secondHow many records one yuno stores per second in a key-indexed timeranger2 topic. It is the write rate of every history, queue and log that Yuneta keeps on disk.
Open of a storeThe start-up time of a yuno that owns a store (master) or follows one that another yuno writes (replica).
tm queryA read of a time range of a key: what a dashboard or a report pays to load one minute of data.
treedb update, link, create, deleteThe cost of one change in the graph database: a node changed in memory, a node changed and saved, a relation made or undone, a node created or removed. The CPU time of the process, per operation.
C_TREEDB openThe start-up of a yuno with many treedbs. With an unchanged schema it is the everyday case; the first open (seed) and the open with a newer schema are one-time costs.
Agent audit recordWhat every command sent to the agent pays to be audited.
Log recordWhat a yuno pays for one line of its log file.
Event loop echoThe ceiling of the io_uring event loop alone: 1 KB messages echoed per second, no gobj layer.
gobj TCP and TLS echoRound trips of a JSON message through the whole stack (C_IOGATE, C_TCP_S, C_PROT_TCP4H, C_CHANNEL), plain and encrypted, with and without a timeranger2 append per message.
Publishgobj_publish_event(): one event delivered to N subscribers of one gobj, the in-process message bus.
Binary sizeEach yuno is one fully static executable. The size includes OpenSSL and the whole framework.

7.25.5 against 7.25.4

The change of the time one operation takes, 7.25.5 against 7.25.4, one bar per figure. Faster: the agent audit record (11 times), the audit record with a flush (5.2 times), the open of 40 treedbs with an unchanged schema (2.8 times), a migrated tm query (-42%), a treedb update in memory (-26%), a master open (-13%), a saved treedb update (-8%), the delete of a parent with 200 children (-6%). Within noise: the appends, the links, the creates, the reopen, the event loop and the TCP echo. Slower, by decision: the create of a topic (33 times), a topic_version change (136 times), a tm query on a topic not yet migrated (31 times), a publish to 100 subscribers with __global__ (2.1 times at 250 bytes, +27% at 20 KB), a replica open (+19%), the first open and the newer-schema open of a treedb (+10% and +9%), a forced delete (+1.8%).

One bar per figure: the change of the time one operation takes (a rate is turned into time per operation), left of zero is faster. Blue is faster, grey is within the noise of its rounds, red is slower and kept by decision.

The prices of 7.25.5, and what each one buys:

SlowerByWhy
Create a topic (timeranger2)3.6 -> 118.9 ms for 102 fsyncs per topic: a power cut never leaves a topic whose files are not on disk.
Change a topic_version1.7 -> 231.5 ms for 104 fsyncs per change: never a new topic_version over a topic_cols.json that is not on disk.
A tm query on a topic of 7.25.4 or earlier12.7 -> 391.6 msUntil mark-tm-order migrates the topic (19 ms, once): the old topic does not say that its tm order holds. After the migration the query takes 7.4 ms.
Open a store as a replica89.7 -> 106.5 msOne more stat() per md2 file: a replica looks for the order markers after reading each file, so it cannot miss one the master writes during the open.
C_TREEDB: first open, newer schema+10%, +9%The record of the projection in progress, written whole with its fsyncs: a crash in the middle is finished at the next open.
Publish with __global__ or __local__+0.23 us a deliveryEach such subscription gets its own kw_twin() of the event, so a peer’s subscription cannot change the event of every later subscriber. Every remote (C_IEVENT_SRV) subscription carries __global__.
treedb forced delete+1.8% (~1 us)The delete holds its events and keeps the column that lets a refused delete change nothing.
The agent audit record, built+2-3%Names are judged with their JSON escapes decoded, and a write-attr is looked for in every string: no secret reaches the audit file.

Every A/B of 7.25.5, change by change, with its rounds and spread, is in performance/c/README.md and in the CHANGELOG (“Performance, against 7.25.4”).

What one machine does with 7.25.5

Measured at tag time on the build of 7.25.5: 5 rounds (3 for perf_c_treedb and perf_auth_bff), mean of the rounds. One process; the event loop runs on one core, and Yuneta scales by running one yuno per core.

Operations per second on one core with Yuneta 7.25.5. timeranger2 appends 224 K, appends with a live reader 167 K, timeranger2 reads 188 K, reads page by page 165 K, the io_uring event loop alone 150 K, the event loop with a timeranger2 append per message 84.9 K, the full gobj stack over TCP 38.6 K, TCP with an append 29.7 K, TLS 29.2 K, TLS with an append 23.4 K, OAuth2 BFF logins 8.4 K.

Operations per second on one core, as each benchmark counts them: a record stored or read, a message echoed, a round trip, a login.

FigureBenchmark7.25.5
Records stored per second, one key-indexed topictest_topic_pkey_integer224,455 +- 2,585
The same, with a live reader (an rt list)test_topic_pkey_integer166,654 +- 1,748
Records stored per second, one key, 600 000 appendsperf_timeranger2 tm_build_appends365,459 +- 5,836
Records read per second, every record of 2 keys, one callback eachtest_topic_pkey_integer_iterator2187,914 +- 3,379
Records read per second, page by pagetest_topic_pkey_integer_iterator5165,301 +- 1,971
Open a store as master, 20 000 md2 filesperf_timeranger279.8 ms
A tm query of one minute of a key (migrated topic)perf_timeranger27.2 ms
treedb: update a node in memory / savedperf_tr_treedb2.76 us / 10.37 us
treedb: link or unlink / create / forced deleteperf_tr_treedb11.02 us / 71.0 us / 69.2 us
C_TREEDB: open 40 treedbs, schema unchangedperf_c_treedb0.649 s
One log line of 300 bytesperf_rotatory381 ns
One agent audit record / flushedperf_rotatory570 ns / 1,263 ns
Event loop echo, 1 KB messages / with an appendperf_yev_ping_pong, perf_yev_ping_pong2149.6 K / 84.9 K msg/s
gobj stack, TCP round trips / with an appendperf_tcp_test4, perf_tcp_test538,587 / 29,699 per s
gobj stack, TLS (OpenSSL 3.6.3) round trips / with an appendperf_tcps_test4, perf_tcps_test529,166 / 23,363 per s
OAuth2 BFF logins (HTTP, 5 clients, mock IdP)perf_auth_bff8,446 per s
Binary size of a yuno, fully static with OpenSSLoutputs/yunos/*10.1-10.4 MB stripped, 33.9-34.7 MB with debug information

TLS with OpenSSL costs 24% of the round trips of plain TCP through the gobj stack (29,166 against 38,587). mbedTLS is not built on the measuring machine, so its figures are not in the report.

How the figures are measured

The benchmarks themselves are described in Benchmarks & Stress Tests.