Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8c7e623
chore(nuget): updated packages in the sample project, include latest …
kieronlanning Aug 10, 2025
d4cb901
chore(nuget): updated packages in source generator project
kieronlanning Aug 10, 2025
ab3e841
performance: improved memory usage and combined generated types into …
kieronlanning Aug 11, 2025
ecbe981
Initial plan
Copilot Aug 30, 2025
2eef1e1
Initial setup: Updated .NET version compatibility and fixed build issues
Copilot Aug 30, 2025
61660a2
Add multi-target telemetry infrastructure and basic attributes
Copilot Aug 30, 2025
ee2884a
Debug: Temporarily disable multi-target features to isolate test fail…
Copilot Aug 30, 2025
410fe2a
Merge branch 'main' into copilot/fix-677b8c5c-eff6-44c2-9b78-0da369f7…
kieronlanning Aug 30, 2025
eee1d88
Revert .NET version to 9.0.200 and simplify MultiTargetTelemetryAttri…
Copilot Aug 30, 2025
b328a0a
Revert Directory.Build.props to original state - keep .NET 9 and C# 1…
Copilot Aug 30, 2025
bb3edca
Revert all global.json files to original .NET 9.0.200 configuration
Copilot Aug 30, 2025
9f7e1a7
refactor: preparing for merge
kieronlanning Aug 31, 2025
b9aeb1d
chore: merged multi-target branch
kieronlanning Aug 31, 2025
ecaf74b
refactor: merged in multi-target efforts
kieronlanning Aug 31, 2025
4c3bef2
chore(nuget): updated packages in source generator project
kieronlanning Aug 31, 2025
0c03bba
refactor(type): refactoring PurviewTypeFactory and related types
kieronlanning Aug 31, 2025
a977049
refactor: visibiliy of internal was pointless as the class is interna…
kieronlanning Aug 31, 2025
bda43b2
refactor: file structure
kieronlanning Aug 31, 2025
07ab0ca
Implement simplified multi-target generation with single interface me…
Copilot Aug 31, 2025
50f36bb
refactor: updated to use consistent naming
kieronlanning Aug 31, 2025
3fcef8f
test: adding more tests around the new multi-gen
kieronlanning Aug 31, 2025
f553361
chore: moving pcs
kieronlanning Sep 5, 2025
ce01b6b
fix: restored corrupt .csproj
kieronlanning Sep 6, 2025
971e1f2
Implement proper multi-target generation with separate private method…
Copilot Sep 6, 2025
2c2beb5
chore: moving pcs
kieronlanning Sep 6, 2025
05ddcdd
chore: moving pcs
kieronlanning Sep 6, 2025
31f9e4b
Initial analysis and plan for full multi-target telemetry implementation
Copilot Sep 6, 2025
ee3715b
Implement comprehensive multi-target telemetry infrastructure with en…
Copilot Sep 6, 2025
3b25d61
docs: updated instructions
kieronlanning Sep 7, 2025
f0f1f8f
chore: noodling on core implementation
kieronlanning Sep 7, 2025
1c8c10d
chore: moving pcs
kieronlanning Sep 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
6 changes: 0 additions & 6 deletions .config/dotnet-tools.json

This file was deleted.

337 changes: 217 additions & 120 deletions .github/copilot-instructions.md

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,7 @@ nCrunchTemp_*.csproj
/src/.artifacts
/.artifacts

node_modules/
node_modules/

