Skip to content

simd modifying existing code skill - #26

Closed
jeffschwMSFT wants to merge 2 commits into
dotnet:mainfrom
jeffschwMSFT:skill/simd-pattern-matching
Closed

simd modifying existing code skill#26
jeffschwMSFT wants to merge 2 commits into
dotnet:mainfrom
jeffschwMSFT:skill/simd-pattern-matching

Conversation

@jeffschwMSFT

Copy link
Copy Markdown
Member

while doing some broad .NET experience analysis, the model suggested it might not think of identifying common SIMD patterns and correctly modify the code without a skill. here are some common simd patterns and ways to optimize.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces two complementary skills for identifying and optimizing SIMD (Single Instruction, Multiple Data) opportunities in existing .NET 8+ codebases. The skills are designed to help AI agents scan codebases for scalar operations that would benefit from vectorization using System.Runtime.Intrinsics.

Changes:

  • Added simd-vector-math skill (355 lines) for optimizing floating-point vector operations like cosine similarity, dot products, L2 distance, batch normalization, and reduction operations
  • Added simd-pattern-matching skill (274 lines) for optimizing byte/string search, character class membership checks, and pattern matching operations
  • Included comprehensive test scenarios (eval.yaml) for both skills with positive optimization cases and negative "no opportunity" cases to teach appropriate application boundaries

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
skills/simd-vector-math/SKILL.md Defines skill for identifying and optimizing scalar floating-point vector math operations (Category A-D patterns: distance computations, batch arithmetic, reductions, lookups) with platform-adaptive SIMD implementations
skills/simd-vector-math/tests/eval.yaml Test scenarios covering cosine similarity, dot product/L2 distance, min-max normalization optimization, plus a negative case (string processing) with no SIMD opportunity
skills/simd-pattern-matching/SKILL.md Defines skill for identifying and optimizing scalar byte/string pattern matching operations (byte search, character class checks, fuzzy matching, bulk scanning) with SIMD acceleration
skills/simd-pattern-matching/tests/eval.yaml Test scenarios covering byte pattern search, alphanumeric counting, plus a negative case (config parser) with no SIMD opportunity

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/dotnet/skills/simd-pattern-matching/SKILL.md Outdated
@jeffschwMSFT jeffschwMSFT changed the title simd pattern matching skill simd modifying existing code skill Feb 21, 2026
@jeffschwMSFT

Copy link
Copy Markdown
Member Author

simd-pattern-matching

Skill Scenario Baseline With Skill Δ Verdict
simd-pattern-matching Optimize scalar byte search 2.0/5 4.0/5 +2.0
simd-pattern-matching Optimize scalar character class counting 2.0/5 3.0/5 +1.0
simd-pattern-matching No optimization opportunity — config file parser 3.0/5 3.0/5 0.0

@jeffschwMSFT

Copy link
Copy Markdown
Member Author

simd-vector-math

Skill Scenario Baseline With Skill Δ Verdict
simd-vector-math Optimize scalar cosine similarity 4.0/5 5.0/5 +1.0
simd-vector-math Optimize scalar dot product and L2 distance 4.0/5 5.0/5 +1.0
simd-vector-math Optimize scalar batch min-max normalization 5.0/5 5.0/5 0.0
simd-vector-math No optimization opportunity — string processing 2.0/5 5.0/5 +3.0

Note: simd-vector-math failed (0/1) because "Optimize scalar batch min-max normalization" regressed on task completion (✓→✗) — the with-skill agent timed out at 300s despite achieving 5.0/5 quality. The baseline completed within the time limit. Increasing the timeout further or reducing exploration overhead would likely resolve this.

@danmoseley

Copy link
Copy Markdown
Contributor

thoguhts about my comment above?

@jeffschwMSFT

Copy link
Copy Markdown
Member Author

thoughts about my comment above?

I was not intentionally ignoring, but I am not sure so when I ask an expert I am hoping they would answer :)

Comment thread src/dotnet/skills/simd-pattern-matching/SKILL.md Outdated
Comment thread src/dotnet/skills/simd-pattern-matching/SKILL.md Outdated
Comment thread src/dotnet/skills/simd-vector-math/SKILL.md Outdated
@danmoseley

