// Valid-traffic differential conformance and measurement runner. No network targets. package main import ( p9 "9fans.net/go/plan9" "bytes" "encoding/binary" "encoding/json" "flag" "fmt" other "github.com/knusbaum/go9p/proto" "io" "math/rand" "os" "os/exec" "path/filepath" "runtime" "time" ) type reader struct { data []byte chunk, calls int } func (r *reader) Read(p []byte) (int, error) { r.calls++ if len(r.data) == 0 { return 0, io.EOF } n := min(len(p), len(r.data), r.chunk) copy(p, r.data[:n]) r.data = r.data[n:] return n, nil } func check(err error) { if err != nil { panic(err) } } func marshal(v any) []byte { b, e := json.MarshalIndent(v, "", " "); check(e); return append(b, '\n') } func corpus(seed int64, rounds int) [][]byte { r := rand.New(rand.NewSource(seed)) frames := [][]byte{} names := []string{"a", "file", "directory", "日本語", "ação"} for i := 0; i < rounds; i++ { q := p9.Qid{Type: 0, Vers: r.Uint32(), Path: r.Uint64()} d := p9.Dir{Qid: q, Mode: 0600, Atime: r.Uint32(), Mtime: r.Uint32(), Length: r.Uint64(), Name: names[i%len(names)], Uid: "user", Gid: "group", Muid: "user"} stat, e := d.Bytes() check(e) if i%2 == 1 { d.Null() stat, e = d.Bytes() check(e) } data := make([]byte, []int{0, 1, 7, 127, 1024, 8192}[i%6]) _, e = r.Read(data) check(e) wn := make([]string, i%17) wq := make([]p9.Qid, i%17) for j := range wn { wn[j] = names[r.Intn(len(names))] wq[j] = q } for typ := uint8(100); typ <= 127; typ++ { if typ == 106 { continue } f := p9.Fcall{Type: typ, Tag: uint16(r.Intn(65535)), Fid: r.Uint32(), Newfid: r.Uint32(), Afid: p9.NOFID, Uname: "user", Aname: "", Version: "9P2000", Msize: 65536, Oldtag: uint16(r.Intn(65535)), Ename: "permission denied", Qid: q, Aqid: p9.Qid{Type: p9.QTAUTH, Vers: q.Vers, Path: q.Path}, Iounit: 0, Name: d.Name, Perm: 0600, Mode: uint8(i % 4), Offset: r.Uint64(), Count: uint32(len(data)), Data: data, Wname: wn, Wqid: wq, Stat: stat} if typ == 100 || typ == 101 { f.Tag = p9.NOTAG } if typ == 114 { f.Name = names[i%len(names)] } b, e := f.Bytes() check(e) frames = append(frames, b) } } return frames } type metric struct { Implementation string `json:"implementation"` Operations uint64 `json:"operations"` CodecNS int64 `json:"codec_ns"` Allocations uint64 `json:"codec_allocations"` AllocatedBytes uint64 `json:"allocated_bytes"` ReadCalls uint64 `json:"read_calls"` Bytes uint64 `json:"bytes"` } func measure(name string, frames [][]byte, repeats, chunk int) metric { m := metric{Implementation: name} var before, after runtime.MemStats runtime.GC() runtime.ReadMemStats(&before) for index, frame := range frames { start := time.Now() for j := 0; j < repeats; j++ { rd := reader{data: frame, chunk: chunk} var out []byte if name == "9fans v0.0.7" { f, e := p9.ReadFcall(&rd) check(e) out, e = f.Bytes() check(e) } else { f, e := other.ParseCall(&rd) check(e) out = f.Compose() } if !bytes.Equal(frame, out) { panic(fmt.Sprintf("%s frame %d type %d differs", name, index, frame[4])) } m.ReadCalls += uint64(rd.calls) m.Bytes += uint64(len(frame)) m.Operations++ } m.CodecNS += time.Since(start).Nanoseconds() } runtime.ReadMemStats(&after) m.Allocations = after.Mallocs - before.Mallocs m.AllocatedBytes = after.TotalAlloc - before.TotalAlloc return m } func main() { seed := flag.Int64("seed", 4200, "deterministic valid-traffic seed") rounds := flag.Int("rounds", 100, "27 messages per round") repeats := flag.Int("repeats", 20, "codec repetitions") chunk := flag.Int("chunk", 65536, "maximum read/write chunk; use 1 to fragment every byte") session := flag.String("session-probe", "", "run live sessions against go9p") probe := flag.String("probe", "../../zig-out/bin/cloud9-probe", "cloud9 executable") output := flag.String("output", "results", "artifact directory") flag.Parse() if *rounds < 1 || *rounds > 10000 || *repeats < 1 || *repeats > 10000 || *chunk < 1 { panic("invalid bounds") } frames := corpus(*seed, *rounds) all := bytes.Join(frames, nil) check(os.MkdirAll(*output, 0755)) check(os.WriteFile(filepath.Join(*output, "corpus.9p"), all, 0644)) config := map[string]any{"seed": *seed, "rounds": *rounds, "repeats": *repeats, "chunk": *chunk, "frames": len(frames), "go": runtime.Version(), "platform": runtime.GOOS + "/" + runtime.GOARCH} check(os.WriteFile(filepath.Join(*output, "config.json"), marshal(config), 0644)) metrics := []metric{measure("9fans v0.0.7", frames, *repeats, *chunk), measure("go9p v1.18.0", frames, *repeats, *chunk)} var input bytes.Buffer for _, v := range []uint32{uint32(len(frames)), uint32(*repeats), uint32(*chunk)} { check(binary.Write(&input, binary.LittleEndian, v)) } input.Write(all) command := exec.Command(*probe) command.Stdin = &input var stderr bytes.Buffer command.Stderr = &stderr out, e := command.Output() if e != nil { panic(fmt.Sprintf("cloud9: %v: %s", e, stderr.String())) } if !bytes.Equal(all, out) { panic("cloud9 round-trip differs; replay corpus.9p with saved configuration") } var cloud map[string]any check(json.Unmarshal(stderr.Bytes(), &cloud)) report := map[string]any{"configuration": config, "correctness": "all generated base-9P2000 frames agree byte-for-byte", "cloud9": cloud, "references": metrics, "measurement_notes": []string{"Cloud9 codec timer excludes pipe I/O; Go timers include in-memory stream parsing and byte comparison. Do not treat these as equivalent throughput benchmarks.", "Go allocations use runtime.MemStats deltas on a single-process run; cloud9 codec has no allocation API.", "Cloud9 I/O counters are actual stdin/stdout syscalls; Go read counters are io.Reader calls, not syscalls.", "These are wire-conformance probes, not differential filesystem-server semantics."}} if *session != "" { report["session"] = sessionProbe(*session, *seed, *rounds) } b := marshal(report) check(os.WriteFile(filepath.Join(*output, "report.json"), b, 0644)) os.Stdout.Write(b) }