Skip to content

  • Projects
  • Groups
  • Snippets
  • Help
  • This project
    • Loading...
  • Sign in / Register
T
Tidal
  • Overview
    • Overview
    • Details
    • Activity
    • Cycle Analytics
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Charts
  • Issues 0
    • Issues 0
    • List
    • Board
    • Labels
    • Milestones
  • Merge Requests 0
    • Merge Requests 0
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
    • Charts
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Charts
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • PLN
  • Tidal
  • Repository

Switch branch/tag
  • Tidal
  • tools
  • bridge
  • perf.py
Find file
BlameHistoryPermalink
  • PLN (Algolia)'s avatar
    feat(gig-log): a session recorder, so a run-through can be REVIEWED and not just felt · 4c57362d
    After a set, "did it glitch?" and "did it get hot?" and "which controls did I
    actually use?" are answered from memory. Memory is a bad instrument, and the
    answers matter: #8 (thermal impact under load), #56 (Pulsar starving audio),
    #46/#11 (which surface controls are really in the hands). PLN records the
    run-through in Ardour; this gives that take a machine-readable twin.
    
    WHAT IT DOES
      `gig-log.py record`   1 Hz JSONL: package/core temp, fan, freq, throttle
                            counters, per-core cpu%, and per-gear %cpu + RSS for
                            scsynth / sclang / ArdourGUI / the whole pulsar process
                            group. Plus PipeWire xruns and every LCXL control move.
      `gig-log.py mark ...` annotate the live session ("gimme acid drop")
      `gig-log.py report`   render it back: sparklines, xrun timeline, gear table,
                            a per-CC surface table with first/last touch
      `gig-log.py status`   is it running, what is it writing
      `gig-log.py install`  systemd --user unit, enabled, starts with the session
      `gig-log.py selftest` prove the parsers AND the cost
    
    Wall-clock stamped in the header, so the timeline lines up with the Ardour take.
    
    THE OBSERVER MUST NOT PERTURB — measured, not asserted
    This rig has twice produced the fault it was measuring: probe-chain's capture
    streams caused the xruns it was hunting, and the LED daemon's per-event fork
    caused the lag it was reporting. So: no audio capture at all, no per-sample
    subprocess spawn (every number comes from sysfs/procfs), and exactly two
    long-lived children (`pw-top -b`, `aseqdump`) drained by threads so a filling
    pipe can never block them. Measured cost of the whole thing: 0.40% of one core
    with 270 pw-top lines parsed in 10 s; 0.79% as the live systemd unit. The first
    selftest reported 0.66% and was FLATTERING ITSELF — it never started the reader
    threads, so it measured a sampler with nothing to parse. Same mistake as the
    first --bench run in the LED work; fixed, then re-measured lower and honest.
    
    AND THE LOGGER MUST NOT BE A FIREHOSE
    A fader sweep is 100+ events/s. A logger that writes them all costs more than
    what it measures, so CC/pitchbend are coalesced to one line per control per
    second carrying count + first/last/min/max — the #71/#72 fix applied to
    ourselves. 128 events on one knob is one line that still shows the whole travel.
    NOTES ARE NEVER COALESCED: a CC is a state and may be superseded, a note is an
    event and dropping one loses a thing that happened.
    
    COUNTERS ARE DELTAS, AND THE BASELINE IS WHERE THE BUGS LIVED
    Two absolute counters here are large and meaningless alone: package_throttle
    was 17024 after 2 idle days, and Ardour's PipeWire ERR was 67072. Both count
    history, including power excursions and device changes that never touched audio.
    So the header records baselines and samples record deltas.
    
    Getting Ardour's baseline right took three rules, and the first report caught
    each one:
      1. baseline on FIRST sight -> pw-top prints a zero-filled snapshot before the
         profiler has data, so base=0 and a 25-second IDLE session reported 72096
         xruns.
      2. baseline on SECOND sight -> usually right. pw-top emits a
         non-deterministic NUMBER of zero tables, so it silently reported 67123 on
         the next real run. A rule that is right most of the time is the worst kind
         for a gig log, because the one bad reading looks exactly like a disaster.
      3. baseline = MAX over each node's first 5 sightings. ERR is monotonic within
         a node's lifetime, so the max over a warm-up IS the true starting count —
         no timing assumption at all. A value below the baseline means the node was
         destroyed and recreated, so re-baseline instead of reporting negative.
    Validated by three independent 15 s runs, all reporting 0 (measure twice in
    time before trusting one reading). The report DECLARES the warm-up blind spot
    rather than hiding it.
    
    Also learned on the way: Ardour accumulates ~6 xruns/min even with nothing
    playing (67072 -> 67123 -> 67134 across captures minutes apart), which is
    exactly why only the session delta may ever be quoted.
    
    FIXED IN THE SHARED READER
    perf._read(None) raised TypeError instead of returning the default, so on any
    machine without a coretemp/dell_smm hwmon the thermal read CRASHED rather than
    reading "unknown" — the Bridge shares this code path. Guarded.
    
    Refactored _proc_cpu_rss into a pure parse_proc_stat() to make it testable, and
    it needed to be: pulsar's renderer comms look like `(pulsar) --type=renderer`,
    so splitting /proc/pid/stat on whitespace from the left shifts every field and
    silently reports some other column as CPU.
    
    TESTS: 71 new (tools/tests/test_gig_log.py), suite 211 -> 282, all green.
    Covers real pw-top/aseqdump lines, every baseline regression above, coalescing
    invariants, notes-survive-a-CC-flood, a torn final line costing one sample not
    the log, absent gear degrading to partial data instead of a crash, and
    sparklines bucketing by MAX so a one-second burst inside a 40-minute set cannot
    be averaged away.
    PLN (Algolia) authored Jul 29, 2026
    4c57362d
perf.py 15.3 KB
EditWeb IDE
×

Replace perf.py

Attach a file by drag & drop or click to upload


Cancel
A new branch will be created in your fork and a new merge request will be started.