bench/OneMedia.Bench measures OneMedia against managed comparators and prints the ratio, allocations and memory for each
row. It is a console app, not packed, and the only project that references the comparator packages.
What is measured
| Row | OneMedia | Comparator (the bar) | Reference tools (information) |
|---|---|---|---|
mp4-demux | read every packet of every track | SharpMP4 | ffmpeg -c copy -f null |
mp4-audio | read the audio track only, other tracks switched off | OneAudio Mp4PacketSource | – |
mp4-probe | open, track list, duration | MetadataExtractor, TagLib#, ATL.NET (fastest of the three counts) | ffprobe, MediaInfo, ExifTool, MP4Box -info |
mkv-demux | read every packet | the Matroska package (full deserialise, then walk the blocks) | ffmpeg -c copy -f null, mkvextract tracks (first track) |
mkv-probe | open, track list, duration | the package's element reader: Info and Tracks read, clusters skipped | ffprobe, MediaInfo, ExifTool, mkvmerge -J, mkvinfo |
The Matroska package counts a laced block as one packet, where OneMedia delivers each frame of a lace; the table flags the different counts. The comparator therefore does less work per file than OneMedia on laced audio, which favours the comparator.
Files per row are listed by list: a small generated file, open-movie files of different shapes (1080p, fragmented,
Matroska/WebM), the published Matroska test files, and the over-4 GiB files with the index at the end (MP4) and a plain
over-4 GiB Matroska. A file missing from the corpus is skipped and said so.
The work is the same for everyone. A packet read counts the packet, adds its size and XORs its first and last byte, so every payload is delivered to the caller and not skipped. The counts are printed next to the times; a comparator whose packet count differs from OneMedia's is flagged in the table (Matroska laced blocks, files the package cannot read). The probe rows read what each library offers: tracks and duration, plus the title and first artist where the library has them; OneMedia's native tags join its probe when its tag layer lands.
Calls. Each comparator is called as its published README shows, with a 64 KiB file buffer. Where the README does not cover a
row the obvious public call is used: SharpMP4 reads track by track with ReadSample; MetadataExtractor uses
ImageMetadataReader.ReadMetadata(stream) and reads every tag's description; TagLib# uses File.Create(path); ATL.NET uses
new Track(path). ATL.NET is audio-oriented and may refuse video files; a refusal is shown as fail.
Method
- One fresh process per (row, implementation, file), so peak memory belongs to that work alone. The parent reads each file once before its rows so all implementations start with it in the page cache; the tables say so.
- In the process: a cold first run (JIT and type loading included), then a warm-up of at least 30 runs and 1.5 s for every
implementation alike, so that the runtime has promoted the hot methods to optimised code before any sample (tier-0, then the
instrumented stage, then optimised, each behind a 100 ms quiet timer). Then one sizing run and 5 samples, each the mean of enough
back-to-back runs to take about 50 ms. The median is reported, and the range is kept in
results.tsv. Probe rows (*-probe) are sampled this way on every file, since probe work does not grow with the file. Demux-style rows on files over 1 GiB get the cold run and then 3 samples of one run each. The cold first run is shown apart in the note column, for the comparators as well; it is a published, non-gating number (the first open in a process: what a one-offinfocall or a per-file open pays). - Allocation is
GC.GetAllocatedBytesForCurrentThreadper run, and per packet. Peak memory is the process's peak working set; the working set before any work is printed beside it. - Reference tools run as processes under
/usr/bin/time, three times (once over 1 GiB): wall time measured by the parent, peak resident set fromtime. Their start-up cost is part of the figure. - Ratio = OneMedia's median ÷ the fastest managed comparator's median for that file. The bar is a geometric mean ≤ 1.00× per row and no file above 1.25×. Rows with no managed comparator pass.
- Every run records CPU, logical cores, ISA flags, storage of the corpus, runtime, restored package versions, tool versions and the one-minute load average before, during (mean and max of 5 s samples) and after.
Running it
dotnet run -c Release --project bench/OneMedia.Bench -- run --rows 0.1 --out results/x64 [--corpus DIR]--rows takes a stage (0.1) or row ids. --files a,b keeps files whose path contains one of the strings, --no-tools leaves
out the reference tools, --reps and --tool-reps set the repetitions, --budget MIN stops starting new cells after that many
minutes (exit code 75) and --resume continues from results.tsv. report rebuilds report.md; prepare derives the
fragmented MP4 (done by run); list shows rows and files. The corpus is $ONEMEDIA_HOME/corpus (default ~/onemedia/corpus).
Timings are only comparable between runs on a quiet machine. The published run is one command per machine under the exclusive bench queue.
JIT tiers: steady state and first open
Each cell runs in a fresh process. The runtime starts every method in unoptimised tier-0 code and promotes hot ones only after a 100 ms quiet period and a background compile, with a second instrumented stage under dynamic PGO. Measuring before that climb finishes measures tier-0 code, which punishes libraries that do more of their own work per call. The samples are therefore taken after a warm-up long enough for every implementation to have tiered up (see Method), and the library carries no tiering overrides.
The first call in a process is a separate matter: it is JIT dominated, it is what a one-off open pays, and it is reported as "cold first run" for OneMedia and for every comparator. It is published but does not enter the ratio.
To see the unwarmed regime for a cell, run OneMedia.Bench child ROW IMPL REL CORPUS REPS under DOTNET_TieredCompilation=0 (every
method fully optimised) or DOTNET_TieredPGO=0.
Provenance of the comparator calls
Every comparator call was chosen from the package's published README, its package page and its public type and member signatures. No comparator's source, decompiled code or unpacked package contents was read, and no reference tool's source was read; the tools run as released binaries.
Looking at a cell
OneMedia.Bench once ROW IMPL REL [CORPUS [TIMES]]runs one cell, optionally in a loop, and prints the mean time of a run.bench/iocount.sh DLL ROW IMPL RELcounts the read calls and bytes a cell makes on its input file (strace).bench/profile.sh DLL ROW IMPL REL TIMESsamples a looped cell withdotnet-traceand prints self and inclusive time by method. It needsdotnet-tracein~/onemedia/u5-bench/tools(dotnet tool install dotnet-trace --tool-path ...).