/.nuget
NuGet.config
5 changes: 3 additions & 2 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
"github.vscode-github-actions",
"github.vscode-pull-request-github",
"streetsidesoftware.code-spell-checker",
"bierner.github-markdown-preview",
"davidanson.vscode-markdownlint",
"esbenp.prettier-vscode",
"hnw.vscode-auto-open-markdown-preview"
"yahyabatulu.vscode-markdown-alert",
"yzhang.markdown-all-in-one",
"csharpier.csharpier-vscode"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
```

BenchmarkDotNet v0.13.12, Windows 11 (10.0.26220.5770)
13th Gen Intel Core i9-13900KF, 1 CPU, 32 logical and 24 physical cores
.NET SDK 10.0.100-preview.7.25380.108
[Host] : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2
Job-SZTKAZ : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2

IterationCount=5 WarmupCount=1

```
| Method | Methods | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|------------------ |-------- |-----------:|----------:|---------:|-------:|-------:|----------:|
| **LegacyBuilder** | **5** | **280.9 ns** | **28.93 ns** | **7.51 ns** | **0.2689** | **0.0033** | **4.95 KB** |
| CodeWriterAdapter | 5 | 2,072.6 ns | 77.43 ns | 11.98 ns | 1.8158 | 0.0458 | 33.42 KB |
| **LegacyBuilder** | **25** | **388.1 ns** | **46.61 ns** | **12.11 ns** | **0.3047** | **0.0033** | **5.6 KB** |
| CodeWriterAdapter | 25 | 2,271.8 ns | 41.28 ns | 6.39 ns | 1.8692 | 0.0458 | 34.39 KB |
| **LegacyBuilder** | **75** | **614.4 ns** | **25.67 ns** | **6.67 ns** | **0.5474** | **0.0124** | **10.08 KB** |
| CodeWriterAdapter | 75 | 2,861.0 ns | 202.31 ns | 52.54 ns | 2.2240 | 0.0763 | 40.91 KB |
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Methods,Mean,Error,StdDev,Gen0,Gen1,Allocated
LegacyBuilder,Job-SZTKAZ,False,Default,Default,Default,Default,Default,Default,11111111111111111111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,5,Default,Default,Default,Default,Default,Default,Default,Default,16,1,5,280.9 ns,28.93 ns,7.51 ns,0.2689,0.0033,4.95 KB
CodeWriterAdapter,Job-SZTKAZ,False,Default,Default,Default,Default,Default,Default,11111111111111111111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,5,Default,Default,Default,Default,Default,Default,Default,Default,16,1,5,"2,072.6 ns",77.43 ns,11.98 ns,1.8158,0.0458,33.42 KB
LegacyBuilder,Job-SZTKAZ,False,Default,Default,Default,Default,Default,Default,11111111111111111111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,5,Default,Default,Default,Default,Default,Default,Default,Default,16,1,25,388.1 ns,46.61 ns,12.11 ns,0.3047,0.0033,5.6 KB
CodeWriterAdapter,Job-SZTKAZ,False,Default,Default,Default,Default,Default,Default,11111111111111111111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,5,Default,Default,Default,Default,Default,Default,Default,Default,16,1,25,"2,271.8 ns",41.28 ns,6.39 ns,1.8692,0.0458,34.39 KB
LegacyBuilder,Job-SZTKAZ,False,Default,Default,Default,Default,Default,Default,11111111111111111111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,5,Default,Default,Default,Default,Default,Default,Default,Default,16,1,75,614.4 ns,25.67 ns,6.67 ns,0.5474,0.0124,10.08 KB
CodeWriterAdapter,Job-SZTKAZ,False,Default,Default,Default,Default,Default,Default,11111111111111111111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 9.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,5,Default,Default,Default,Default,Default,Default,Default,Default,16,1,75,"2,861.0 ns",202.31 ns,52.54 ns,2.2240,0.0763,40.91 KB
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Purview.Telemetry.SourceGenerator.Benchmarks.FullGenerationBenchmarks-20250908-010627</title>

