This skill should be used when the user asks to "review performance", "optimize F#", ".NET performance", "performance audit", "find bottlenecks", "improve efficiency", or wants analysis of F# code performance focusing on .NET runtime patterns, async architecture, and data structure choices.
Install
npx skillscat add bromanko/llm-agents/fsharp-performance-review Install via the SkillsCat registry.
SKILL.md
F# Performance Review
Action required: Run /review fsharp performance to start an interactive performance review. Do not perform the review manually.
Analyze F# code for performance issues, focusing on .NET runtime patterns, allocation behavior, async architecture, and efficient data handling.
Scope Determination
First, determine what code to review:
- If the user specifies files/directories: Review those paths
- If no scope specified: Review working changes
- Check for
.jjdirectory first, usejj diffif present - Otherwise use
git diffto identify changed.fsand.fsxfiles - If no changes, ask the user what to review
- Check for
Review Process
- Identify hot paths: Find frequently executed code (request handlers, loops, recursive functions)
- Analyze data flow: Track how data moves through the system
- Check .NET-specific patterns below
- Review async architecture if applicable
- Output findings in the standard format
Performance Checklist
Allocation & GC Pressure
- Avoid unnecessary boxing (e.g., DU cases with value types, generic constraints)
- Use
[<Struct>]on small discriminated unions and records where appropriate - Avoid excessive intermediate collections in pipelines (consider
Seqor manual loops) - Use
ValueOption/ValueTaskin hot paths where allocation matters StringBuilderused instead of repeated string concatenation- Aware of closure allocations in lambdas capturing local variables
Collection Choices
List(F# immutable list) used for sequential access and pattern matchingArrayused for random access, interop, and performance-critical codeSeqused for lazy evaluation and large data streamsMap/Setused for immutable key-based lookupsDictionary/HashSetused in hot paths where mutability is acceptable- Avoid
List.nth(O(n)) for random access — use arrays ResizeArraypreferred over repeatedList.appendfor building collections
Async & Task Patterns
task { }CE preferred overasync { }for .NET interop and performance- Avoid
Async.RunSynchronouslyblocking on async code Task.WhenAllused for concurrent independent operations- No unnecessary
async/taskwrapping of synchronous code CancellationTokenthreaded through for cancellable operations- Avoid
Async.Startfire-and-forget without error handling
Recursion & Iteration
- Tail-call optimization used (accumulator pattern)
Array.ParallelorPSeqfor CPU-bound parallel work- Recursive functions use
[<TailCall>]attribute where supported - Loops preferred over recursion in performance-critical code (when readability allows)
Seq.cacheused when a sequence is enumerated multiple times
String Handling
String.ConcatorStringBuilderover+in loopsStringComparison.OrdinalIgnoreCasefor case-insensitive comparisonsReadOnlySpan<char>/Spanfor parsing-heavy code- Interpolated strings preferred over
sprintffor simple formatting (less allocation) - Avoid repeated regex compilation — use
[<Literal>]patterns or compiled regex
Computation Expressions
- Custom CEs don't allocate excessively in
Bind/Return ResultCE chains don't build unnecessary intermediate state- Consider inlining short CE builders in hot paths
Interop & Marshalling
- P/Invoke signatures correct and efficient
[<Struct>]used for interop structs to avoid heap allocationReadOnlySpan/Memoryused for buffer operations- Minimize managed/unmanaged transitions
Caching & Memoization
- Pure functions with expensive computation are memoized where appropriate
ConcurrentDictionaryorLazy<T>for thread-safe caching- Cache eviction considered for unbounded caches
- Avoid memoizing functions with large input spaces
I/O & External Calls
- External calls don't block critical paths
- Batch operations where possible
- Connection pooling for databases/services
- Timeouts prevent hanging on slow externals
- Streaming used for large data (avoid loading entire datasets into memory)
Output Format
Present findings as:
## Findings
### [SEVERITY] Issue Title
**File:** `path/to/File.fs:LINE`
**Category:** performance
**Issue:** Description of the performance concern and its impact.
**Suggestion:** How to optimize, with code example if helpful.
**Effort:** trivial|small|medium|large
---Use severity indicators:
- HIGH: Significant bottleneck, unbounded growth, blocking issues
- MEDIUM: Suboptimal patterns, unnecessary overhead
- LOW: Minor optimizations, micro-improvements
Summary
After all findings, provide:
- Total count by severity
- Top bottlenecks to address
- Hot paths identified
- Architecture recommendations (if applicable)
- Overall performance assessment (1-2 sentences)