Skip to content

Per block gas accounting#185

Merged
tomusdrw merged 15 commits into
mainfrom
td-per-block-gas-accounting
Mar 3, 2026
Merged

Per block gas accounting#185
tomusdrw merged 15 commits into
mainfrom
td-per-block-gas-accounting

Conversation

@tomusdrw

@tomusdrw tomusdrw commented Feb 28, 2026

Copy link
Copy Markdown
Owner

Results on my machine:

  ┌─────────────────┬──────────┬─────────┐
  │     Config      │  Traces  │ vs Main │
  ├─────────────────┼──────────┼─────────┤
  │ Main (baseline) │ 4017.0ms │ —       │
  ├─────────────────┼──────────┼─────────┤
  │ Per-instruction │ 3396.2ms │ -15.4%  │
  ├─────────────────┼──────────┼─────────┤
  │ Block-gas       │ 3230.4ms │ -19.6%  │
  └─────────────────┴──────────┴─────────┘

The branch contains a bunch of other performance improvements as well:

  1. Conversion to static arrays.
  2. Bundling code & gasCost into single u32 (u8 + u24).

Some IDEAS for future optimisations:

  1. Minimize the number of lookups during interpreter loop by bundling information together (mask, basic blocks, code, gas cost, args parsers).
  2. Minimize iterations over the code (initial phase).
  3. Pre-compute instructions and arguments - go over the code only once, and constructStaticArray<u64> containing all required information in the hot loop - three entries contain an instruction, gas, block info and all arguments decoded. We are additionally going to need a StaticArray<u32> that will be a mapping of PC into indices in this new program array.

Resolves #183

@coderabbitai

coderabbitai Bot commented Feb 28, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds per-block gas accounting: it introduces a new useBlockGas flag in VM run options and API entrypoints, exposes an Interpreter.useBlockGas public field, computes Program.blockGasCosts during program construction, and changes the interpreter loop to deduct gas per basic block when the flag is enabled. CLI, benchmarking, and trace-replay code paths are updated to accept and propagate the flag.

Possibly related PRs

Suggested reviewers

  • mateuszsikora
  • DrEverr
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Per block gas accounting' directly and concisely describes the main change—introducing block-level gas accounting instead of per-instruction accounting across multiple API and interpreter files.
Linked Issues check ✅ Passed The PR resolves issue #183 (Per-block gas counter) by implementing block gas accounting throughout the codebase: adding useBlockGas flags to API functions [api-debugger, api-internal, api-utils], computing blockGasCosts in Program [program.ts], and integrating block gas into Interpreter execution logic [interpreter.ts].
Out of Scope Changes check ✅ Passed Most changes directly support per-block gas accounting. Bench/compare.ts refactoring and biome.jsonc expansion are minor supportive changes. Build.yml workflow simplification is a tangential improvement. All changes remain reasonably within the scope of implementing and benchmarking block gas accounting.
Description check ✅ Passed The PR description provides benchmark results, performance improvements achieved, and future optimization ideas directly related to the block-gas accounting implementation shown in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch td-per-block-gas-accounting

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bench/run.ts (1)

37-46: ⚠️ Potential issue | 🟡 Minor

Missing --block-gas option in help text.

The new --block-gas CLI option is not documented in the help output.

