Add 3x9 factorial analysis of std79-doe heartbeat/physics telemetry
Correlates every HB-ON/HB-OFF heartbeat-tick CSV row (results-20260912- with-heartbeat-csv/*-doe-raw.log) back to which trial (run_id, id_idx, id_label, rep) was active when it printed, despite the async tick printer splicing rows mid-token -- including mid a DOE-RUN marker itself -- into the trial loop's own console output on the shared serial line. Pipeline (analysis-20260912/, see its own README.md): - correlate_doe.py: two-pass reconstruction per architecture (remove atomic CSV-row spans to rebuild the clean trial-output stream, map each removed row's offset back to the nearest preceding run_id marker); identity/rep looked up from a known-clean prior run's run_id mapping rather than re-parsed, since one aarch64 marker (trial 12, rajames rep 1) lost its id_idx digit to a zero-separator collision with an adjacent CSV field and is unrecoverable from that log alone -- its rows fold into trial 11 instead, documented as a known limitation. - combine.py: merges all three architectures into combined.csv (768 rows), decoding Q48.16 fields to floats and jitter_bits' IEEE754 bit pattern to real jitter_ns. - analysis.R: per-cell (architecture x identity) means/SD and two-way ANOVA for each of 12 telemetry metrics, one boxplot SVG per metric, written up as ANALYSIS.md. Key findings: identity significantly affects word-heat/window-sizing metrics (expected -- different identities execute different word sets), architecture significantly affects timing metrics (APIC ticks/tick, timing variance, fleet heat -- expected, different QEMU targets), zero architecture x identity interaction on any metric. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXieurDfDSsDFdnSyusuWo
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
403a7639e1
commit
934be5a257
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
combine.py -- build combined.csv from the three per-architecture
|
||||
correlated CSVs (correlate_doe.py's output), decoding Q48.16 fixed-point
|
||||
fields to plain floats and jitter_bits' IEEE754 bit pattern to a real
|
||||
jitter_ns value, since R has no convenient native uint64/bit-punning
|
||||
story worth using here.
|
||||
|
||||
Usage (from this directory, after running correlate_doe.py for each
|
||||
architecture against ../results-20260912-with-heartbeat-csv/*-doe-raw.log
|
||||
to produce amd64-correlated.csv / aarch64-correlated.csv /
|
||||
riscv64-correlated.csv):
|
||||
|
||||
python3 combine.py amd64-correlated.csv aarch64-correlated.csv riscv64-correlated.csv combined.csv
|
||||
"""
|
||||
import csv
|
||||
import struct
|
||||
import sys
|
||||
|
||||
Q48 = 65536.0
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print("usage: combine.py <in1.csv> [in2.csv ...] <out.csv>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
*in_paths, out_path = sys.argv[1:]
|
||||
|
||||
fields = ["arch", "run_id", "id_idx", "id_label", "rep", "tick_number", "elapsed_ns",
|
||||
"tick_interval_ns", "hot_word_count", "avg_word_heat", "window_width",
|
||||
"actual_window_size", "predicted_label_hits", "jitter_ns", "apic_ticks",
|
||||
"time_trust", "variance", "vm_call_depth_max", "hera_heat", "hermes_heat",
|
||||
"artemis_heat"]
|
||||
|
||||
out_rows = []
|
||||
for path in in_paths:
|
||||
arch = path.split("-correlated.csv")[0].split("/")[-1]
|
||||
with open(path) as f:
|
||||
for row in csv.DictReader(f):
|
||||
jitter_bits = int(row["jitter_bits"])
|
||||
jitter_ns = struct.unpack('<d', struct.pack('<Q', jitter_bits))[0]
|
||||
out = dict(row)
|
||||
out["arch"] = arch
|
||||
out["avg_word_heat"] = int(row["avg_word_heat_q48"]) / Q48
|
||||
out["time_trust"] = int(row["time_trust_q48"]) / Q48
|
||||
out["variance"] = int(row["variance_q48"]) / Q48
|
||||
out["hera_heat"] = int(row["hera_heat_q48"]) / Q48
|
||||
out["hermes_heat"] = int(row["hermes_heat_q48"]) / Q48
|
||||
out["artemis_heat"] = int(row["artemis_heat_q48"]) / Q48
|
||||
out["jitter_ns"] = jitter_ns
|
||||
out_rows.append({k: out[k] for k in fields})
|
||||
|
||||
with open(out_path, "w", newline="") as f:
|
||||
w = csv.DictWriter(f, fieldnames=fields)
|
||||
w.writeheader()
|
||||
w.writerows(out_rows)
|
||||
|
||||
print(f"rows written: {len(out_rows)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user