Copy link
Copy Markdown
Contributor

A bunch of @tannergooding feedback I'd expect copilot could infer from instructing it to read our past blog posts, etc. I found that super useful for the NRT annotation one to gather more "team wisdom"

@tannergooding

Copy link
Copy Markdown
Member

I'd expect copilot could infer from instructing it to read our past blog posts, etc

There is also https://github.com/dotnet/runtime/blob/e5f78931886de441a0c9ffd26ad373a0c1d1bc77/docs/coding-guidelines/vectorization-guidelines.md, which is the general "coding guidelines" for anyone adding SIMD to the repo.

We also have some other documents such as https://github.com/dotnet/runtime/blob/e5f78931886de441a0c9ffd26ad373a0c1d1bc77/docs/design/coreclr/botr/vectors-and-intrinsics.md which cover other details and how SIMD support is setup in the JIT/VM

@jeffschwMSFT

Copy link
Copy Markdown
Member Author

the reason I started this skill was at copilot's request :) when exploring areas of potential need, SIMD'ifying existing code was elevated as a weak spot.

A bunch of @tannergooding feedback I'd expect copilot could infer from instructing it to read our past blog posts

It likely does, but with such a large corpus of information it needs to be guided.

I would expect that we want to keep most paths using IndexOf as IndexOf

This is a great point, I am curious if you feel there are patterns that would benefit from SIMD? eg. are there are parts of a skill that make sense, or is our strategy to keep improving the framework and less about moving customer code.

@tannergooding

Copy link
Copy Markdown
Member

I would expect us to evaluate on a per scenario basis.

In most cases we want to use existing centralized helper APIs where possible, like those exposed on Span (often via MemoryExtensions) or on TensorPrimitives. There are then special cases that warrant their own vectorization support, like many of the transcoding APIs.

In many cases, if we find an API that would benefit from vectorization but where we do not have an existing centralized helper, we want to consider if exposing a new centralized API is appropriate and vectorize that instead; only vectorizing the specific path if its one of the special cases that warrants that support.


SIMD code can be complex and hard to maintain, it also involves a bit of unsafe code (such as due to JIT limitations) and so its not something we really want to do "everywhere" or want customers to feel the need to go and do themselves.

We rather want to try to ensure they get the benefits while keeping most paths readable and maintainable first and foremost.

@jeffschwMSFT

Copy link
Copy Markdown
Member Author

really appreciate the feedback Tanner. Trying to find out what skills mater and which do not. I am going to take another run at this and see what you think.

@jeffschwMSFT

jeffschwMSFT commented Feb 24, 2026

Copy link
Copy Markdown
Member Author
Skill Scenario Baseline With Skill Δ Verdict
simd-pattern-matching Optimize printable ASCII validation 3.0/5 5.0/5 +2.0
simd-pattern-matching Optimize scalar character class counting 3.3/5 4.7/5 +1.4
simd-pattern-matching No optimization opportunity — config file parser 3.0/5 3.0/5 +0.0
simd-vector-math Optimize weighted Euclidean distance 4.3/5 4.3/5 +0.0
simd-vector-math Optimize quantized dequantization 4.7/5 4.7/5 +0.0
simd-vector-math No optimization opportunity — string processing service 1.3/5 2.7/5 +1.4

In addition, I ran this against a real piece of code doing 'maths' which I have been meaning to vectorize. Both with and skillout the skill it did a fine job, but overall raw thoughput is higher with the skill.

without skill

Config Overall Perf Math Specific benchmark
.NET 6 (netstandar2.1) ~1195ms ~820ms
.NET 10 + SIMD ~763ms ~480ms
Speedup 1.57x faster 1.71x faster

with skill

Config Overall Perf Math Specific benchmark
.NET 6 (netstandar2.1) ~1063ms ~769
.NET 10 + SIMD ~405ms ~181ms
Speedup 2.6x faster 4.2x faster

