Skip to content

Commit cab329d

Browse files
authored
Merge pull request #154 from githubnext/copilot/update-benchmark-autoloop-program
perf-comparison autoloop: run benchmarks and commit real results.json each iteration
2 parents fc3d0cf + 7dbe651 commit cab329d

2 files changed

Lines changed: 55 additions & 21 deletions

File tree

.autoloop/programs/perf-comparison/program.md

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ This is an open-ended program — it runs continuously, always adding the next b
2222
- Creates the same dataset as the TypeScript version
2323
- Runs the same operation with the same loop structure
2424
- Outputs the same JSON format
25-
5. **Run both benchmarks** via `benchmarks/run_benchmarks.sh` and capture results.
26-
6. **Update `benchmarks/results.json`** with the new timing data.
27-
7. **Update `playground/benchmarks.html`** to display the new function's comparison metrics.
25+
5. **Update `playground/benchmarks.html`** if needed to display the new function's comparison metrics.
26+
27+
The evaluation step (below) runs `benchmarks/run_benchmarks.sh` to execute **every** TS/Python benchmark pair and regenerates `benchmarks/results.json` with the real timing data. That regenerated file is what gets committed on a successful iteration, so when the autoloop branch is merged to `main`, the pages workflow (`.github/workflows/pages.yml`) picks up the real results and `playground/benchmarks.html` renders real comparison data instead of "No benchmark data available yet."
2828

2929
### Key constraints
3030

@@ -50,24 +50,59 @@ Do NOT modify:
5050

5151
## Evaluation
5252

53+
The evaluation runs `benchmarks/run_benchmarks.sh`, which executes every TS/Python
54+
benchmark pair and writes real timing data to `benchmarks/results.json`. The metric
55+
is the number of benchmarks that appear in that regenerated file — i.e. the number
56+
of function pairs whose benchmarks actually ran to completion and produced valid
57+
JSON output. This means a benchmark pair is only "counted" if it truly runs, and
58+
the committed `benchmarks/results.json` always reflects real data that the
59+
`pages.yml` workflow will copy to the playground on merge to `main`.
60+
5361
```bash
54-
# Set up Python environment if needed
62+
set -euo pipefail
63+
64+
# Ensure Python and pandas are available
5565
if ! command -v python3 &>/dev/null; then
56-
echo "Python3 not found, skipping"
66+
echo "ERROR: python3 is required but not found" >&2
67+
exit 1
5768
fi
58-
pip3 install pandas --quiet 2>/dev/null || true
59-
60-
# Count the number of benchmark pairs (functions with both TS and Python benchmarks)
61-
ts_benchmarks=$(ls benchmarks/tsb/bench_*.ts 2>/dev/null | wc -l | tr -d ' ')
62-
py_benchmarks=$(ls benchmarks/pandas/bench_*.py 2>/dev/null | wc -l | tr -d ' ')
63-
64-
# The metric is the minimum of the two (both must exist for a complete benchmark)
65-
if [ "$ts_benchmarks" -lt "$py_benchmarks" ]; then
66-
count=$ts_benchmarks
67-
else
68-
count=$py_benchmarks
69+
python3 -c "import pandas" 2>/dev/null || pip3 install pandas --quiet
70+
71+
# Ensure Bun is available (install if missing — autoloop runners may not have it).
72+
# Failure to install Bun is logged but does not abort the script, because we must
73+
# still emit the final metric line for autoloop to parse.
74+
if ! command -v bun &>/dev/null; then
75+
curl -fsSL https://bun.sh/install | bash || echo "WARN: bun install script failed" >&2
76+
export PATH="$HOME/.bun/bin:$PATH"
77+
fi
78+
if ! command -v bun &>/dev/null; then
79+
echo "ERROR: bun is not available after install attempt; benchmarks will fail" >&2
6980
fi
7081

82+
# Install JS/TS dependencies so benchmark scripts can import from src/.
83+
# `|| true` keeps the script alive so the final metric is still emitted; any
84+
# errors are visible in the autoloop logs for debugging.
85+
bun install --silent || echo "WARN: bun install failed; benchmarks may fail to import src/" >&2
86+
87+
# Run every benchmark pair and regenerate benchmarks/results.json with real data.
88+
# This is the file .github/workflows/pages.yml copies into the playground, so
89+
# committing it here is what makes real benchmark data appear on the pages site
90+
# once the autoloop branch is merged to main. Output is left visible so
91+
# per-benchmark failures can be diagnosed from autoloop logs; `|| true` ensures
92+
# we still reach the metric emission below if the script exits nonzero.
93+
bash benchmarks/run_benchmarks.sh || echo "WARN: run_benchmarks.sh exited nonzero" >&2
94+
95+
# Metric: number of benchmark entries in the regenerated results.json.
96+
count=$(python3 -c "
97+
import json
98+
try:
99+
with open('benchmarks/results.json') as f:
100+
data = json.load(f)
101+
print(len(data.get('benchmarks', [])))
102+
except Exception:
103+
print(0)
104+
")
105+
71106
echo "{\"benchmarked_functions\": ${count:-0}}"
72107
```
73108

src/reshape/explode.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface ExplodeOptions {
3636
* When `false` (default), the original row labels are propagated
3737
* (duplicated once for each element of each list value).
3838
*/
39-
readonly ignore_index?: boolean;
39+
readonly ignoreIndex?: boolean;
4040
}
4141

4242
// ─── helpers ──────────────────────────────────────────────────────────────────
@@ -89,7 +89,7 @@ function expandCell(value: Scalar): Scalar[] {
8989
* ```
9090
*/
9191
export function explodeSeries(series: Series<Scalar>, options?: ExplodeOptions): Series<Scalar> {
92-
const ignoreIndex = options?.ignore_index ?? false;
92+
const ignoreIndex = options?.ignoreIndex ?? false;
9393
const outValues: Scalar[] = [];
9494
const outLabels: Label[] = [];
9595

@@ -122,7 +122,7 @@ export function explodeSeries(series: Series<Scalar>, options?: ExplodeOptions):
122122
* Explode one or more list-valued columns of a DataFrame into multiple rows.
123123
*
124124
* All other columns have their values repeated to match the expanded rows.
125-
* Row labels are propagated (duplicated) unless `ignore_index` is `true`.
125+
* Row labels are propagated (duplicated) unless `ignoreIndex` is `true`.
126126
*
127127
* When multiple columns are specified they must have the same list lengths per
128128
* row — pandas raises a `ValueError` for mismatched lengths; here each column
@@ -150,9 +150,8 @@ export function explodeDataFrame(
150150
column: string | readonly string[],
151151
options?: ExplodeOptions,
152152
): DataFrame {
153-
const ignoreIndex = options?.ignore_index ?? false;
153+
const ignoreIndex = options?.ignoreIndex ?? false;
154154
const explodeCols: readonly string[] = typeof column === "string" ? [column] : column;
155-
156155
// Validate column names
157156
for (const col of explodeCols) {
158157
if (!df.columns.values.includes(col)) {

0 commit comments

Comments
 (0)