📝 Proposed fix to add help text
   console.log(`Usage: tsx bench/run.ts [options]
 
 Options:
   --traces <dir>      Directory with ecalli trace .log files
   --w3f <dir>         Directory with W3F test vector .json files
   --iterations <n>    Number of timed iterations (default: 5)
   --warmup <n>        Number of warmup iterations (default: 1)
   --output <file>     Write JSON results to file
+  --block-gas         Enable per-block gas accounting (default: false)
   -h, --help          Show this help`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bench/run.ts` around lines 37 - 46, The help text printed in bench/run.ts is
missing the new --block-gas CLI option; update the console.log usage block (the
multi-line string printed in run.ts) to include a new line documenting
"--block-gas <n>    Block gas limit to use for simulated blocks" (or similar
concise description) so the option appears in the displayed help alongside the
existing --traces, --w3f, --iterations, --warmup, and --output entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@bench/run.ts`:
- Around line 37-46: The help text printed in bench/run.ts is missing the new
--block-gas CLI option; update the console.log usage block (the multi-line
string printed in run.ts) to include a new line documenting "--block-gas <n>   
Block gas limit to use for simulated blocks" (or similar concise description) so
the option appears in the displayed help alongside the existing --traces, --w3f,
--iterations, --warmup, and --output entries.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 41e43f6 and e271b28.

📒 Files selected for processing (8)
  • assembly/api-debugger.ts
  • assembly/api-internal.ts
  • assembly/api-types.ts
  • assembly/api-utils.ts
  • assembly/interpreter.ts
  • assembly/program.ts
  • bench/run.ts
  • bin/src/trace-replay.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build.yml:
- Around line 78-79: When running the benchmark step that executes "npm run
bench:baseline" the current copy command "cp ./bench/baseline.json
../baseline.json" writes the file to the workspace root, but the later compare
step expects "../baseline.json" relative to the workspace root (i.e. one level
up); update the copy destination in the build.yml step that currently runs "cp
./bench/baseline.json ../baseline.json" so it writes the baseline to the parent
of the workspace (use "../../baseline.json" when still inside the "./baseline"
subdirectory) so the compare step that references "../baseline.json" will find
the file.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b5eb9eb and 20408cf.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bench/run.ts`:
- Around line 49-50: The code uses parseInt for CLI inputs (e.g., computing
ITERATIONS and WARMUP) which accepts partially numeric strings like "5abc" or
"3.7"; add explicit validation before parsing to reject non-integer strings (use
a strict integer regex like /^\d+$/) for values.iterations, values.warmup and
every other CLI numeric value parsed in this file (the same pattern around the
parseInt usage in the 53-62 block). If validation fails, surface a clear
error/exit early instead of calling parseInt; then call parseInt (or Number)
only on validated strings to compute ITERATIONS, WARMUP, and the other numeric
constants.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 20408cf and b4ec137.

📒 Files selected for processing (3)
  • bench/compare.ts
  • bench/run.ts
  • biome.jsonc

Comment thread bench/run.ts
@github-actions

github-actions Bot commented Mar 1, 2026

Copy link
Copy Markdown

Benchmark Results

✅ No significant changes

Metric Baseline Current Change
Trace total 7821.7ms 5724.8ms -2096.9ms (-26.8%)
All traces
Trace Baseline Current Change
trace-003 353.3ms 246.8ms -30.2%
trace-055 285.1ms 200.6ms -29.7%
trace-031 249.5ms 175.9ms -29.5%
trace-039 276.1ms 194.7ms -29.5%
trace-041 240.8ms 169.9ms -29.5%
trace-059 254.1ms 179.4ms -29.4%
trace-053 209.0ms 148.0ms -29.2%
trace-038 220.7ms 156.6ms -29.0%
trace-025 239.2ms 170.8ms -28.6%
trace-051 205.8ms 147.0ms -28.6%
trace-017 271.1ms 193.8ms -28.5%
trace-023 226.1ms 161.7ms -28.5%
trace-008 146.2ms 104.7ms -28.4%
trace-022 192.5ms 138.3ms -28.2%
trace-010 180.9ms 130.1ms -28.1%
trace-054 164.2ms 118.1ms -28.1%
trace-047 164.2ms 118.3ms -28.0%
trace-030 177.8ms 128.1ms -28.0%
trace-011 152.7ms 110.1ms -27.9%
trace-048 148.4ms 107.1ms -27.8%
trace-001 156.6ms 113.2ms -27.7%
trace-024 162.5ms 117.7ms -27.6%
trace-028 175.6ms 127.2ms -27.6%
trace-027 145.2ms 106.3ms -26.8%
trace-014 138.8ms 101.9ms -26.6%
trace-050 114.3ms 84.0ms -26.5%
trace-020 126.6ms 93.1ms -26.5%
trace-032 116.7ms 85.9ms -26.4%
trace-061 104.9ms 77.2ms -26.3%
trace-063 110.4ms 81.3ms -26.3%
trace-006 125.7ms 92.6ms -26.3%
trace-035 122.2ms 90.1ms -26.2%
trace-021 109.0ms 81.1ms -25.6%
trace-033 96.6ms 71.9ms -25.6%
trace-026 93.3ms 69.5ms -25.5%
trace-015 105.4ms 78.7ms -25.3%
trace-052 88.1ms 65.9ms -25.2%
trace-005 80.0ms 60.2ms -24.8%
trace-036 86.6ms 65.1ms -24.8%
trace-042 73.2ms 55.8ms -23.8%
trace-004 64.5ms 49.4ms -23.5%
trace-045 71.3ms 54.7ms -23.4%
trace-037 62.4ms 47.9ms -23.3%
trace-043 64.6ms 49.8ms -23.0%
trace-019 70.3ms 54.3ms -22.8%
trace-056 58.8ms 45.8ms -22.0%
trace-057 53.9ms 42.2ms -21.6%
trace-018 65.9ms 52.0ms -21.1%
trace-002 51.4ms 40.7ms -20.7%
trace-034 54.4ms 43.2ms -20.6%
trace-016 54.9ms 43.7ms -20.4%
trace-007 48.9ms 39.0ms -20.3%
trace-013 43.9ms 35.4ms -19.2%
trace-062 45.3ms 36.7ms -19.0%
trace-049 45.1ms 36.7ms -18.7%
trace-058 37.6ms 31.1ms -17.3%
trace-029 39.0ms 32.4ms -17.0%
trace-012 35.0ms 29.4ms -16.1%
trace-040 36.6ms 31.0ms -15.3%
trace-009 33.9ms 28.8ms -15.0%
trace-060 35.2ms 30.0ms -14.7%
trace-044 33.2ms 28.7ms -13.6%
trace-046 26.0ms 23.6ms -9.3%

@tomusdrw

tomusdrw commented Mar 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai create an issue with performance optimisations ideas from PR description and add relevant context and assessment.

@coderabbitai

coderabbitai Bot commented Mar 1, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the full PR description and details
gh pr view 185 --json title,body,url,number

Length of output: 1378


🏁 Script executed:

#!/bin/bash
# Create GitHub issue with performance optimization ideas
gh issue create \
  --title "Future Performance Optimization Ideas for Interpreter" \
  --assignee tomusdrw \
  --body "## Context

Following the performance improvements achieved in PR `#185`, this issue tracks additional optimization ideas for future implementation.

## Current Performance Improvements (PR `#185`)

Benchmark results on the author's machine show significant improvements:

- **Per-instruction gas accounting**: -15.4% vs Main baseline
- **Block-gas approach**: -19.6% vs Main baseline

PR `#185` implemented:
1. Conversion to static arrays
2. Bundling code & gasCost into single u32 (u8 + u24)

## Future Optimization Ideas

### 1. Bundle Information to Minimize Lookups
Minimize the number of lookups during the interpreter loop by bundling information together (mask, basic blocks, code, gas cost, args parsers).

**Assessment**: This would reduce memory access overhead during hot loop execution by consolidating related data structures.

### 2. Minimize Code Iterations
Minimize iterations over the code during the initial phase.

**Assessment**: Reducing passes over the bytecode during initialization would improve startup time and reduce preprocessing overhead.

### 3. Pre-compute Instructions and Arguments
Go over the code only once and construct \`StaticArray<u64>\` containing all required information for the hot loop. Each entry would contain:
- Instruction
- Gas cost
- Block info
- All decoded arguments

Additionally, create a \`StaticArray<u32>\` mapping PC (program counter) to indices in the new program array.

**Assessment**: This is the most ambitious optimization that could potentially eliminate runtime decoding overhead entirely. By pre-processing all instructions and arguments into a contiguous array, the hot loop would only need to:
- Index into the pre-computed array
- Execute the instruction with pre-decoded arguments
- Update the PC mapping

This could significantly reduce branching and memory access patterns in the critical execution path.

## Related

- PR `#185`: https://github.com/tomusdrw/anan-as/pull/185
- Resolves `#183`
- Requested by: `@tomusdrw`"

Length of output: 46


@tomusdrw I've created issue #187 with the future performance optimization ideas from PR #185.

The issue includes:

  • Context about the current performance improvements (-19.6% with Block-gas approach)
  • Already implemented optimizations (static arrays, bundled u32)
  • Three future optimization ideas with detailed assessments
  • Backlink to PR #185 and reference to #183

You can view it here: #187

@tomusdrw
tomusdrw merged commit c2b7f5a into main Mar 3, 2026
4 checks passed
@tomusdrw
tomusdrw deleted the td-per-block-gas-accounting branch March 3, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-block gas counter

1 participant