Repository navigation
ENH: record a suite outside the subject's checkout as its own benchmark source - #70
Conversation
|
Pushed a demo to its own repository: https://github.com/ev-br/benchx_user |
|
Mind taking a quick look @MaanasArora ? This is a small addition to allow out-of-tree benchmark suites: basically, the goal is to be able to record the benchmarking suite (local or a repository) separately from the project being benchmarked. |
MaanasArora
left a comment
There was a problem hiding this comment.
Sorry for the delay @ev-br, this looks great thanks! It's a good idea to do this, for both tracked and ad-hoc use cases.
My main comment is that we correctly identify unversioned benchmarks as dirty now, so revisions doesn't seem to work if they're outside. I think it'll be a (different) small change in compare.py though, so happy for it to be follow-up!
| ### 3.3 Benchmark suite location (addendum) | ||
|
|
||
| §3's field table and §3.1 name only the subject's target. Nothing in the original draft says where the *benchmark* suite's own code lives, yet every non-thin result requires `benchmark.source` and `benchmark.revision` (`benchmark-result-schema.md` §4.1, §5.2) alongside `provenance.benchmark_dirty`/`benchmark_tree`. This is a gap in the original design, closed here: an optional `benchmark` object, `{source, revision}`, mirroring `sourceRef` and a bare revision key the way `target.kind: revision` does. When present, the runner records that revision the same way it records `target`'s, from the benchmark checkout it is pointed at; it does not fetch it. When absent, the benchmarks are assumed to live in the same checkout as `target`, and the runner reuses `target`'s resolved source, revision, dirty flag, and tree for `benchmark.*` and `provenance.benchmark_dirty`/`benchmark_tree` — the common case where a project's benchmarks live alongside its own code. A benchmark suite with no version control at all (an installed, unversioned directory) is not covered by this addendum and remains open. | ||
| §3's field table and §3.1 name only the subject's target. Nothing in the original draft says where the *benchmark* suite's own code lives, yet every non-thin result requires `benchmark.source` and `benchmark.revision` (`benchmark-result-schema.md` §4.1, §5.2) alongside `provenance.benchmark_dirty`/`benchmark_tree`. This is a gap in the original design, closed here: an optional `benchmark` object, `{source, revision}`, mirroring `sourceRef` and a bare revision key the way `target.kind: revision` does. When present, the runner records that revision the same way it records `target`'s, from the benchmark checkout it is pointed at; it does not fetch it. When absent, the benchmarks are assumed to live in the same checkout as `target`, and the runner reuses `target`'s resolved source, revision, dirty flag, and tree for `benchmark.*` and `provenance.benchmark_dirty`/`benchmark_tree` — the common case where a project's benchmarks live alongside its own code. A benchmark suite with no version control is covered for a single file: `benchmark.revision` is then absent, `benchmark.source` is the `file://` URI of the file's directory (`type: directory`), `provenance.benchmark_tree` is the file's git blob id (`git hash-object FILE`), and `benchmark_dirty` is `dirty`. The file, not its directory, is the unit hashed, so what it imports is not covered. A suite inside another git repository takes that repository's source and HEAD as its revision, with the file's own blob id as the tree and `clean` when the file equals HEAD's version. The prototype applies this to suites that are source files (pyperf); a suite that is a built binary (Google Benchmark) is the subject's own. The runner finds the suite's identity itself, whatever the order says, and refuses an order whose `benchmark` disagrees with it. A `file://` source names a place on one machine, so such a series does not follow the suite to another machine or folder (the prototype's identity keeps the benchmark's source URI). |
There was a problem hiding this comment.
Nit, but seems Claude is memorializing an "original draft", if we don't need it maybe we can retire its memory here :)
|
|
||
| NAME = "pyperf" | ||
| # The suite is a Python source file, which may live outside the subject's checkout. | ||
| SUITE_IS_SOURCE = True |
There was a problem hiding this comment.
Just a note, we would also need this for asv after rebase.
| "ended_at": _timestamp(started + duration), | ||
| "subject_dirty": source["dirty"], | ||
| "benchmark_dirty": source["dirty"], | ||
| "benchmark_dirty": benchmark["dirty"] if benchmark else source["dirty"], |
There was a problem hiding this comment.
I think right now compare.py matches for clean trees, so I think if we have an unversioned benchmark file we can't run it against revisions. I think it might just be a missing update from #83? Either way, happy to do that in follow-up too if it's tricky!
| suite = Path(suite_file).resolve() | ||
| if suite.is_relative_to(Path(subject_source).resolve()): | ||
| return None | ||
| tree = blob_id(suite) |
There was a problem hiding this comment.
My Claude noticed this could be too strict about line-endings (on Windows for example where the git default is CRLF). It suggests we use git hash-object instead of the blob, but I haven't looked too much into it, maybe we can look at it down the line!
There was a problem hiding this comment.
Oh let's punt on Windows for the moment? There are multiple places which assume POSIX, let's turn windows testing and make it run in one go separately.
…rk source A pyperf suite that lies outside the subject's source tree is the benchmark's own code. Its identity is the suite file, not its directory: in a git checkout the source is that repository and its HEAD, with the file's blob id as the tree (clean when it equals HEAD's version); outside git the source is the file:// URI of its directory, with no revision, the blob id as the tree, and dirty. The work order carries `benchmark` (its revision is now optional), and the runner finds the suite's identity itself and refuses an order that disagrees. A Google Benchmark suite is a binary built from the subject, so it is the subject's own, as before. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
cff9c6e to
748857a
Compare
|
Thanks for the review @MaanasArora ! Merged this per your approval, with fixes to Claude's memorializations and setting the out-of-tree flag for |
One more piece from my dogfooding numpy benchmarks: the subject is numpy, and benchmarks are out-of-tree. For the moment, they live in a branch of
benchx/prototype/examples, and are uncommitted. With this PR, the relevant parts of the results JSON readand
A pyperf suite that lies outside the subject's source tree is the benchmark's own code. Its identity is the suite file, not its directory: in a git checkout the source is that repository and its HEAD, with the file's blob id as the tree (clean when it equals HEAD's version); outside git the source is the file:// URI of its directory, with no revision, the blob id as the tree, and dirty.
The work order carries
benchmark(its revision is now optional), and the runner finds the suite's identity itself and refuses an order that disagrees. A Google Benchmark suite is a binary built from the subject, so it is the subject's own, as before.closes #48