Goal
Replace the current per-slot statistics file with a recorder that does not
perturb what it measures, and decompose the controller's share of the E3 data
path into stages that join the library's own records.
Two problems with the current mechanism
-
It writes on the data path. The per-slot stage CSV opens an ofstream,
writes a row, and flushes it once per slot, inside the sample handler.
A synchronous formatted write plus a flush on a per-slot path costs orders of
magnitude more than the intervals it is trying to record, so the numbers it
produces include a large and variable contribution from the act of recording
them.
-
It depends on something that does not exist. The code comments state that
the downstream send stages "are measured library-side in libe3's
publisher-stage CSV (--pub-stages-log), joinable by message_id". There is no
such option in libe3, on any branch. So the send side of the path is
currently unmeasured, and the CSV that exists stops at the handoff.
Scope
| Stage |
What |
| Hook to codelet |
already derived from the RAN-side timestamps |
| Codelet to dispatcher |
already derived |
| Dispatcher to handler |
the queue wait, already derived |
| Shared-memory publish |
currently timed inline |
| E3SM encode |
the Service Model payload encoder |
| Emit / fan-out |
the handoff into the library, per subscriber |
| Everything downstream |
owned by libe3, not by this repository |
E3SM and E3AP are separate boxes. This repository owns the Service Model
codec. E3AP framing, queuing, encoding and the connector send are the library's,
and are instrumented there. Do not re-time them here; join to them instead.
Mechanism
Use latrec, the per-thread lock-free ring recorder that libe3 ships in
include/libe3/latrec.h: one clock_gettime(CLOCK_MONOTONIC) plus four stores
per stamp into an mmap-backed ring. No syscall, no allocation, no formatting, no
lock, and no I/O on the data path. Conversion to a table happens offline, out of
process, against the mmap'd rings.
A stage block is reserved for this controller in wineslab/libe3#55. Use those
identifiers; do not invent your own.
The recorder is gated by a single runtime environment variable and is off by
default, so the same binary runs traced and untraced. Once it is in, the
--stats-log option and its per-slot flush should go: keeping two recording
mechanisms means one of them is always the one that is wrong.
Work items
Exploration first
Do not assume the code locations beyond what is stated above. Find and record
them back in this issue as file:function for:
- Where the sample handler is entered and where each currently-derived stage
boundary sits.
- Where the Service Model payload is encoded.
- Where the indication is handed to the library, per subscriber.
- Where the message identifier that keys the join is available.
Data-taking review (mandatory)
This must be a permanent, flag-gated capability, not a throwaway.
Acceptance
Closing paragraph
When this is done, write a closing paragraph here covering: what landed, the
stage identifiers now emitted and where, what the old per-slot CSV was costing,
how the join to the library's records was verified, and anything still open.
Goal
Replace the current per-slot statistics file with a recorder that does not
perturb what it measures, and decompose the controller's share of the E3 data
path into stages that join the library's own records.
Two problems with the current mechanism
It writes on the data path. The per-slot stage CSV opens an
ofstream,writes a row, and flushes it once per slot, inside the sample handler.
A synchronous formatted write plus a flush on a per-slot path costs orders of
magnitude more than the intervals it is trying to record, so the numbers it
produces include a large and variable contribution from the act of recording
them.
It depends on something that does not exist. The code comments state that
the downstream send stages "are measured library-side in libe3's
publisher-stage CSV (
--pub-stages-log), joinable by message_id". There is nosuch option in libe3, on any branch. So the send side of the path is
currently unmeasured, and the CSV that exists stops at the handoff.
Scope
E3SM and E3AP are separate boxes. This repository owns the Service Model
codec. E3AP framing, queuing, encoding and the connector send are the library's,
and are instrumented there. Do not re-time them here; join to them instead.
Mechanism
Use latrec, the per-thread lock-free ring recorder that libe3 ships in
include/libe3/latrec.h: oneclock_gettime(CLOCK_MONOTONIC)plus four storesper stamp into an mmap-backed ring. No syscall, no allocation, no formatting, no
lock, and no I/O on the data path. Conversion to a table happens offline, out of
process, against the mmap'd rings.
A stage block is reserved for this controller in wineslab/libe3#55. Use those
identifiers; do not invent your own.
The recorder is gated by a single runtime environment variable and is off by
default, so the same binary runs traced and untraced. Once it is in, the
--stats-logoption and its per-slot flush should go: keeping two recordingmechanisms means one of them is always the one that is wrong.
Work items
JSON-encoder camelCase change, which predates a large amount of the
library's current behavior, including several data-quality fixes to the
transport and teardown paths. Measurements taken against that pin are not
comparable with anything else. Bump it, and rebuild against current
main.boundary.
--pub-stages-logreferences from the comments, and insteaddocument that the downstream stages come from the library's own records,
joined by the message identifier the library already assigns.
library record for the same indication must be pairable.
Exploration first
Do not assume the code locations beyond what is stated above. Find and record
them back in this issue as
file:functionfor:boundary sits.
Data-taking review (mandatory)
This must be a permanent, flag-gated capability, not a throwaway.
path once the CSV is gone.
the CSV enabled and with latrec enabled, and report both against a clean
run. This is worth recording, because it tells us how much of the existing
per-slot numbers were measurement artifact.
Acceptance
library
main.joinable to the library's records by the message identifier.
file:functionper stage) is filled in above.Closing paragraph
When this is done, write a closing paragraph here covering: what landed, the
stage identifiers now emitted and where, what the old per-slot CSV was costing,
how the join to the library's records was verified, and anything still open.