#!/bin/bash # One paced ring-buffer run (STATUS item 4, FINDINGS 49.7.2). # # tools/bench/check.sh runs the ring pass FREE-RUNNING, which is right for what # it gates -- wrap correctness at a fixed ring size, delivery removed as a # variable by an unlimited pipe. It cannot answer the buffering question, # because a free-running decoder never lets the ring back up. # # This runs the same rig with the decoder held to the container's frame rate, # so the ring fills and FR_HEAD-FR_TAIL means "frames the decoder could still # draw with the pipe dead". Every run is verified PIXEL-EXACT: a paced decode # that drops a pixel is not a slack measurement, it is a bug. # # tools/bench/pace_run.sh [cut_at_tick] [cut_frames] # # kbps 0 = unlimited pipe. There is no default rate anywhere in this tree # (FINDINGS 50) and there is none here either. # # DLX_RINGOWN=1 hands the RING to the 68000 as well (ROADMAP P5, # src/player/ring.i): this script's Lua stops placing records and becomes a # transport that answers one request at a time. DLX_PREFILL_FR is then the # prefill policy, in whole records. It needs a DLX4 container, because the # machine cannot learn a record's length by walking a stream it has not fetched. # # DLX_ITER=2 runs the scene TWICE, which under DLX_RINGOWN means a real seek # between the passes: the channel goes quiet, the ring is declared empty and the # whole accumulated lookahead is thrown away and rebuilt from the prefill. It # needs DLX_PACE=2, because rebasing the frame clock across a pass is the # machine's to do and a host-written tick would carry on counting. # # DLX_PACE selects WHO KEEPS THE TIME: 1 (default) is the host writing the tick, # 2 is the 68000 writing it off the CRTC's V-DISP (ROADMAP P3, FINDINGS 54). # Everything else about the run is identical, which is the whole point -- the # pace gate in src/player/stream.s cannot tell them apart, so a difference in # the result is a difference in the CLOCK and not in the rig. set -e cd "$(dirname "$0")/../.." RING=${1:?ring KB}; KBPS=${2:?pipe KB/s, or 0 for unlimited} CUT_AT=$3; CUT_FR=${4:-1} DLX=${DLX:-tmp/rc_fr_singe_scsi_span.dlx} PACE=${DLX_PACE:-1} OWN=${DLX_RINGOWN:-0} ITERS=${DLX_ITER:-1} if [ "$OWN" = 1 ] && [ "$ITERS" != 1 ] && [ "$PACE" != 2 ]; then echo "DLX_ITER>1 needs DLX_PACE=2: the frame clock is rebased per pass by" echo "src/player/stream.s, and a host-written tick would go on counting" echo "through the seek and open every slot of the second pass at once." exit 2 fi TAG="r${RING}_k${KBPS}${CUT_AT:+_cut${CUT_AT}x${CUT_FR}}" # The default tag is left ALONE when the host keeps the time: tools/bench/ # pace_sweep.sh reads tmp/pace_r_k.log by name, and renaming the # host-paced logs would break a sweep that has nothing to do with this option. if [ "$PACE" != 1 ]; then TAG="${TAG}_p$PACE"; fi if [ "$OWN" = 1 ]; then TAG="${TAG}_own"; fi if [ "$ITERS" != 1 ]; then TAG="${TAG}_x$ITERS"; fi tools/vasm/vasmm68k_mot -Fbin -o tmp/stream.bin src/player/stream.s > /dev/null [ -f tmp/stream_disk.bin ] || python3 tools/bench/prep_stream.py "$DLX" > tmp/prep_stream.log mkdir -p "tmp/snap_pace_$TAG"; rm -f "tmp/snap_pace_$TAG/x68000"/*.png # `env` rather than an assignment prefix: an empty ${CUT_AT:+...} in the middle # of a prefix is not an assignment token, so bash takes the next word as the # command and the run dies with "SDL_VIDEODRIVER=dummy: command not found". CUTENV=(); [ -n "$CUT_AT" ] && CUTENV=(DLX_CUT_AT="$CUT_AT" DLX_CUT_FR="$CUT_FR") ( cd tmp && env DLX_PACE=$PACE DLX_RING_KB=$RING DLX_STREAM_KBPS=$KBPS \ DLX_RINGOWN=$OWN DLX_ITER=$ITERS \ ${DLX_PREFILL_FR:+DLX_PREFILL_FR=$DLX_PREFILL_FR} \ "${CUTENV[@]}" DLX_SLACK_CSV="slack_$TAG.csv" \ SDL_VIDEODRIVER=dummy stdbuf -oL timeout -k 5 900 \ mame x68000 -bios ipl10 -ramsize 2M -video soft -window -sound none \ -nothrottle -plugins -autoboot_script ../tools/bench/stream.lua \ -snapshot_directory "./snap_pace_$TAG" -snapview native -seconds_to_run 90 \ > "pace_$TAG.log" 2>&1 ) # The completion marker is not optional: a run killed mid-decode compares a # half-drawn screen and reads as a wrap bug rather than as a truncated run. grep -q "snapshot taken" "tmp/pace_$TAG.log" || { echo "FAIL($TAG): no snapshot marker -- the pass did not complete." tail -6 "tmp/pace_$TAG.log"; exit 1; } echo "=== $TAG" grep -aE "decoder (SELF-PACED|PACED|FREE)|FRAME CLOCK|ring: |UNDERRUNS|NO IDLE|SEEK SLACK|RING-BOUND|RATE-BOUND|BUILD TIME|PIPE CUT|DEADLINE|REQUIRED|MACHINE-OWNED|PREFILL:|CHANNEL IDLE|MISPLACED|SEEK PASS" \ "tmp/pace_$TAG.log" | sed "s/\[STR\] / /" python3 tools/bench/verify_decode.py "$DLX" --snap "tmp/snap_pace_$TAG" | tail -2