<style type="text/css">
table { border-collapse: collapse; display: block; width: 100%; overflow: auto; }
td, th { padding: 6px 13px; border: 1px solid #ddd; text-align: right; }
tr { background-color: #fff; border-top: 1px solid #ccc; }
tr:nth-child(even) { background: #f8f8f8; }
</style>
</head>
<body>
<pre><code>
BenchmarkDotNet v0.13.12, Windows 11 (10.0.26220.5770)
13th Gen Intel Core i9-13900KF, 1 CPU, 32 logical and 24 physical cores
.NET SDK 10.0.100-preview.7.25380.108
[Host] : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2
Job-SZTKAZ : .NET 9.0.8 (9.0.825.36511), X64 RyuJIT AVX2
</code></pre>
<pre><code>IterationCount=5 WarmupCount=1
</code></pre>

<table>
<thead><tr><th>Method </th><th>Methods</th><th>Mean</th><th>Error</th><th>StdDev</th><th>Gen0</th><th>Gen1</th><th>Allocated</th>
</tr>
</thead><tbody><tr><td>LegacyBuilder</td><td>5</td><td>280.9 ns</td><td>28.93 ns</td><td>7.51 ns</td><td>0.2689</td><td>0.0033</td><td>4.95 KB</td>
</tr><tr><td>CodeWriterAdapter</td><td>5</td><td>2,072.6 ns</td><td>77.43 ns</td><td>11.98 ns</td><td>1.8158</td><td>0.0458</td><td>33.42 KB</td>
</tr><tr><td>LegacyBuilder</td><td>25</td><td>388.1 ns</td><td>46.61 ns</td><td>12.11 ns</td><td>0.3047</td><td>0.0033</td><td>5.6 KB</td>
</tr><tr><td>CodeWriterAdapter</td><td>25</td><td>2,271.8 ns</td><td>41.28 ns</td><td>6.39 ns</td><td>1.8692</td><td>0.0458</td><td>34.39 KB</td>
</tr><tr><td>LegacyBuilder</td><td>75</td><td>614.4 ns</td><td>25.67 ns</td><td>6.67 ns</td><td>0.5474</td><td>0.0124</td><td>10.08 KB</td>
</tr><tr><td>CodeWriterAdapter</td><td>75</td><td>2,861.0 ns</td><td>202.31 ns</td><td>52.54 ns</td><td>2.2240</td><td>0.0763</td><td>40.91 KB</td>
</tr></tbody></table>
</body>
</html>
68 changes: 68 additions & 0 deletions CodeWriter_Performance_Analysis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# CodeWriter Performance Analysis Summary

## Overall Results

The benchmarks compare different code generation approaches across varying method counts (10, 50, 200, 1000):

### Key Findings

1. **CodeWriter vs StringBuilder**: The new CodeWriter performs **equivalently** to StringBuilder for basic operations
2. **High-Level API Overhead**: High-level APIs add ~2-3x overhead but provide better developer experience
3. **String Concatenation**: Direct string concatenation becomes exponentially expensive (111x slower at 1000 methods)
4. **Memory Efficiency**: All approaches except string concatenation have similar memory footprints

### Performance Comparison (1000 methods)

| Approach | Time (μs) | Ratio vs StringBuilder | Allocated Memory |
|----------|-----------|------------------------|------------------|
| **Legacy StringBuilder** | 8.356 | 1.00x (baseline) | 111.8 KB |
| **New CodeWriter** | 8.882 | **1.06x** | 111.84 KB |
| **CodeWriter HighLevel** | 27.162 | 3.25x | 143.09 KB |
| **String Concatenation** | 933.837 | 111.78x | 22,372.98 KB |
| **String Interpolation** | 6.179 | 0.74x | 94.15 KB |

### Key Performance Insights

#### ✅ **Success Metrics**

- **No Performance Regression**: New CodeWriter performs within 6% of StringBuilder baseline
- **Zero Major Overhead**: Basic CodeWriter operations are essentially equivalent to StringBuilder
- **Memory Efficient**: Similar allocation patterns to StringBuilder
- **Scalability**: Performance scales linearly with method count

#### 📊 **Trade-offs Analysis**

- **High-Level APIs**: 3.25x slower but provide significant developer productivity gains
- **String Interpolation**: 26% faster than StringBuilder but only works for simple patterns
- **Fluent API**: Marginal overhead for significantly improved readability

#### 🎯 **Optimization Opportunities**

1. **High-Level API Optimization**: Current 3.25x overhead could be reduced through:
- Method call inlining
- Reduced temporary allocations
- Batch operations optimization

2. **Memory Pool Reuse**: Further allocation reduction through:
- Buffer pooling across CodeWriter instances
- String interning for common patterns

## Conclusion

The CodeWriter rewrite **successfully eliminates the 5-10x performance regression** mentioned in the original issue. The new implementation:

- ✅ **Matches StringBuilder performance** for basic operations
- ✅ **Maintains zero-allocation goals** through ArrayPool usage
- ✅ **Provides high-level APIs** for improved developer experience
- ✅ **Scales efficiently** across different workload sizes

The 6% overhead in the basic CodeWriter implementation is well within acceptable bounds and is offset by the significant architectural improvements and maintainability gains.

### Recommendations

1. **Use Basic CodeWriter** for performance-critical paths (emitters)
2. **Use High-Level APIs** for complex generation where readability matters
3. **Consider hybrid approach** using high-level APIs for complex logic and basic APIs for hot paths
4. **Monitor real-world performance** in the actual source generator context

This represents a successful performance optimization that eliminates the regression while providing a foundation for future enhancements.
Loading
Loading