@opensassi/opencode 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/AGENTS.md +35 -0
  2. package/README.md +81 -0
  3. package/bin/opencode.js +3 -0
  4. package/lib/cli.js +38 -0
  5. package/lib/commands/init.js +117 -0
  6. package/lib/commands/print-agents.js +6 -0
  7. package/lib/commands/print-skill.js +8 -0
  8. package/lib/commands/run.js +57 -0
  9. package/lib/index.js +4 -0
  10. package/lib/util/paths.js +21 -0
  11. package/package.json +40 -0
  12. package/scripts/asm-optimizer/run-baseline.sh +158 -0
  13. package/scripts/check-artifacts.js +131 -0
  14. package/scripts/extract-artifacts.js +204 -0
  15. package/scripts/install/linux/ubuntu-noble-24.04/install.sh +94 -0
  16. package/scripts/install/osx/macos-sequoia-15.0/install.sh +115 -0
  17. package/scripts/install/windows/wsl2/install.ps1 +98 -0
  18. package/scripts/install.ps1 +32 -0
  19. package/scripts/install.sh +83 -0
  20. package/scripts/puppeteer-config.json +3 -0
  21. package/scripts/test-artifacts.js +346 -0
  22. package/scripts/validate-all.js +18 -0
  23. package/scripts/verify-artifact.js +157 -0
  24. package/skills/asm-optimizer/SKILL.md +295 -0
  25. package/skills/daily-evaluation/SKILL.md +86 -0
  26. package/skills/git/SKILL.md +100 -0
  27. package/skills/issue/SKILL.md +104 -0
  28. package/skills/npm-optimizer/SKILL.md +218 -0
  29. package/skills/opensassi/SKILL.md +77 -0
  30. package/skills/opensassi/scripts/ensure-gitignore.sh +89 -0
  31. package/skills/opensassi/scripts/env-check.ps1 +139 -0
  32. package/skills/opensassi/scripts/env-check.sh +200 -0
  33. package/skills/opensassi/scripts/install-flamegraph.sh +32 -0
  34. package/skills/opensassi/scripts/install-npm-deps.sh +25 -0
  35. package/skills/profiler/SKILL.md +213 -0
  36. package/skills/profiler/scripts/benchmark.sh +63 -0
  37. package/skills/profiler/scripts/common.sh +55 -0
  38. package/skills/profiler/scripts/compare.sh +63 -0
  39. package/skills/profiler/scripts/profile.sh +63 -0
  40. package/skills/profiler/scripts/setup.sh +32 -0
  41. package/skills/session-evaluation/SKILL.md +128 -0
  42. package/skills/skill-manager/SKILL.md +251 -0
  43. package/skills/system-design/SKILL.md +558 -0
  44. package/skills/system-design-review/SKILL.md +396 -0
  45. package/skills/todo/SKILL.md +165 -0
  46. package/skills-index.json +137 -0
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env bash
2
+ # env-check.sh — Bootstrap environment detection for opencode opensassi skill.
3
+ # Detects OS, ensures git, installs Node.js LTS via nvm if needed.
4
+ # Outputs JSON to stdout: {os, distro, version, codename, pkg_manager, shell,
5
+ # is_wsl, arch, node_version, nvm_version, git_version}
6
+ #
7
+ # Usage: bash env-check.sh
8
+ # Dependencies: bash, common UNIX utilities (uname, grep, cut, etc.)
9
+
10
+ set -euo pipefail
11
+
12
+ # --- OS Detection ---
13
+ OS="$(uname -s)"
14
+ ARCH="$(uname -m)"
15
+ SHELL_NAME="$(basename "${SHELL:-bash}")"
16
+ IS_WSL=false
17
+
18
+ if grep -qi "microsoft\|wsl" /proc/version 2>/dev/null; then
19
+ IS_WSL=true
20
+ fi
21
+
22
+ # Normalize arch
23
+ case "$ARCH" in
24
+ x86_64|amd64) ARCH="x64" ;;
25
+ aarch64|arm64) ARCH="arm64" ;;
26
+ esac
27
+
28
+ # --- Distro Detection ---
29
+ DISTRO=""
30
+ VERSION=""
31
+ CODENAME=""
32
+ PKG_MANAGER=""
33
+
34
+ detect_linux() {
35
+ if [ -f /etc/os-release ]; then
36
+ . /etc/os-release
37
+ DISTRO="${ID:-linux}"
38
+ VERSION="${VERSION_ID:-}"
39
+ CODENAME="${VERSION_CODENAME:-$UBUNTU_CODENAME}"
40
+ elif [ -f /etc/lsb-release ]; then
41
+ . /etc/lsb-release
42
+ DISTRO="${DISTRIB_ID:-linux}"
43
+ VERSION="${DISTRIB_RELEASE:-}"
44
+ CODENAME="${DISTRIB_CODENAME:-}"
45
+ fi
46
+ DISTRO="$(echo "$DISTRO" | tr '[:upper:]' '[:lower:]')"
47
+
48
+ # Detect package manager
49
+ for pm in apt dnf yum pacman zypper; do
50
+ if command -v "$pm" &>/dev/null; then
51
+ PKG_MANAGER="$pm"
52
+ break
53
+ fi
54
+ done
55
+ }
56
+
57
+ detect_macos() {
58
+ DISTRO="macos"
59
+ if command -v sw_vers &>/dev/null; then
60
+ VERSION="$(sw_vers -productVersion 2>/dev/null || echo "")"
61
+ case "$VERSION" in
62
+ 15.*) CODENAME="sequoia" ;;
63
+ 14.*) CODENAME="sonoma" ;;
64
+ 13.*) CODENAME="ventura" ;;
65
+ 12.*) CODENAME="monterey" ;;
66
+ 11.*) CODENAME="big-sur" ;;
67
+ *) CODENAME="unknown" ;;
68
+ esac
69
+ fi
70
+ if command -v brew &>/dev/null; then
71
+ PKG_MANAGER="brew"
72
+ fi
73
+ }
74
+
75
+ case "$OS" in
76
+ Linux)
77
+ detect_linux
78
+ if $IS_WSL; then
79
+ # In WSL, use Windows-side detection for pkg_manager hint
80
+ :
81
+ fi
82
+ ;;
83
+ Darwin)
84
+ detect_macos
85
+ ;;
86
+ MINGW*|MSYS*|CYGWIN*)
87
+ # Git Bash / MSYS2 on Windows — limited support, point to ps1
88
+ DISTRO="windows"
89
+ OS="win32"
90
+ PKG_MANAGER=""
91
+ if command -v winget &>/dev/null; then
92
+ PKG_MANAGER="winget"
93
+ elif command -v choco &>/dev/null; then
94
+ PKG_MANAGER="choco"
95
+ fi
96
+ ;;
97
+ *)
98
+ DISTRO="unknown"
99
+ ;;
100
+ esac
101
+
102
+ # --- Ensure git ---
103
+ if ! command -v git &>/dev/null; then
104
+ echo "[INFO] git not found. Installing..." >&2
105
+ case "${PKG_MANAGER:-}" in
106
+ apt) sudo apt update && sudo apt install -y git ;;
107
+ dnf) sudo dnf install -y git ;;
108
+ yum) sudo yum install -y git ;;
109
+ pacman) sudo pacman -Sy --noconfirm git ;;
110
+ zypper) sudo zypper install -y git ;;
111
+ brew) brew install git ;;
112
+ *)
113
+ echo "[WARN] Cannot install git automatically. Install git manually." >&2
114
+ ;;
115
+ esac
116
+ fi
117
+ GIT_VERSION="$(git --version 2>/dev/null | sed 's/git version //' || echo "")"
118
+
119
+ # --- Ensure Node.js (LTS via nvm) ---
120
+ NODE_VERSION=""
121
+ NVM_VERSION=""
122
+
123
+ setup_node() {
124
+ # Check if node is already at LTS or later
125
+ if command -v node &>/dev/null; then
126
+ local current
127
+ current="$(node --version | sed 's/^v//')"
128
+ local major
129
+ major="$(echo "$current" | cut -d. -f1)"
130
+ # Use node if >= 18 (LTS cutoff)
131
+ if [ "$major" -ge 18 ] 2>/dev/null; then
132
+ NODE_VERSION="$current"
133
+ echo "[INFO] Node.js v$NODE_VERSION already available" >&2
134
+ return 0
135
+ fi
136
+ fi
137
+
138
+ # Find or install nvm
139
+ local nvm_install_dir=""
140
+ if [ -n "${NVM_DIR:-}" ] && [ -s "$NVM_DIR/nvm.sh" ]; then
141
+ nvm_install_dir="$NVM_DIR"
142
+ elif [ -s "$HOME/.nvm/nvm.sh" ]; then
143
+ nvm_install_dir="$HOME/.nvm"
144
+ elif [ -s "$HOME/.local/share/nvm/nvm.sh" ]; then
145
+ nvm_install_dir="$HOME/.local/share/nvm"
146
+ fi
147
+
148
+ if [ -n "$nvm_install_dir" ]; then
149
+ echo "[INFO] nvm found at $nvm_install_dir" >&2
150
+ export NVM_DIR="$nvm_install_dir"
151
+ # shellcheck disable=SC1091
152
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
153
+ NVM_VERSION="$(nvm --version 2>/dev/null || echo "")"
154
+ else
155
+ echo "[INFO] nvm not found. Installing nvm v0.40.0..." >&2
156
+ export NVM_DIR="$HOME/.nvm"
157
+ mkdir -p "$NVM_DIR"
158
+ curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh" | bash 2>/dev/null || {
159
+ echo "[ERROR] Failed to install nvm. Install manually:" >&2
160
+ echo " curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash" >&2
161
+ return 1
162
+ }
163
+ # shellcheck disable=SC1091
164
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
165
+ NVM_VERSION="$(nvm --version 2>/dev/null || echo "")"
166
+ echo "[INFO] nvm v$NVM_VERSION installed" >&2
167
+ fi
168
+
169
+ # Install LTS node (idempotent — no-op if already present)
170
+ if [ -n "${NVM_DIR:-}" ] && [ -s "$NVM_DIR/nvm.sh" ]; then
171
+ echo "[INFO] Installing latest Node.js LTS via nvm..." >&2
172
+ nvm install --lts 2>/dev/null || true
173
+ nvm use --lts 2>/dev/null || true
174
+ # Write .nvmrc for project
175
+ local project_root
176
+ project_root="$(git rev-parse --show-toplevel 2>/dev/null || echo ".")"
177
+ echo "--lts" > "$project_root/.nvmrc" 2>/dev/null || true
178
+ NODE_VERSION="$(node --version 2>/dev/null | sed 's/^v//' || echo "")"
179
+ echo "[INFO] Node.js v$NODE_VERSION (LTS) ready via nvm" >&2
180
+ fi
181
+ }
182
+
183
+ setup_node || true
184
+
185
+ # --- Output JSON ---
186
+ cat <<JSONEOF
187
+ {
188
+ "os": "$OS",
189
+ "distro": "$DISTRO",
190
+ "version": "$VERSION",
191
+ "codename": "$CODENAME",
192
+ "pkg_manager": "$PKG_MANAGER",
193
+ "shell": "$SHELL_NAME",
194
+ "is_wsl": $IS_WSL,
195
+ "arch": "$ARCH",
196
+ "node_version": "$NODE_VERSION",
197
+ "nvm_version": "$NVM_VERSION",
198
+ "git_version": "$GIT_VERSION"
199
+ }
200
+ JSONEOF
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+ # install-flamegraph.sh — Clone Brendan Gregg's FlameGraph at pinned tag v1.0.
3
+ # Idempotent: updates existing clone if present.
4
+ # Usage: bash install-flamegraph.sh
5
+
6
+ set -euo pipefail
7
+
8
+ PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || (cd "$(dirname "$0")/../../.." && pwd))"
9
+ FLAMEGRAPH_DIR="$PROJECT_ROOT/scripts/FlameGraph"
10
+
11
+ if [ -d "$FLAMEGRAPH_DIR/.git" ]; then
12
+ echo "[INFO] FlameGraph already cloned. Updating to v1.0..."
13
+ git -C "$FLAMEGRAPH_DIR" fetch --tags --depth=1 2>&1 | tail -1
14
+ git -C "$FLAMEGRAPH_DIR" checkout v1.0 2>&1 || {
15
+ echo "[WARN] Could not checkout v1.0; resetting to tag..."
16
+ git -C "$FLAMEGRAPH_DIR" reset --hard v1.0 2>&1
17
+ }
18
+ else
19
+ echo "[INFO] Cloning FlameGraph v1.0 to $FLAMEGRAPH_DIR..."
20
+ git clone --depth=1 --branch v1.0 https://github.com/brendangregg/FlameGraph.git "$FLAMEGRAPH_DIR" 2>&1 || {
21
+ echo "[ERROR] Failed to clone FlameGraph. Clone manually:"
22
+ echo " git clone --depth=1 --branch v1.0 https://github.com/brendangregg/FlameGraph.git $FLAMEGRAPH_DIR"
23
+ exit 1
24
+ }
25
+ fi
26
+
27
+ if [ -f "$FLAMEGRAPH_DIR/flamegraph.pl" ]; then
28
+ echo "[INFO] FlameGraph ready: $FLAMEGRAPH_DIR"
29
+ else
30
+ echo "[WARN] FlameGraph clone may be incomplete — flamegraph.pl not found."
31
+ ls "$FLAMEGRAPH_DIR" | head -10
32
+ fi
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+ # install-npm-deps.sh — Install npm dependencies for the opencode project.
3
+ # Usage: bash install-npm-deps.sh
4
+
5
+ set -euo pipefail
6
+
7
+ PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || (cd "$(dirname "$0")/../../.." && pwd))"
8
+
9
+ if ! command -v node &>/dev/null; then
10
+ echo "[ERROR] Node.js not found. Run env-check.sh first."
11
+ exit 1
12
+ fi
13
+
14
+ if [ ! -f "$PROJECT_ROOT/package.json" ]; then
15
+ echo "[WARN] No package.json found at $PROJECT_ROOT — skipping npm install"
16
+ exit 0
17
+ fi
18
+
19
+ echo "[INFO] Installing npm dependencies..."
20
+ cd "$PROJECT_ROOT"
21
+ npm install 2>&1 | tail -5 || {
22
+ echo "[ERROR] npm install failed"
23
+ exit 1
24
+ }
25
+ echo "[INFO] npm dependencies installed"
@@ -0,0 +1,213 @@
1
+ ---
2
+ name: profiler
3
+ description: Profiling, flamegraph generation, and benchmarking using Linux perf
4
+ ---
5
+
6
+ # Interactive Profiler Agent Prompt
7
+
8
+ ## Persona
9
+
10
+ You are a **senior performance engineer** with deep expertise in Linux perf, CPU profiling, SIMD optimization (SSE4.1, ARM Neon/SVE/SVE2).
11
+ Your role is to help users profile their software, generate flamegraphs, run benchmarks with quality regression detection, and target optimization efforts.
12
+
13
+ You always work **interactively** — propose a profiling plan, run tools, analyze results, and only proceed to deeper investigation when the user agrees.
14
+
15
+ ---
16
+
17
+ ## Response Guidelines
18
+
19
+ When activated:
20
+
21
+ 1. **Check environment** — Run `check` to verify: `perf` available, Release binary exists, benchmark data at `test/data/`, FlameGraph scripts at `scripts/FlameGraph/`, quality metric tooling if needed.
22
+ 2. **Report status** — Output a summary of what's available and what's missing. Do not initiate a profiling session without user direction.
23
+ 3. **Propose first steps** — Suggest running a baseline `profile` or `benchmark` depending on the user's goal.
24
+
25
+ ---
26
+
27
+ ## Commands
28
+
29
+ ### `check`
30
+
31
+ Verify the profiling toolchain. Runs the following checks and reports pass/fail:
32
+
33
+ - `perf` is installed and accessible
34
+ - Encoder Release binary exists (check `bin/release-static/` or build tree)
35
+ - `test/data/` contains benchmark input data
36
+ - `scripts/FlameGraph/stackcollapse-perf.pl` and `flamegraph.pl` exist (clone via opensassi skill if missing)
37
+ - `ffmpeg` available (needed for `--vmaf`)
38
+ - `vmaf` tool available (needed for `--vmaf`)
39
+ - `.profiler/` output directory exists
40
+
41
+ Saves a brief report to `.profiler/check.json`.
42
+
43
+ ### `setup`
44
+
45
+ Download and prepare test data for profiling.
46
+
47
+ Usage:
48
+ ```
49
+ setup # default: download/prompt for test data
50
+ setup --frames 50 # override frame count
51
+ setup --resize 1280x720 # produce resized variant via ffmpeg
52
+ ```
53
+
54
+ What it does:
55
+ 1. Downloads or prepares test input data (configurable for your domain)
56
+ 3. If `--resize` given, runs `ffmpeg` to produce resized variants
57
+ 4. Creates `.profiler/` directory structure: `flamegraphs/`, `benchmarks/`, `perf_archives/`, `reports/`
58
+ 5. Creates `.gitignore` entries for test data and `.profiler/` if not present
59
+ 6. Checks that `scripts/FlameGraph/` exists; if not, runs the opensassi skill to clone it
60
+
61
+ Example output files (video encoder project):
62
+ ```
63
+ test/data/input_1080p10.yuv (full-res source, 10 frames)
64
+ test/data/input_1280x720f10.yuv (default profile resolution)
65
+ test/data/input_832x480f10.yuv (--resize 832x480)
66
+ ```
67
+
68
+ ### `profile`
69
+
70
+ Run `perf record` on your program and produce a flamegraph.
71
+
72
+ Usage:
73
+ ```
74
+ profile # default: test data, default config, cycles
75
+ profile --events cache-misses,branch-misses # custom perf events
76
+ profile --frames 50 # override frame count
77
+ ```
78
+
79
+ What it does:
80
+ 1. Runs: `perf record --call-graph fp -e cycles,cache-misses,branch-misses -o <file> -- <program> <args>`
81
+ 2. Generates folded stack: `perf script -i perf.data | stackcollapse-perf.pl > folded.txt`
82
+ 3. Generates flamegraph: `flamegraph.pl folded.txt > flame.svg`
83
+ 4. Collects hardware counter summary: `perf stat -e cycles,cache-misses,branch-misses -- <program> <args> > perf.stat 2>&1`
84
+ 5. Saves all to `.profiler/perf_archives/{label}/`
85
+
86
+ Output artifacts:
87
+ ```
88
+ .profiler/perf_archives/<label>/
89
+ ├── perf.data (raw, for LLM/tooling analysis)
90
+ ├── perf.stat (hardware counter summary)
91
+ ├── folded.txt (collapsed stacks for diffing)
92
+ ├── flame.svg (interactive flamegraph)
93
+ └── meta.json (program config, args, version)
94
+ ```
95
+
96
+ ### `benchmark`
97
+
98
+ Run N iterations of the program with performance metric collection.
99
+
100
+ Usage:
101
+ ```
102
+ benchmark # default: 5 iterations
103
+ benchmark --iter 10 # 10 iterations
104
+ ```
105
+
106
+ Output:
107
+ ```
108
+ .profiler/benchmarks/benchmark-{timestamp}.json
109
+ ```
110
+
111
+ JSON structure:
112
+ ```json
113
+ {
114
+ "label": "benchmark-label",
115
+ "timestamp": "...",
116
+ "iterations": [
117
+ {
118
+ "iter": 1,
119
+ "wall_time_ms": 45230,
120
+ "metric_1": 38.42,
121
+ "metric_2": 44.15
122
+ }
123
+ ],
124
+ "summary": {
125
+ "time_avg_ms": 44987,
126
+ "time_min_ms": 44123,
127
+ "time_max_ms": 46234
128
+ },
129
+ "config": {
130
+ "source": "test/data/input.yuv",
131
+ "frames": 50,
132
+ "metrics": ["metric_1"]
133
+ }
134
+ }
135
+ ```
136
+
137
+ ### `compare`
138
+
139
+ Compare two benchmark runs side-by-side.
140
+
141
+ Usage:
142
+ ```
143
+ compare <baseline.json> <candidate.json>
144
+ ```
145
+
146
+ Output:
147
+ ```
148
+ === Comparison: baseline vs candidate ===
149
+ Metric Baseline Candidate Δ% Status
150
+ ──────────────────────────────────────────────────────────
151
+ Wall time (ms) 44987 41230 -8.35% ✓
152
+ Throughput 1.112 1.213 +9.08% ✓
153
+ Quality 38.41 38.38 -0.08% ⚠ below threshold
154
+
155
+ Regression thresholds:
156
+ Δ time > +2% AND Δ quality < -0.1 → REGRESSION flag
157
+ Status: PASS (no regression detected)
158
+ ```
159
+
160
+ A regression is flagged when both conditions are met:
161
+ - Wall-clock time increases by more than the threshold (default +2%)
162
+ - Any quality metric drops below its threshold
163
+
164
+ These thresholds are configurable in `common.sh`.
165
+
166
+ ### `report`
167
+
168
+ Bundle a profiling session into a report.
169
+
170
+ Usage:
171
+ ```
172
+ report # bundle most recent profile + benchmark
173
+ report --profile <label> # specific profile archive
174
+ report --benchmark <file> # specific benchmark JSON
175
+ ```
176
+
177
+ Produces:
178
+ ```
179
+ .profiler/reports/report-{timestamp}/
180
+ ├── flame.svg
181
+ ├── benchmark-table.txt
182
+ ├── perf-summary.txt
183
+ ├── system-info.txt (uname, cpuinfo, perf version, encoder version)
184
+ └── meta.json
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Design Principles
190
+
191
+ - **Default workload**: configurable in `common.sh`
192
+ - **Resized input variants** via `setup --resize WxH` for fast iteration
193
+ - **Release build only** (ensure `-fno-omit-frame-pointer` is enabled for meaningful flamegraphs)
194
+ - **5 iterations minimum** for benchmark; raw `perf.data` retained for LLM analysis
195
+ - **FlameGraph scripts** at `scripts/FlameGraph/` (cloned by opensassi skill from Brendan Gregg's repo)
196
+ - **Input data**: `test/data/` (gitignored, downloaded by setup)
197
+ - **Output artifacts**: `.profiler/` (hidden dir, gitignored)
198
+ - **Read-only on source code** — never modifies source or build files
199
+ - **perf events**: `cycles,cache-misses,branch-misses` default; extend via `--events`
200
+
201
+ ---
202
+
203
+ ## Support Scripts
204
+
205
+ Support scripts live in the `@opensassi/opencode` package. Run them via `npx @opensassi/opencode run --skill profiler <name>`:
206
+
207
+ | Script | Purpose |
208
+ |---|---|
209
+ | `common.sh` | Shared config, paths, defaults, threshold constants |
210
+ | `setup.sh` | Download test data, --resize/--frames, FlameGraph clone, gitignore |
211
+ | `profile.sh` | perf record → flamegraph pipeline |
212
+ | `benchmark.sh` | Iteration loop, metric collection, JSON output |
213
+ | `compare.sh` | Two JSON input, Δ% table, regression detection |
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env bash
2
+ # Benchmark: run N iterations of your program with timing.
3
+ # Usage: ./benchmark.sh [--iter N]
4
+
5
+ source "$(dirname "$0")/common.sh"
6
+
7
+ # --- Parse args ---
8
+ ITERATIONS=$DEFAULT_ITERATIONS
9
+
10
+ while [[ $# -gt 0 ]]; do
11
+ case "$1" in
12
+ --iter) shift; ITERATIONS="$1" ;;
13
+ *) log_error "Unknown option: $1"; exit 1 ;;
14
+ esac
15
+ shift
16
+ done
17
+
18
+ PROGRAM="$(find_program)"
19
+ if [[ -z "$PROGRAM" ]]; then
20
+ log_error "Program binary not found."
21
+ exit 1
22
+ fi
23
+
24
+ # --- Iteration loop ---
25
+ RESULTS_FILE="$OUTPUT_DIR/benchmarks/benchmark-$(timestamp).json"
26
+
27
+ declare -a ITER_DATA
28
+ for ((i=1; i<=ITERATIONS; i++)); do
29
+ log_info "Iteration $i / $ITERATIONS ..."
30
+
31
+ START_MS=$(date +%s%3N)
32
+ "$PROGRAM" 2>&1 | tee "$OUTPUT_DIR/benchmarks/iter_${i}.log"
33
+ END_MS=$(date +%s%3N)
34
+ WALL_MS=$((END_MS - START_MS))
35
+
36
+ ITEM=$(cat <<ITEMEOF
37
+ {
38
+ "iter": $i,
39
+ "wall_time_ms": $WALL_MS
40
+ }
41
+ ITEMEOF
42
+ )
43
+ ITER_DATA+=("$ITEM")
44
+ done
45
+
46
+ # --- Build JSON ---
47
+ JSON=$(cat <<JSONEOF
48
+ {
49
+ "label": "benchmark-$(timestamp)",
50
+ "timestamp": "$(timestamp)",
51
+ "iterations": [
52
+ $(IFS=,; echo "${ITER_DATA[*]}")
53
+ ],
54
+ "config": {
55
+ "program": "$PROGRAM",
56
+ "iterations": $ITERATIONS
57
+ }
58
+ }
59
+ JSONEOF
60
+ )
61
+
62
+ echo "$JSON" > "$RESULTS_FILE"
63
+ log_info "Benchmark saved: $RESULTS_FILE"
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+ # Common configuration and paths for the profiler skill.
3
+ # Source this from other scripts: source "$(dirname "$0")/common.sh"
4
+
5
+ set -euo pipefail
6
+
7
+ # --- Paths ---
8
+ PROJECT_ROOT="$(cd "$(dirname "$0")/../../../../" && pwd)"
9
+ SCRIPTS_DIR="$PROJECT_ROOT/.opencode/skills/profiler/scripts"
10
+ OUTPUT_DIR="$PROJECT_ROOT/.profiler"
11
+ DATA_DIR="$PROJECT_ROOT/test/data"
12
+ FLAMEGRAPH_DIR="$PROJECT_ROOT/scripts/FlameGraph"
13
+
14
+ # --- Default workload (customize for your project) ---
15
+ DEFAULT_INPUT="input"
16
+ DEFAULT_RESOLUTION="1280x720"
17
+ DEFAULT_FRAMES=10
18
+ DEFAULT_CONFIG="default"
19
+
20
+ # --- Benchmark defaults ---
21
+ DEFAULT_ITERATIONS=5
22
+
23
+ # --- Regression thresholds ---
24
+ THRESHOLD_TIME_PCT=2.0
25
+ THRESHOLD_QUALITY=0.1
26
+
27
+ # --- perf defaults ---
28
+ PERF_EVENTS_DEFAULT="cycles,cache-misses,branch-misses"
29
+
30
+ # --- Binary discovery (customize for your project) ---
31
+ find_program() {
32
+ local paths=(
33
+ "$PROJECT_ROOT/bin/release/program"
34
+ "$PROJECT_ROOT/build/program"
35
+ "$PROJECT_ROOT/program"
36
+ )
37
+ for p in "${paths[@]}"; do
38
+ if [[ -x "$p" ]]; then
39
+ echo "$p"
40
+ return 0
41
+ fi
42
+ done
43
+ echo ""
44
+ return 1
45
+ }
46
+
47
+ # --- Timestamp ---
48
+ timestamp() {
49
+ date +%Y%m%dT%H%M%S
50
+ }
51
+
52
+ # --- Logging ---
53
+ log_info() { echo "[INFO] $*"; }
54
+ log_warn() { echo "[WARN] $*" >&2; }
55
+ log_error() { echo "[ERROR] $*" >&2; }
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env bash
2
+ # Compare two benchmark JSON files, output Δ% table with regression detection.
3
+ # Usage: ./compare.sh <baseline.json> <candidate.json>
4
+
5
+ source "$(dirname "$0")/common.sh"
6
+
7
+ if [[ $# -ne 2 ]]; then
8
+ log_error "Usage: $0 <baseline.json> <candidate.json>"
9
+ exit 1
10
+ fi
11
+
12
+ BASELINE="$1"
13
+ CANDIDATE="$2"
14
+
15
+ if [[ ! -f "$BASELINE" ]]; then log_error "Baseline not found: $BASELINE"; exit 1; fi
16
+ if [[ ! -f "$CANDIDATE" ]]; then log_error "Candidate not found: $CANDIDATE"; exit 1; fi
17
+
18
+ python3 -c "
19
+ import json, sys
20
+
21
+ with open('$BASELINE') as f: b = json.load(f)
22
+ with open('$CANDIDATE') as f: c = json.load(f)
23
+
24
+ def avg(items, key):
25
+ vals = [i.get(key) for i in items if i.get(key) is not None]
26
+ if not vals:
27
+ return None
28
+ return sum(vals) / len(vals)
29
+
30
+ def pct(b_val, c_val):
31
+ if b_val is None or c_val is None or b_val == 0:
32
+ return None
33
+ return ((c_val - b_val) / b_val) * 100
34
+
35
+ b_t = avg(b['iterations'], 'wall_time_ms')
36
+ c_t = avg(c['iterations'], 'wall_time_ms')
37
+
38
+ print(f\"{'Metric':<25} {'Baseline':<14} {'Candidate':<14} {'Δ%':<10} {'Status'}\")
39
+ print(f\"{'-'*25} {'-'*14} {'-'*14} {'-'*10} {'-'*10}\")
40
+
41
+ def fmt(v, unit=''):
42
+ if v is None: return 'N/A'
43
+ return f'{v:.2f}{unit}'
44
+
45
+ regression = False
46
+
47
+ # Wall time: negative Δ% = good (faster)
48
+ dt = pct(b_t, c_t)
49
+ status = '✓' if dt is not None and dt < $THRESHOLD_TIME_PCT else ''
50
+ if dt is not None and dt >= $THRESHOLD_TIME_PCT:
51
+ status = '⚠ REGRESSION'
52
+ regression = True
53
+ print(f\"{'Wall time (ms)':<25} {fmt(b_t):<14} {fmt(c_t):<14} {fmt(dt, '%'):<10} {status}\")
54
+
55
+ print()
56
+ if regression:
57
+ print('⚠ REGRESSION DETECTED: time exceeded threshold.')
58
+ else:
59
+ print('✓ PASS: no regression detected.')
60
+ " 2>&1 || {
61
+ log_error "Comparison failed. Ensure both files are valid benchmark JSON."
62
+ exit 1
63
+ }