cljr-performance

Dangercoder's avatarfrom Dangercoder

Optimize Cljr compiler and runtime performance. Use when optimizing emitter output, runtime collections, REPL evaluation, or leveraging .NET 10/C# 14 features. Covers Span<T>, FrozenDictionary, AggressiveInlining, benchmarking, and allocation reduction strategies.

⭐0stars🔀0forks📁View on GitHub🕐Updated Dec 7, 2025

When & Why to Use This Skill

This Claude skill provides expert guidance on optimizing the Cljr compiler and .NET runtime performance. It focuses on leveraging cutting-edge .NET 10 and C# 14 features—such as Span<T>, FrozenDictionary, and AggressiveInlining—to minimize memory allocations and maximize execution speed. It is designed to help developers refine emitter output, enhance runtime collection efficiency, and implement systematic benchmarking workflows to ensure high-performance Clojure-to-.NET compilation.

Use Cases

  • Compiler Emitter Optimization: Enhancing C# code generation logic to produce high-performance output tailored for the .NET 10 runtime environment.
  • Memory Allocation Reduction: Implementing zero-copy patterns with Span<T> and reusable buffers via ArrayPool to significantly decrease Garbage Collection pressure.
  • High-Performance Data Structures: Optimizing persistent collections using SIMD-accelerated HAMT and FrozenDictionary for ultra-fast, read-heavy lookups.
  • Systematic Benchmarking: Utilizing BenchmarkDotNet to quantify performance improvements, identify hot paths, and prevent regressions in the Cljr runtime.
  • Modernization with C# 14: Integrating preview features like implicit span conversions and AVX10.2 intrinsics for low-level hardware acceleration and cleaner API design.
namecljr-performance
descriptionOptimize Cljr compiler and runtime performance. Use when optimizing emitter output, runtime collections, REPL evaluation, or leveraging .NET 10/C# 14 features. Covers Span<T>, FrozenDictionary, AggressiveInlining, benchmarking, and allocation reduction strategies.

Cljr Performance Optimization

This skill guides performance optimization for the Cljr Clojure-to-.NET compiler, targeting .NET 10 with C# 14 preview features.

When to use this skill

  • Optimizing emitter-generated C# code
  • Improving runtime collection performance
  • Reducing memory allocations
  • Leveraging .NET 10 / C# 14 performance features
  • Writing or analyzing benchmarks
  • Optimizing REPL evaluation performance

Project Performance Profile

Target Framework

  • Runtime: .NET 10 (LTS)
  • Language: C# 14 preview (Runtime, CLI, REPL) / C# 12 (Compiler, SourceGenerator)

Existing Optimizations

Optimization Status Location
Span<T> / ReadOnlySpan<T> ✓ PersistentVector
FrozenDictionary ✓ Protocol, MethodImplCache
[AggressiveInlining] ✓ Hot paths throughout
Symbol/Keyword interning ✓ Symbol.cs, Keyword.cs
HAMT with SIMD PopCount ✓ PersistentHashMap
32-way trie ✓ PersistentVector
Transient collections ✓ Vector, HashMap batch ops
Method dispatch caching ✓ MultiFn, Protocol
BenchmarkDotNet suite ✓ tests/Cljr.Benchmarks/

Opportunities for Further Optimization

Optimization Status Potential Use
stackalloc ✗ Small temp arrays in hot paths
ArrayPool<T> ✗ Reusable buffer arrays
SearchValues<T> ✗ Character/byte searching
CompositeFormat ✗ String formatting
C# 14 implicit span conversions ✗ Cleaner span APIs
AVX10.2 intrinsics ✗ SIMD operations

Performance Optimization Workflow

Step 1: Measure First

Never optimize without benchmarks. Run existing benchmarks:

cd tests/Cljr.Benchmarks
dotnet run -c Release -- --filter "*"

Or specific benchmarks:

dotnet run -c Release -- --filter "VectorBenchmarks"
dotnet run -c Release -- --filter "*Conj*"

Step 2: Identify Hot Paths

Use profiling or benchmark results to identify:

  • High-frequency operations
  • Allocation-heavy code paths
  • Cache miss patterns

Step 3: Apply Optimizations

See reference files for specific patterns:

Step 4: Verify Improvement

Re-run benchmarks and compare:

dotnet run -c Release -- --filter "YourBenchmark" --runtimes net10.0

Quick Reference: Key Optimizations

AggressiveInlining

For small, frequently-called methods:

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T GetValue() => _value;

Span for Zero-Copy

// Instead of creating arrays
public ReadOnlySpan<object?> ArrayFor(int i) => _tail.AsSpan();

// Span-based construction (already in PersistentVector)
public static PersistentVector Create(ReadOnlySpan<object?> items)

FrozenDictionary for Read-Heavy Lookups

using System.Collections.Frozen;

// Mutable during construction
private readonly ConcurrentDictionary<Type, Cache> _impls = new();
// Frozen for fast reads
private volatile FrozenDictionary<Type, Cache>? _frozen;

public void Freeze() => _frozen = _impls.ToFrozenDictionary();

Symbol/Keyword Interning

Already implemented - ensures reference equality:

// Good: reference equality after interning
if (ReferenceEquals(sym1, sym2)) { ... }

// Avoid: value equality is slower
if (sym1.Equals(sym2)) { ... }

Transients for Batch Operations

// Slow: O(n²) allocations
var vec = PersistentVector.Empty;
foreach (var item in items)
    vec = vec.Conj(item);

// Fast: O(n) with transient
var transient = PersistentVector.Empty.AsTransient();
foreach (var item in items)
    transient.ConjBang(item);
return transient.Persistent();

Key Files

Area Files
Runtime Collections src/Cljr.Runtime/Collections/PersistentVector.cs, PersistentHashMap.cs
Protocol Dispatch src/Cljr.Runtime/Protocol.cs, MultiFn.cs
Symbol Interning src/Cljr.Runtime/Symbol.cs, Keyword.cs
Emitter src/Cljr.Compiler/Emitter/CSharpEmitter.cs
Benchmarks tests/Cljr.Benchmarks/CollectionBenchmarks.cs

References

External Resources