
Sf Debug
Benchmark Apex code on Salesforce with warm-up iterations and side-by-side comparisons before you ship slow triggers or batch jobs.
Overview
sf-debug is an agent skill most often used in Ship (also Build backend, Operate iterate) that teaches reliable Salesforce Apex benchmarking with warm-up iterations and side-by-side performance comparisons.
Install
npx skills add https://github.com/jaganpro/sf-skills --skill sf-debugWhat is this skill?
- Dan Appleman–style Apex benchmarking template for Anonymous Apex runs
- Warm-up phase plus multiple iterations for statistically stable timings
- Side-by-side BenchmarkComparison class with automatic winner determination
- Quick single-operation loop with per-iteration millisecond reporting
- Copy-paste blocks for 10,000-iteration default workloads
- 10,000 default iterations in comparison benchmark template
- Warm-up phase plus multiple iterations in BenchmarkComparison pattern
Adoption & trust: 1.3k installs on skills.sh; 418 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You cannot tell whether your Apex refactor actually improved CPU time because one-off debug logs and tiny test runs lie about governor-limit behavior.
Who is it for?
Salesforce solo builders comparing two Apex implementations before a release or after a slowdown report.
Skip if: Teams that only need functional debugging without timing data, or non-Salesforce JVM/Java benchmarking outside Apex.
When should I use this skill?
Salesforce Apex feels slow, governor limits fail in bulk, or you need to prove one implementation beats another before deploy.
What do I get? / Deliverables
You get repeatable Anonymous Apex benchmarks with warm-up and iteration counts so you can pick the faster Apex pattern before deploying or reopening a performance incident.
- Timed benchmark snippet
- Side-by-side comparison run with reported winner
- Per-iteration millisecond metrics
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Performance debugging belongs on the Ship shelf because it gates release readiness for governor-limit-sensitive Apex, even though you often run benchmarks while still building features. Perf is the canonical subphase for timing regressions, JIT warm-up methodology, and winner/loser comparisons—not one-off log parsing in Operate.
Where it fits
Compare string concatenation versus StringBuilder in a hot loop before merging a trigger change.
Run 10,000-iteration benchmarks with warm-up before promoting a batch class to production.
Replay BenchmarkComparison in a full sandbox copy after users report intermittent CPU timeouts.
How it compares
Use structured Anonymous Apex benchmarking instead of guessing performance from a single test class run or ad-hoc System.debug timing.
Common Questions / FAQ
Who is sf-debug for?
Indie and solo Salesforce developers shipping Apex triggers, services, or batch jobs who need defensible performance numbers before merge or deploy.
When should I use sf-debug?
During Ship perf hardening when CPU or row limits are tight, while Build backend refactors change hot loops, and during Operate iterate when production slowness needs a sandbox replay with 10,000-iteration comparisons.
Is sf-debug safe to install?
Review the Security Audits panel on this Prism page before installing; benchmark snippets execute in your org and should run only in sandboxes with data you are allowed to stress-test.
SKILL.md
READMESKILL.md - Sf Debug
/** * Apex Benchmarking Template * * Reliable performance testing using Dan Appleman's technique from * "Advanced Apex Programming". Run in Anonymous Apex for consistent results. * * Features: * - Warm-up phase to normalize JIT compilation * - Multiple iterations for statistical accuracy * - Side-by-side comparison of two approaches * - Automatic winner determination * * @see https://www.jamessimone.net/blog/joys-of-apex/benchmarking-matters/ * @see https://www.advancedapex.com/ */ // ═══════════════════════════════════════════════════════════════════════════ // SIMPLE BENCHMARK (Copy into Anonymous Apex) // ═══════════════════════════════════════════════════════════════════════════ // Quick single-operation benchmark Long startTime = System.currentTimeMillis(); for (Integer i = 0; i < 10000; i++) { // Your operation here String s = 'test'.toUpperCase(); } Long duration = System.currentTimeMillis() - startTime; System.debug('Duration: ' + duration + 'ms'); System.debug('Per iteration: ' + (duration / 10000.0) + 'ms'); // ═══════════════════════════════════════════════════════════════════════════ // COMPARISON BENCHMARK CLASS // ═══════════════════════════════════════════════════════════════════════════ /** * Compare two implementations side-by-side * * Usage in Anonymous Apex: * BenchmarkComparison.run(); */ public class BenchmarkComparison { private static final Integer ITERATIONS = 10000; private static final Integer WARMUP_ITERATIONS = 100; public static void run() { System.debug('═══════════════════════════════════════════════════════'); System.debug('BENCHMARK: [Description Here]'); System.debug('Iterations: ' + ITERATIONS); System.debug('═══════════════════════════════════════════════════════'); // Warm-up phase (normalizes JIT compilation effects) System.debug('\n🔥 Warm-up phase...'); for (Integer i = 0; i < WARMUP_ITERATIONS; i++) { methodA(); methodB(); } System.debug(' Warm-up complete'); // Benchmark Method A System.debug('\n📊 Running Method A...'); Long startA = System.currentTimeMillis(); for (Integer i = 0; i < ITERATIONS; i++) { methodA(); } Long durationA = System.currentTimeMillis() - startA; // Benchmark Method B System.debug('📊 Running Method B...'); Long startB = System.currentTimeMillis(); for (Integer i = 0; i < ITERATIONS; i++) { methodB(); } Long durationB = System.currentTimeMillis() - startB; // Results System.debug('\n═══════════════════════════════════════════════════════'); System.debug('RESULTS'); System.debug('═══════════════════════════════════════════════════════'); System.debug('Method A: ' + durationA + 'ms (' + (durationA / (Decimal)ITERATIONS) + 'ms per iteration)'); System.debug('Method B: ' + durationB + 'ms (' + (durationB / (Decimal)ITERATIONS) + 'ms per iteration)'); System.debug('───────────────────────────────────────────────────────'); Long difference = Math.abs(durationA - durationB); String winner = durationA < durationB ? 'Method A' : 'Method B'; Decimal improvement = durationA < durationB ? (durationB / (Decimal)durationA) : (durationA / (Decimal)durationB); System.debug('🏆 Winner: ' + winner); System.debug(' Difference: ' + difference + 'ms'); System.debug(' Improvement: ' + improvement.setScale(1) + 'x faster'); // Governor limits status System.debug('\n📈 Governor Limits Used:'); System.debug(' CPU Time: ' + Limits.getCpuTime() + '/' + Limits.getLimitCpuTime() + 'ms'); System.debug(' Heap Size: ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize() + ' bytes'); } // ═══════════════════════════════════════════════════════════