Agent SkillsJamieMason/syncpack › optimize-benchmarks

optimize-benchmarks

GitHub

针对 syncpack-specifier 的迭代性能优化技能。通过基准测试识别瓶颈,执行单次聚焦优化并验证测试,对比基线评估收益。若提升则更新基线继续,否则回滚或停止,旨在持续提升解析性能。

.claude/skills/optimize-benchmarks/SKILL.md JamieMason/syncpack

Trigger Scenarios

用户请求优化 syncpack-specifier 性能 需要迭代式基准测试与代码调优

Install

npx skills add JamieMason/syncpack --skill optimize-benchmarks -g -y
More Options

Non-standard path

npx skills add https://github.com/JamieMason/syncpack/tree/main/.claude/skills/optimize-benchmarks -g -y

Use without installing

npx skills use JamieMason/syncpack@optimize-benchmarks

指定 Agent (Claude Code)

npx skills add JamieMason/syncpack --skill optimize-benchmarks -a claude-code -g -y

安装 repo 全部 skill

npx skills add JamieMason/syncpack --all -g -y

预览 repo 内 skill

npx skills add JamieMason/syncpack --list

SKILL.md

Frontmatter
{
    "name": "optimize-benchmarks",
    "description": "Iterative performance optimisation loop for syncpack-specifier. Runs benchmarks, identifies bottlenecks, applies optimisations, verifies tests pass and benchmarks improve, then repeats."
}

Optimize Benchmarks

Iterative loop: benchmark, optimise, test, verify improvement, repeat.

Workflow

1. Baseline

cargo bench -p syncpack-specifier -- --save-baseline before 2>&1 | tail -40

Save the output. Identify which variants are slowest.

2. Identify Bottleneck

From the full baseline, focus on the slowest benchmarks first.

Priority order for specifier parsing:

  1. Specifier::create — the main parse function, called for every version string
  2. parser::is_range — checks 12 regexes sequentially
  3. parser::is_exact — checks 4 regexes sequentially
  4. parser::is_complex_range — splits, collects, iterates
  5. Individual regex matches in regexes.rs

3. Apply ONE Optimisation

Make a single, focused change. Do NOT bundle multiple optimisations — each must be independently measurable.

4. Verify Tests Pass

cargo test -p syncpack-specifier 2>&1 | tail -5

If tests fail, fix or revert. Never proceed with failing tests.

5. Benchmark Against Baseline

cargo bench -p syncpack-specifier -- --baseline before 2>&1 | tail -40

Look for [-XX.XXX% ...] (improvement) or [+XX.XXX% ...] (regression).

6. Evaluate

  • Improved: Report the gains. Update baseline: cargo bench -p syncpack-specifier -- --save-baseline before. Continue to step 2.
  • No change: Revert and try a different approach.
  • Regressed: Revert immediately.

7. Repeat

Go to step 2. Stop when:

  • User says stop
  • No bottlenecks remain
  • Gains are <1% across all benchmarks

Known Optimisation Opportunities

High Impact

Replace regex with char-based parsing in parser.rs / regexes.rs

Most regexes in regexes.rs match simple patterns like ^[0-9]+\.[0-9]+\.[0-9]+$ (exact semver). These can be replaced with byte/char iteration:

// Instead of regex EXACT: r"^[0-9]+\.[0-9]+\.[0-9]+$"
fn is_exact_version(s: &str) -> bool {
  let mut dots = 0;
  let bytes = s.as_bytes();
  if bytes.is_empty() { return false; }
  for &b in bytes {
    match b {
      b'0'..=b'9' => {},
      b'.' => dots += 1,
      _ => return false,
    }
  }
  dots == 2
}

Regex is_match() has overhead even for simple patterns: engine setup, capture group allocation. Char-based parsing for these patterns is 5-20x faster.

Reduce sequential regex attempts in parser::is_range

is_range tries 12 regexes. Instead, match on first char(s) to dispatch:

fn is_range(s: &str) -> bool {
  match s.as_bytes().first() {
    Some(b'^') => is_semver_after(s, 1) || is_semver_tag_after(s, 1),
    Some(b'~') => is_semver_after(s, 1) || is_semver_tag_after(s, 1),
    Some(b'>') => { /* check >= vs > then validate remainder */ },
    Some(b'<') => { /* check <= vs < then validate remainder */ },
    _ => false,
  }
}

Consolidate related regex patterns

Many regexes are pairs: EXACT + EXACT_TAG, CARET + CARET_TAG, etc. Merge each pair into one function that handles both cases:

fn is_exact(s: &str) -> bool {
  // Parse digits.digits.digits, then optionally -tag
  let rest = parse_semver_triple(s)?;
  rest.is_empty() || rest.starts_with('-')
}

Medium Impact

Replace lazy_static with std::sync::OnceLock

lazy_static uses an extra indirection layer. OnceLock (stable since Rust 1.80) is zero-cost after init:

use std::sync::OnceLock;

fn exact_regex() -> &'static Regex {
  static RE: OnceLock<Regex> = OnceLock::new();
  RE.get_or_init(|| Regex::new(r"^[0-9]+\.[0-9]+\.[0-9]+$").unwrap())
}

But if regex is being replaced with char-based parsing, this becomes irrelevant.

Reorder checks in Specifier::create by frequency

In a typical monorepo, most specifiers are ^x.y.z (range) or x.y.z (exact). The current order already checks exact first, then range — good. But is_exact tries 4 regex patterns. A single fast char check can short-circuit:

// Fast path: first char is digit → likely exact or major or minor
// Fast path: first char is ^ or ~ → likely range

Avoid String allocation in strip_semver_range

strip_semver_range returns &str (already good), but callers like Range::create then .to_string() the result. Consider whether the allocation can be deferred.

Low Impact

  • Replace HashMap in caches with FxHashMap (faster hashing for short strings)
  • Use SmallString or stack-allocated strings for short specifiers
  • Pre-size cache HashMap with expected capacity

Architecture Notes

Key files in crates/syncpack-specifier/src/:

File Role
lib.rs Specifier enum, create() dispatch, caches
parser.rs is_exact(), is_range(), etc. — classification functions
regexes.rs All lazy_static regex patterns
exact.rs, range.rs, etc. Variant constructors calling node_semver
semver_range.rs SemverRange enum, parse()

The hot path is: Specifier::create()parser::is_*()regexes::* → variant ::create()node_semver parsing.

Optimising the parser::is_* layer gives the biggest wins because it runs for every specifier, and most of the time most checks return false (only one branch matches).

Rules

  • ONE change per iteration
  • Always verify tests pass before benchmarking
  • Always compare against baseline
  • Report numbers: before → after (% change)
  • Revert regressions immediately
  • Don't optimise what doesn't show up in benchmarks
  • Use fast iteration ("batch" filter) during the loop, full suite only at start and end

Version History

  • 15.3.2 Current 2026-07-06 19:59

Same Skill Collection

.claude/skills/add-feature/SKILL.md
.claude/skills/document-code/SKILL.md
.claude/skills/fix-bug/SKILL.md
.claude/skills/front-loading/SKILL.md
.claude/skills/review-docs/SKILL.md
.claude/skills/search-code/SKILL.md
.claude/skills/signal-over-noise/SKILL.md
.claude/skills/testing-gaps/SKILL.md
.claude/skills/write-code/SKILL.md
.claude/skills/write-tests/SKILL.md

Metadata

Files
0
Version
15.3.2
Hash
b999709c
Indexed
2026-07-06 19:59

- 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-06 19:37
浙ICP备14020137号-1 $방문자$