In addition, the run without the skill choose to add the nuget reference for Numerics, while the Skill knew it was part of the framework (less wasted time). Finally, interestingly, the non-skill run actually found 1 optimization which the skill one did not (a copy to move to Array.Copy).

Add SKILL.md and eval.yaml for both SIMD skills under the new
plugins/dotnet/skills/ and tests/dotnet/ directory structure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@artl93

artl93 commented Mar 2, 2026

Copy link
Copy Markdown
Member

I cannot comment on the implementation - I'd be curious how this does when merged with the other Perf skill and seeing how they interact in the real world needle-in-a-haystack eval. (You can advise copilot to build such a scenario. Your eval will balloon, but you might get some more real-world results.)

I'm also curious from a general applicability if we'd want this loaded by default in all sessions - that's a fair amount of tokens for a somewhat narrow opportunity. (It fits the standard, but I am curious if it's worth it by default.)

Comment thread plugins/dotnet/skills/simd-pattern-matching/SKILL.md
Comment thread plugins/dotnet/skills/simd-pattern-matching/SKILL.md
Comment thread plugins/dotnet/skills/simd-pattern-matching/SKILL.md
Comment thread plugins/dotnet/skills/simd-pattern-matching/SKILL.md
Comment thread plugins/dotnet/skills/simd-pattern-matching/SKILL.md
- **Bitwise:** operators `&`, `|`, `^`, `~`
- **Mask extraction:** `vec.ExtractMostSignificantBits()` → `uint` bitmask
- **Population count:** `BitOperations.PopCount(mask)` for counting matches
- **Shuffle:** `Vector128.Shuffle(vec, indices)` for nibble-lookup tables

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does there need to be an explicit callout for arithmetic operations?

Can we simplify this to just indicate that we prefer using the APIs on these types without listing them all?

We notably also have a number of other helpers so that things like ExtractMostSignificantBits is ideally needed/used less, such as All/Any/None, IndexOf, LastIndexOf, Count, etc

Comment thread plugins/dotnet/skills/simd-pattern-matching/SKILL.md
Build two 16-entry lookup tables (high/low nibble). `Vector128.Shuffle` with nibble index → AND results → `ExtractMostSignificantBits` + `PopCount` for counting.

### Memory access pattern
Head (scalar for pre-vector bytes) → Body (`Vector256.LoadUnsafe` / `Vector128.LoadUnsafe`) → Tail (overlapping last-vector for idempotent operations, or scalar remainder). Always use `ref MemoryMarshal.GetReference(span)` and `LoadUnsafe(ref T, nuint elementOffset)`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backtracking for idempotent operations is great, but we can also do the same thing for non-idempotent scenarios.

See for example here: https://source.dot.net/#System.Numerics.Tensors/System/Numerics/Tensors/netcore/Common/TensorPrimitives.IAggregationOperator.cs,00a250d202e0c1bb,references

Where the Vectrorized128 path is doing an aggregation operation and so can't include already processed elements twice, so we just get a mask based on what the remainder was so that we can appropriately adjust those to some identity value for the operation.

In other non-aggregation cases you can just merge it with the last stored vector so that the final store preserves those how they should've been, rather than potentially changing them.

@@ -0,0 +1,122 @@
---
name: simd-vector-math
description: Optimizes scalar float/double vector math in .NET 8+ with cross-platform Vector128/Vector256 SIMD intrinsics. Transforms hot-path scalar code into vectorized implementations — never generates greenfield.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the difference between pattern matching and vector-math here.

Seems like these are both just "optimize loop code" scenarios where if we don't have an existing built-in, we want to vectorize it. All the general vectorization steps should then be essentially the same.

@jeffschwMSFT jeffschwMSFT closed this by deleting the head repository Mar 4, 2026
@tannergooding

Copy link
Copy Markdown
Member

Was this closed because the plan is to integrate it with another skill as well or is it just not moving forward?

@jeffschwMSFT

jeffschwMSFT commented Mar 5, 2026 via email

Copy link
Copy Markdown
Member Author

moesac0970 pushed a commit to moesac0970/skills that referenced this pull request Jul 4, 2026
…olication skills removed, diagnostics skills kept
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants