| name | description | argument-hint | agent | tools | ||||
|---|---|---|---|---|---|---|---|---|
perf-optimization |
Investigate and implement performance improvements in Microsoft.Data.SqlClient. |
<area or issue to optimize, e.g. "TdsParser allocation reduction" or issue number> |
agent |
|
Investigate and optimize performance for: "${input:area}".
Performance is critical for a database driver — every allocation, copy, and synchronization on the hot path affects all consumers. Follow this structured approach:
- If a GitHub issue is provided, fetch the issue details and any profiling data.
- Determine the code area to optimize in
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/. - Identify whether this is:
- Allocation reduction — reducing GC pressure on hot paths
- CPU optimization — reducing computation or branching
- I/O optimization — reducing network round-trips or buffer copies
- Lock contention — reducing synchronization overhead
- Caching — reusing computed results or objects
- Read the relevant source files to understand the current code path.
- Look for common performance anti-patterns:
new byte[]on hot paths → useArrayPool<T>.Shared- Excessive
stringconcatenation → useStringBuilderorstring.Create - Repeated object creation → use
static readonlycached instances - LINQ on hot paths → use manual loops
- Boxing of value types → use generic methods
- Unnecessary
asyncstate machines → useValueTaskor synchronous paths when result is available - Allocating
XmlWriterSettings,JsonSerializerOptions, etc. per-call → cache asstatic readonly new MemoryCacheEntryOptions()per-call → share or reuse instances- Reflection-based serialization → use source-generated serializers (
[JsonSerializable])
Before making changes, document:
- What is being optimized (specific class/method)
- Why it matters (frequency of execution, measured or estimated impact)
- How it will be optimized (which pattern applied)
- Risk assessment (could this change behavior? thread safety implications?)
| Pattern | When to Use | Example |
|---|---|---|
ArrayPool<T>.Shared |
Temporary byte/char buffers | TDS packet buffers |
Span<T> / Memory<T> |
Avoiding array copies | Parsing TDS tokens |
static readonly instances |
Immutable config objects | XmlWriterSettings, MemoryCacheEntryOptions |
ValueTask<T> |
Async methods that often complete synchronously | Read operations with buffered data |
| Source-generated serializers | JSON serialization | [JsonSerializable(typeof(T))] context |
string.Create |
Building strings with known length | Connection string formatting |
| Object pooling | Frequently allocated/disposed objects | StringBuilder pool |
| Lazy initialization | Expensive objects used conditionally | SSL stream setup |
- Make changes in
src/Microsoft.Data.SqlClient/src/. Do NOT modify legacy directories. - Ensure the optimization compiles for ALL target frameworks (
net462,net8.0,net9.0). - Use
#if NETfor APIs only available in .NET 8+ (e.g.,SearchValues<T>, newerSpanoverloads). - Preserve exact behavioral semantics — the optimization must be invisible to callers.
- Pay special attention to thread safety when caching or sharing instances.
- Verify all existing tests pass — performance changes must not alter behavior.
- Check for thread safety if shared state is introduced.
- If feasible, create a micro-benchmark to demonstrate the improvement.
- Review for regressions on other platforms (if using
#ifguards).
- If the optimization changes internal structure, add unit tests to verify the new code path.
- For cache/pool implementations, add tests for concurrent access.
- For
ArrayPoolusage, verify buffers are returned (no leaks).
- Use commit message format:
Perf | <description> (#issue) - Summarize the optimization with before/after analysis (allocations, throughput, or timing).
- Provide a checklist:
- No behavior changes (optimization is transparent)
- Thread-safe if shared state introduced
- Compiles for all target frameworks
- All existing tests pass
- Follows coding style (
policy/coding-style.md)