<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pedro Sakuma Travi</title>
    <description>The latest articles on DEV Community by Pedro Sakuma Travi (@pedrosakuma).</description>
    <link>https://dev.to/pedrosakuma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4029119%2F244313b9-edbc-420f-8b16-a91ffcef588a.jpg</url>
      <title>DEV Community: Pedro Sakuma Travi</title>
      <link>https://dev.to/pedrosakuma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pedrosakuma"/>
    <language>en</language>
    <item>
      <title>How ReadOnlySpan&lt;char&gt;.IndexOf finds a substring with SIMD</title>
      <dc:creator>Pedro Sakuma Travi</dc:creator>
      <pubDate>Sun, 18 Oct 2026 22:43:33 +0000</pubDate>
      <link>https://dev.to/pedrosakuma/how-readonlyspanindexof-finds-a-substring-with-simd-2i2d</link>
      <guid>https://dev.to/pedrosakuma/how-readonlyspanindexof-finds-a-substring-with-simd-2i2d</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/pedrosakuma/como-readonlyspanindexof-encontra-uma-substring-com-simd-2jg1"&gt;Leia em português&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article follows the video's sequence of ideas: the video animates the&lt;br&gt;
states; here we can pause at each diagram and examine the code and assembly.&lt;br&gt;
The walkthrough uses the same teaching example, separate from the measured&lt;br&gt;
inputs. The opening result comes from a selected MediumRun, but still applies&lt;br&gt;
to a particular machine and scenario. The KMP and BMH comparison at the end is&lt;br&gt;
supplementary material, outside the main video.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. The surprising result
&lt;/h2&gt;

&lt;p&gt;A search written as a loop might seem cheaper than a call to a higher-level&lt;br&gt;
API. To test that intuition, we compared two implementations that find &lt;strong&gt;the&lt;br&gt;
first occurrence&lt;/strong&gt; of a substring and return its index, or &lt;code&gt;-1&lt;/code&gt; if none exists.&lt;/p&gt;

&lt;p&gt;Here is the result used in the opening: a 16-&lt;code&gt;char&lt;/code&gt; substring inserted at the&lt;br&gt;
end of a pseudorandom text containing 65,536 &lt;code&gt;char&lt;/code&gt; elements.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Mean per search&lt;/th&gt;
&lt;th&gt;Standard deviation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Naive loop&lt;/td&gt;
&lt;td&gt;134.935 µs&lt;/td&gt;
&lt;td&gt;24.518 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;.IndexOf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5.653 µs&lt;/td&gt;
&lt;td&gt;389 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this input and host, the loop's mean was approximately &lt;strong&gt;23.9×&lt;/strong&gt; the mean&lt;br&gt;
for &lt;code&gt;IndexOf&lt;/code&gt;. That is not a prediction for every string, CPU, or runtime&lt;br&gt;
version. As we will see, the loop and runtime also use different algorithms;&lt;br&gt;
this benchmark does not isolate the cost of abstraction alone.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. The two implementations
&lt;/h2&gt;

&lt;p&gt;The harness uses BenchmarkDotNet. The methods, inputs, configuration, and&lt;br&gt;
instructions for putting together a reproduction are included in this&lt;br&gt;
article. Each operation receives one &lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;&lt;/code&gt; for the text and&lt;br&gt;
another for the needle. The comparison is ordinal: it compares UTF-16 &lt;code&gt;char&lt;/code&gt;&lt;br&gt;
code units without culture-sensitive rules. Both implementations return the&lt;br&gt;
first occurrence's index, or &lt;code&gt;-1&lt;/code&gt; if there is no match. A .NET &lt;code&gt;char&lt;/code&gt; is a&lt;br&gt;
UTF-16 code unit, not necessarily a user-perceived grapheme.&lt;/p&gt;

&lt;p&gt;The baseline implements naive, or brute-force, search: try every starting&lt;br&gt;
position and compare the needle character by character. The second method&lt;br&gt;
calls the runtime API. These two methods drive the main explanation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
               &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BenchmarkDotNet measures them through these wrappers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Baseline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first wrapper measures the naive loop above. The second measures&lt;br&gt;
&lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;.IndexOf&lt;/code&gt; with ordinal comparison. To explain the observed&lt;br&gt;
path, we use the .NET 10.0.12 runtime implementation:&lt;br&gt;
&lt;a href="https://github.com/dotnet/runtime/blob/v10.0.12/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs" rel="noopener noreferrer"&gt;&lt;code&gt;SpanHelpers.IndexOf(ref char, int, ref char, int)&lt;/code&gt; in&lt;br&gt;
&lt;code&gt;SpanHelpers.Char.cs&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
On this host, it uses a vectorized candidate filter and checks candidates&lt;br&gt;
against the complete substring. This is not our own search algorithm, nor a&lt;br&gt;
guarantee that another runtime version or CPU will choose the same path.&lt;/p&gt;

&lt;p&gt;Before timing, &lt;code&gt;GlobalSetup&lt;/code&gt; runs all four methods for each input and requires&lt;br&gt;
the expected result. For example, a scenario labeled "missing" cannot enter&lt;br&gt;
the benchmark if a search finds an accidental occurrence. Validation happens&lt;br&gt;
before measurement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;naive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomEarlyMatch&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMiddleMatch&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixLate&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMissing&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixMissing&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;naive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benchmark compares a scalar, character-by-character search with the&lt;br&gt;
runtime's optimized implementation. It does not isolate API-call overhead.&lt;br&gt;
The question is what work the algorithms perform, not whether a particular&lt;br&gt;
syntax or abstraction is inherently faster. KMP and Boyer–Moore–Horspool&lt;br&gt;
appear at the end as a complementary comparison, not a replacement for the&lt;br&gt;
main explanation.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Inputs: what did we test?
&lt;/h2&gt;

&lt;p&gt;The harness combines &lt;strong&gt;seven scenarios&lt;/strong&gt; with texts of &lt;strong&gt;4,096 and 65,536&lt;br&gt;
&lt;code&gt;char&lt;/code&gt; elements&lt;/strong&gt;. Inputs are built once during setup, outside the timed region.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Text and needle&lt;/th&gt;
&lt;th&gt;Expected result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomEarlyMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pseudorandom text over &lt;code&gt;a&lt;/code&gt;–&lt;code&gt;h&lt;/code&gt;; needle &lt;code&gt;abcdefghabcdefgh&lt;/code&gt; inserted at index 0.&lt;/td&gt;
&lt;td&gt;index 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomMiddleMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same generator and needle, inserted halfway through the text.&lt;/td&gt;
&lt;td&gt;index &lt;code&gt;HaystackLength / 2&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomLateMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same generator and needle, inserted into the final 16 elements.&lt;/td&gt;
&lt;td&gt;index &lt;code&gt;HaystackLength - 16&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomMissing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same generator and alphabet, without inserting the needle.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-1&lt;/code&gt;, checked in setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RepeatedPrefixMissing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text consisting only of &lt;code&gt;a&lt;/code&gt;; needle &lt;code&gt;aaaaaaab&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RepeatedPrefixLate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text consisting only of &lt;code&gt;a&lt;/code&gt;, with &lt;code&gt;aaaaaaab&lt;/code&gt; replacing the final eight elements.&lt;/td&gt;
&lt;td&gt;index &lt;code&gt;HaystackLength - 8&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RepeatedAlternatingLateFalse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Alternating &lt;code&gt;ab&lt;/code&gt; text; 64-element needle alternating for the first 63 elements and ending in &lt;code&gt;a&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-1&lt;/code&gt;; false candidates differ at the final element&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pseudorandom generator is deterministic. It starts at &lt;code&gt;0xC0FFEE&lt;/code&gt; and&lt;br&gt;
updates a 32-bit state for each position using&lt;br&gt;
&lt;code&gt;state = state * 1664525 + 1013904223&lt;/code&gt;. The top three bits select one of the&lt;br&gt;
eight characters &lt;code&gt;a&lt;/code&gt;–&lt;code&gt;h&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;CreateOrdinaryHaystack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;alphabet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefgh"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0xC0FFEE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;1664525&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1013904223&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alphabet&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In matching scenarios, the corresponding text segment is replaced with the&lt;br&gt;
needle. For the late match used in the opening, this is equivalent to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefghabcdefgh"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CreateOrdinaryHaystack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;matchIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// RandomLateMatch&lt;/span&gt;
&lt;span class="n"&gt;haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[..&lt;/span&gt;&lt;span class="n"&gt;matchIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;
    &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;matchIndex&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)..];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The missing scenario keeps the same alphabet, avoiding a trivial miss caused&lt;br&gt;
by impossible characters. Setup verifies that the complete needle is absent.&lt;/p&gt;
&lt;h3&gt;
  
  
  The adversarial benchmark scenario
&lt;/h3&gt;

&lt;p&gt;This measured case differs from both the opening and the teaching example in&lt;br&gt;
sections 6–7. The text alternates &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;. The needle also alternates, but&lt;br&gt;
its final &lt;code&gt;char&lt;/code&gt; is changed to &lt;code&gt;a&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;CreateAlternatingNeedleWithLateMismatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[^&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runtime uses the first &lt;code&gt;char&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;, and searches backward for the last&lt;br&gt;
needle element that differs from it. Positions 63 and 62 contain &lt;code&gt;a&lt;/code&gt;, so the&lt;br&gt;
selected position is 61, containing &lt;code&gt;b&lt;/code&gt;. Both filters pass at every even start:&lt;br&gt;
&lt;code&gt;haystack[i] == 'a'&lt;/code&gt; and &lt;code&gt;haystack[i + 61] == 'b'&lt;/code&gt;. The complete substring,&lt;br&gt;
however, differs at its final element: the text has &lt;code&gt;b&lt;/code&gt; at relative position&lt;br&gt;
63, while the needle has &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Text length&lt;/th&gt;
&lt;th&gt;Expected false candidates&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;2,017&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;td&gt;32,737&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Setup checks a conceptual one-bit-per-lane summary, &lt;code&gt;0x5555&lt;/code&gt;, the expected&lt;br&gt;
one-bit-per-byte extracted mask, &lt;code&gt;0x33333333&lt;/code&gt;, and the total candidate count.&lt;br&gt;
The first summary is neither the comparison vector nor an intermediate&lt;br&gt;
runtime variable: each approved lane contains &lt;code&gt;FFFF&lt;/code&gt;. This is a scalar&lt;br&gt;
validation of the fixture, not a reading of runtime registers.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Measurement and results
&lt;/h2&gt;

&lt;p&gt;We used BenchmarkDotNet 0.15.8, Release builds, .NET 10.0.12 (SDK 10.0.401),&lt;br&gt;
Ubuntu 24.04.4 Linux x64, and an AMD EPYC 7763 at 2.45 GHz. BenchmarkDotNet&lt;br&gt;
reported one CPU available to the process. The host exposed AVX2 and BMI1;&lt;br&gt;
the assembly capture discussed here comes from this environment.&lt;/p&gt;

&lt;p&gt;Two lengths, seven scenarios, and four methods yield 56 method/case&lt;br&gt;
combinations in the broad ShortRun matrix. These attributes configure it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ShortRunJob&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MemoryDiagnoser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;DisassemblyDiagnoser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubstringSearchBenchmarks&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomEarlyMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMiddleMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMissing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixMissing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixLate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The broad matrix used &lt;code&gt;ShortRun&lt;/code&gt;: three warmup iterations and three measurement&lt;br&gt;
iterations. For the late-match and adversarial scenarios, we also ran&lt;br&gt;
&lt;code&gt;MediumRun&lt;/code&gt;: ten warmups, fifteen measurement iterations, and two processes&lt;br&gt;
per benchmark. This table reports MediumRun means and standard deviations;&lt;br&gt;
units have been converted for readability:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input length&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Naive: mean ± standard deviation&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;IndexOf&lt;/code&gt;: mean ± standard deviation&lt;/th&gt;
&lt;th&gt;Ratio of means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;Late match, pseudorandom text&lt;/td&gt;
&lt;td&gt;3.443 ± 0.238 µs&lt;/td&gt;
&lt;td&gt;323 ± 15 ns&lt;/td&gt;
&lt;td&gt;10.7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;td&gt;Late match, pseudorandom text&lt;/td&gt;
&lt;td&gt;134.935 ± 24.518 µs&lt;/td&gt;
&lt;td&gt;5.653 µs ± 389 ns&lt;/td&gt;
&lt;td&gt;23.9×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;Many candidates, final-element mismatch&lt;/td&gt;
&lt;td&gt;149.369 ± 57.317 µs&lt;/td&gt;
&lt;td&gt;7.645 µs ± 390 ns&lt;/td&gt;
&lt;td&gt;19.5×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;td&gt;Many candidates, final-element mismatch&lt;/td&gt;
&lt;td&gt;1.925 ± 0.202 ms&lt;/td&gt;
&lt;td&gt;129.186 ± 7.864 µs&lt;/td&gt;
&lt;td&gt;14.9×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The adversarial scenario has substantial dispersion, particularly in the&lt;br&gt;
naive loop. We therefore report dispersion alongside means rather than treat&lt;br&gt;
it as a typical case. Nor do we attribute the entire gain to SIMD: the C#&lt;br&gt;
baseline examines positions with a different algorithm from &lt;code&gt;IndexOf&lt;/code&gt;, which&lt;br&gt;
also uses vector instructions. The supported conclusion is narrower:&lt;br&gt;
&lt;strong&gt;on this host, for these inputs, the runtime implementation was faster&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the original run, validation compared &lt;code&gt;IndexOf&lt;/code&gt;, KMP, and BMH against the&lt;br&gt;
naive baseline across 34,193 deterministic cases: all binary strings up to&lt;br&gt;
eight &lt;code&gt;char&lt;/code&gt; elements and needles up to five, plus 2,000 generated inputs&lt;br&gt;
containing diverse characters, including NUL and surrogate code units.&lt;br&gt;
Coverage included empty needles, needles longer than the text, injected&lt;br&gt;
matches, and missing substrings.&lt;/p&gt;

&lt;p&gt;In the original capture, adding &lt;code&gt;--job Medium&lt;/code&gt; to a class annotated with&lt;br&gt;
&lt;code&gt;[ShortRunJob]&lt;/code&gt; ran both jobs. The reported values come from &lt;code&gt;Job=MediumRun&lt;/code&gt;&lt;br&gt;
rows. The reproduction at the end uses only &lt;code&gt;[MediumRunJob]&lt;/code&gt; to run the two&lt;br&gt;
selected scenarios without repeating the ShortRun matrix.&lt;/p&gt;

&lt;p&gt;The project pins &lt;code&gt;RuntimeFrameworkVersion&lt;/code&gt; to &lt;code&gt;10.0.12&lt;/code&gt; and disables&lt;br&gt;
roll-forward. Its configuration and commands are included below, without&lt;br&gt;
depending on files outside this article.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. The idea behind SIMD
&lt;/h2&gt;

&lt;p&gt;SIMD applies the same operation to multiple data elements. In the observed&lt;br&gt;
path, those elements are 16-bit UTF-16 code units. A 256-bit vector holds&lt;br&gt;
16 &lt;code&gt;char&lt;/code&gt; lanes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane:  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
char: [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That does not mean the entire search takes one instruction. The vector selects&lt;br&gt;
several possible starts for verification. The path still iterates over blocks,&lt;br&gt;
processes masks, and checks the complete substring.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Finding candidates
&lt;/h2&gt;
&lt;h3&gt;
  
  
  A small input for following the calculations
&lt;/h3&gt;

&lt;p&gt;We use the same teaching fixture as the video: a &lt;strong&gt;64-code-unit&lt;/strong&gt; needle&lt;br&gt;
inserted at index &lt;strong&gt;6&lt;/strong&gt; of a &lt;strong&gt;79-code-unit&lt;/strong&gt; text, filled with &lt;code&gt;x&lt;/code&gt; outside that&lt;br&gt;
segment. The needle alternates &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, except for its final element, &lt;code&gt;a&lt;/code&gt;.&lt;br&gt;
This reproduces the input; it is not a timed benchmark scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;63&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;79&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;CopyTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// result == 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are &lt;code&gt;79 - 64 + 1 = 16&lt;/code&gt; valid starts, from 0 through 15, fitting one&lt;br&gt;
16-lane window. The goal is to explain the path to a match, not depict the&lt;br&gt;
data responsible for the benchmark timings.&lt;/p&gt;
&lt;h3&gt;
  
  
  Choosing two needle positions
&lt;/h3&gt;

&lt;p&gt;The first position is &lt;code&gt;value[0] == 'a'&lt;/code&gt;. For the second, the runtime searches&lt;br&gt;
backward for an element different from the first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;needle position:     0    1   ...   61   62   63
value:               a    b   ...    b    a    a
                     ^              ^
                    ch1            ch2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Positions 63 and 62 contain &lt;code&gt;a&lt;/code&gt;; position 61 contains &lt;code&gt;b&lt;/code&gt;. Therefore,&lt;br&gt;
&lt;code&gt;ch1ch2Distance = 61&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;ch2&lt;/code&gt; is not necessarily the final character&lt;/strong&gt;:&lt;br&gt;
it is the second position chosen for filtering.&lt;/p&gt;

&lt;p&gt;These values are broadcast into vectors: &lt;code&gt;ch1&lt;/code&gt; contains 16 copies of &lt;code&gt;a&lt;/code&gt;;&lt;br&gt;
&lt;code&gt;ch2&lt;/code&gt;, 16 copies of &lt;code&gt;b&lt;/code&gt;. For start &lt;code&gt;i&lt;/code&gt;, we ask whether &lt;code&gt;text[i] == 'a'&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;text[i + 61] == 'b'&lt;/code&gt;. If either fails, that start cannot be a complete match.&lt;/p&gt;
&lt;h3&gt;
  
  
  Offset, lane, and address are different concepts
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;offset&lt;/code&gt; is the start of the candidate window in the text. Lane &lt;code&gt;j&lt;/code&gt; represents&lt;br&gt;
start &lt;code&gt;offset + j&lt;/code&gt;. Here, &lt;code&gt;offset = 0&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lane&lt;/th&gt;
&lt;th&gt;Candidate start&lt;/th&gt;
&lt;th&gt;First position&lt;/th&gt;
&lt;th&gt;Second position&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 + 6 = 6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[6] == 'a'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;text[0 + 6 + 61]&lt;/code&gt;, or &lt;code&gt;text[67] == 'b'&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 + 8 = 8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[8] == 'a'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;text[0 + 8 + 61]&lt;/code&gt;, or &lt;code&gt;text[69] == 'b'&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The runtime excerpt compares the second position first, then the first, then&lt;br&gt;
combines them with AND. Variable types are omitted and line breaks adjusted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;cmpCh2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;searchSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nuint&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ch1ch2Distance&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="n"&gt;cmpCh1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ch1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;searchSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nuint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;cmpAnd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmpCh1&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cmpCh2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AsByte&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this branch, &lt;code&gt;searchSpace&lt;/code&gt; references &lt;code&gt;ushort&lt;/code&gt; elements. Load offsets are&lt;br&gt;
in 16-bit UTF-16 units, &lt;strong&gt;not bytes&lt;/strong&gt;. The loads read &lt;code&gt;text[61..77]&lt;/code&gt; and&lt;br&gt;
&lt;code&gt;text[0..16]&lt;/code&gt;, with exclusive upper bounds. Adding the distance to the&lt;br&gt;
displaced load keeps each candidate's two positions in the same lane: lane 6&lt;br&gt;
relates &lt;code&gt;text[6]&lt;/code&gt; to &lt;code&gt;text[67]&lt;/code&gt;, not elements belonging to different starts.&lt;/p&gt;
&lt;h3&gt;
  
  
  Comparing and combining all 16 lanes
&lt;/h3&gt;

&lt;p&gt;Each equality produces &lt;code&gt;FFFF&lt;/code&gt; when true and &lt;code&gt;0000&lt;/code&gt; when false. In this table,&lt;br&gt;
&lt;strong&gt;1 and 0 abbreviate those 16-bit values&lt;/strong&gt;; they are not the integer values&lt;br&gt;
stored in the vector. The operation remains &lt;code&gt;==&lt;/code&gt; in every lane, even when its&lt;br&gt;
result is false.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane:        0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
text[i+61]:  b  a  b  a  b  a  b  a  a  x  x  x  x  x  x  x
ch2:         b  b  b  b  b  b  b  b  b  b  b  b  b  b  b  b
cmpCh2:      1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0

text[i]:     x  x  x  x  x  x  a  b  a  b  a  b  a  b  a  b
ch1:         a  a  a  a  a  a  a  a  a  a  a  a  a  a  a  a
cmpCh1:      0  0  0  0  0  0  1  0  1  0  1  0  1  0  1  0

cmpCh1:      0  0  0  0  0  0  1  0  1  0  1  0  1  0  1  0
cmpCh2:      1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0
AND:         0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lane 6 passes both equalities: &lt;code&gt;a == a&lt;/code&gt; and &lt;code&gt;b == b&lt;/code&gt;. Lane 8 passes the first,&lt;br&gt;
&lt;code&gt;text[8] == 'a'&lt;/code&gt;, but fails the second: &lt;code&gt;text[69]&lt;/code&gt; contains &lt;code&gt;a&lt;/code&gt;, so &lt;code&gt;a == b&lt;/code&gt;&lt;br&gt;
is false. AND retains only lane 6.&lt;/p&gt;

&lt;p&gt;SIMD comparisons process lanes in parallel. Reading columns 6 and 8 merely&lt;br&gt;
explains their results. &lt;code&gt;AsByte()&lt;/code&gt; reinterprets the same bits as bytes;&lt;br&gt;
it does not convert &lt;code&gt;FFFF&lt;/code&gt; to the number 1.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cmpAnd != Vector256&amp;lt;byte&amp;gt;.Zero&lt;/code&gt; produces a scalar decision: &lt;strong&gt;a candidate&lt;br&gt;
exists&lt;/strong&gt;. It neither identifies the index nor confirms the substring. In the&lt;br&gt;
captured benchmark assembly, &lt;code&gt;vpcmpeqw&lt;/code&gt;, &lt;code&gt;vpand&lt;/code&gt;, and &lt;code&gt;vptest&lt;/code&gt; correspond to&lt;br&gt;
the comparisons, combination, and test. This evidence belongs to the documented&lt;br&gt;
host; it is not a guarantee of the same translation on every machine.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Locating and confirming the candidate
&lt;/h2&gt;
&lt;h3&gt;
  
  
  From one 16-bit lane to two mask bits
&lt;/h3&gt;

&lt;p&gt;The runtime extracts the most significant bit of each byte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmpAnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractMostSignificantBits&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 16 elements of 16 bits, reinterpreted as 32 bytes. In lane 6, the&lt;br&gt;
true result contains two &lt;code&gt;FF&lt;/code&gt; bytes; every other element contains two &lt;code&gt;00&lt;/code&gt;&lt;br&gt;
bytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane 6:                  FFFF
bytes in vector:         byte 12 = FF     byte 13 = FF
bits in each byte:                 11111111         11111111
most significant bit:             1                1
mask position:                    12               13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lane 0 corresponds to bytes and bits 0–1; lane 1 to 2–3; lane 6 to 12–13.&lt;br&gt;
The actual extracted mask is therefore &lt;strong&gt;&lt;code&gt;0x00003000&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;index:   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
bit:     0  0  0  0  0  0  0  0  0  0  0  0  1  1  0  0
index:  16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
bit:     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indices increase &lt;strong&gt;from left to right&lt;/strong&gt;, as in the video. This is not the&lt;br&gt;
usual numeric binary notation: the least significant bit is on the left.&lt;br&gt;
Each bit represents a byte of the result vector, not a character directly.&lt;br&gt;
In the observed assembly, extraction corresponds to &lt;code&gt;vpmovmskb&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Counting, converting, and adding the offset
&lt;/h3&gt;

&lt;p&gt;The next calculation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;charPos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nint&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrailingZeroCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ushort&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Counting starts at bit 0 and finds 12 zeros before the first 1. Thus,&lt;br&gt;
&lt;code&gt;TrailingZeroCount(0x00003000) = 12&lt;/code&gt;. Dividing by &lt;code&gt;sizeof(ushort)&lt;/code&gt;, which is 2,&lt;br&gt;
converts the byte position represented by that bit into an element position:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;first set bit:    12
charPos:         12 / 2 = 6
index in text:   offset + charPos = 0 + 6 = 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;charPos&lt;/code&gt; is relative to the window; the text index includes &lt;code&gt;offset&lt;/code&gt;. They&lt;br&gt;
coincide here because offset is zero. In the captured assembly, the count&lt;br&gt;
corresponds to &lt;code&gt;tzcnt&lt;/code&gt;, and division by two to a bit shift.&lt;/p&gt;
&lt;h3&gt;
  
  
  Checking the entire sequence
&lt;/h3&gt;

&lt;p&gt;Only now do we check complete equality. Here is the runtime excerpt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;searchSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;charPos&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nuint&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;charPos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;valueLength == 2&lt;/code&gt; is false because our needle contains 64 elements.&lt;br&gt;
&lt;code&gt;SequenceEqual&lt;/code&gt; compares its 128 bytes with those of the segment starting at&lt;br&gt;
&lt;code&gt;text[6]&lt;/code&gt;. These ranges have exclusive upper bounds:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Needle segment&lt;/th&gt;
&lt;th&gt;Corresponding text segment&lt;/th&gt;
&lt;th&gt;Equal contents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[0..16]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[6..22]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[16..32]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[22..38]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[32..48]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[38..54]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[48..64]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[54..70]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababaa&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All four pairs are equal. The call returns &lt;code&gt;true&lt;/code&gt;, and the method returns&lt;br&gt;
&lt;strong&gt;&lt;code&gt;offset + charPos = 6&lt;/code&gt;&lt;/strong&gt;. The table organizes data, not instruction execution&lt;br&gt;
order. Confirmation also uses SIMD in the captured assembly for the benchmark's&lt;br&gt;
needle of this size. We do not need to walk through its implementation to&lt;br&gt;
understand its role in the search.&lt;/p&gt;

&lt;p&gt;If confirmation failed, the runtime would clear the candidate's two bits and&lt;br&gt;
continue with the next marked pair, if any remained. That does not happen in&lt;br&gt;
this fixture, which finds a match.&lt;/p&gt;

&lt;p&gt;We can check the arithmetic without reading internal registers. Add this to&lt;br&gt;
the C# example that constructs &lt;code&gt;text&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; in section 6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;expectedMask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;expectedMask&lt;/span&gt; &lt;span class="p"&gt;|=&lt;/span&gt; &lt;span class="m"&gt;3u&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedMask&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0x00003000&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrailingZeroCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedMask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ushort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Inconsistent teaching fixture."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;expectedMask&lt;/code&gt; is a scalar verification calculation, not an extraction from&lt;br&gt;
the vector used internally by &lt;code&gt;IndexOf&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Verify, do not assume
&lt;/h2&gt;

&lt;p&gt;The teaching example has an occurrence at index 6. The adversarial scenario&lt;br&gt;
measured in section 3 keeps the same needle but uses an entirely alternating&lt;br&gt;
text, without inserting an occurrence. Every even start passes both filter&lt;br&gt;
positions, but the complete comparison fails at the final element: the text&lt;br&gt;
has &lt;code&gt;b&lt;/code&gt;, while the needle ends in &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Candidates in the first window&lt;/th&gt;
&lt;th&gt;Extracted one-bit-per-byte mask&lt;/th&gt;
&lt;th&gt;Search result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Teaching example: 79 elements, inserted occurrence&lt;/td&gt;
&lt;td&gt;Only lane 6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00003000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adversarial: alternating &lt;code&gt;ab&lt;/code&gt; text&lt;/td&gt;
&lt;td&gt;Lanes 0, 2, 4, 6, 8, 10, 12, 14&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x33333333&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the adversarial input, we could summarize approved lanes as &lt;code&gt;0x5555&lt;/code&gt;,&lt;br&gt;
using one bit per lane. That is only a conceptual representation. Vector&lt;br&gt;
results are &lt;code&gt;FFFF/0000&lt;/code&gt;, and the extracted &lt;code&gt;mask&lt;/code&gt; variable contains two set&lt;br&gt;
bits per candidate. After rejecting start 0, clearing bits 0–1 changes&lt;br&gt;
&lt;code&gt;0x33333333&lt;/code&gt; to &lt;code&gt;0x33333330&lt;/code&gt;. The next trailing-zero count is 4;&lt;br&gt;
&lt;code&gt;4 / 2 = 2&lt;/code&gt; points to the next candidate. In the observed assembly,&lt;br&gt;
two &lt;code&gt;blsr&lt;/code&gt; instructions clear the two bits.&lt;/p&gt;

&lt;p&gt;For a text containing 65,536 elements, there are&lt;br&gt;
&lt;code&gt;((65,536 - 64) / 2) + 1 = 32,737&lt;/code&gt; even candidate starts. All are false and&lt;br&gt;
fail at the final element. This counts distinct positions passing the filter,&lt;br&gt;
not measured internal &lt;code&gt;SequenceEqual&lt;/code&gt; calls: the final window can overlap&lt;br&gt;
positions examined earlier.&lt;/p&gt;

&lt;p&gt;During setup, the harness recomputes the expected first-block mask and total&lt;br&gt;
candidate count with scalar code, and checks that all four methods return&lt;br&gt;
&lt;code&gt;-1&lt;/code&gt;. That validates the input and arithmetic; it does not read internal&lt;br&gt;
runtime registers. The connection to instructions comes from the versioned&lt;br&gt;
source and captured assembly. The first expected steps are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mask before&lt;/th&gt;
&lt;th&gt;Trailing zeros&lt;/th&gt;
&lt;th&gt;Position / 2&lt;/th&gt;
&lt;th&gt;Confirmation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333333&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;fails at relative element 63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333330&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;fails at relative element 63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333300&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;fails at relative element 63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;fails at relative element 63&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Finally, the approximately 24× opening result belongs to a third input:&lt;br&gt;
&lt;strong&gt;a pseudorandom late match, with a 16-element needle and 65,536-element text&lt;/strong&gt;.&lt;br&gt;
It is neither the adversarial result nor a measurement of the teaching fixture.&lt;br&gt;
The example explains the algorithm; each measurement belongs to its own input.&lt;/p&gt;
&lt;h2&gt;
  
  
  9. Advancing, finishing, and returning to the result
&lt;/h2&gt;

&lt;p&gt;After checking a block, the algorithm advances by a vector width. If the next&lt;br&gt;
advance would pass the last full candidate window, the loop clamps its offset&lt;br&gt;
to that final window, overlapping the previous block to cover the remaining&lt;br&gt;
starts without reading beyond the input. Inputs with fewer than eight possible&lt;br&gt;
starts cannot use this host's 128-bit vector path and take the scalar path.&lt;br&gt;
The exact bounds and branches come from the runtime source, not from the API's&lt;br&gt;
name alone.&lt;/p&gt;

&lt;p&gt;In this capture, the filter uses AVX2: word comparisons, AND, vector testing,&lt;br&gt;
and mask extraction. &lt;code&gt;tzcnt&lt;/code&gt; and &lt;code&gt;blsr&lt;/code&gt; belong to BMI1, and confirmation also&lt;br&gt;
uses vectorized byte comparisons. This observation applies to the documented&lt;br&gt;
runtime, JIT, and CPU; another machine may take a different path. The opening&lt;br&gt;
number shows that, in this experiment, the runtime finds candidates in parallel&lt;br&gt;
and outperforms the scalar, character-by-character search. It does not prove&lt;br&gt;
that less abstraction always costs more, or that SIMD always wins. Interpreting&lt;br&gt;
a benchmark requires knowing which data and algorithms were measured.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mapping the observed instructions
&lt;/h3&gt;

&lt;p&gt;This table summarizes the capture on Linux x64 / EPYC 7763, .NET 10.0.12,&lt;br&gt;
AVX2, and BMI1. It is neither a promise of one-to-one translation on other&lt;br&gt;
CPUs or versions nor a new capture of the teaching fixture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Observed instructions&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Broadcast &lt;code&gt;ch1&lt;/code&gt; and &lt;code&gt;ch2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;vmovd&lt;/code&gt;, &lt;code&gt;vpbroadcastw&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Repeat the value in 16 lanes of 16 bits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Vector256.Equals&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vpcmpeqw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Produce &lt;code&gt;FFFF&lt;/code&gt; or &lt;code&gt;0000&lt;/code&gt; per lane.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AND the results&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vpand&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retain positions passing both comparisons.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test the vector against zero&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;vptest&lt;/code&gt; and a branch&lt;/td&gt;
&lt;td&gt;Skip mask extraction when there is no candidate.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ExtractMostSignificantBits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vpmovmskb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extract 32 bits, one per byte.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TrailingZeroCount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tzcnt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Locate the first set bit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Divide by 2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;shr ..., 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Convert a byte position to a UTF-16 element position.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clear a rejected candidate's two bits&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;blsr&lt;/code&gt;, twice&lt;/td&gt;
&lt;td&gt;Continue to another candidate.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the adversarial case's 128-byte confirmation, the observed assembly&lt;br&gt;
compares AVX2 chunks of 32 bytes. The first three chunks agree; the fourth&lt;br&gt;
contains the final-element mismatch. This describes that capture, not a&lt;br&gt;
requirement that &lt;code&gt;SequenceEqual&lt;/code&gt; always execute four steps.&lt;/p&gt;
&lt;h2&gt;
  
  
  As a side note: what about KMP and Boyer–Moore?
&lt;/h2&gt;

&lt;p&gt;After the main conclusion, a natural question is how the comparison changes&lt;br&gt;
with algorithms that avoid restarting from scratch. We added two&lt;br&gt;
implementations to the same harness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Knuth–Morris–Pratt (KMP):&lt;/strong&gt; builds a needle prefix table and uses it to resume
from the longest prefix that could still match. Search and preprocessing
together cost O(n + m), where &lt;code&gt;n&lt;/code&gt; is the text length and &lt;code&gt;m&lt;/code&gt; the needle length.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boyer–Moore–Horspool (BMH):&lt;/strong&gt; compares right to left and, after a mismatch,
advances based on the window's final character and its position in the needle.
Preprocessing costs O(m); search often skips positions, but its worst case
remains O(nm).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this &lt;strong&gt;one search per needle&lt;/strong&gt; comparison, timed work includes building&lt;br&gt;
each algorithm's tables on every call. KMP allocates and fills its prefix&lt;br&gt;
table; BMH builds a sparse shift table, &lt;code&gt;Dictionary&amp;lt;char, int&amp;gt;&lt;/code&gt;, before scanning.&lt;br&gt;
The runtime receives the same needle and text without reused preprocessed&lt;br&gt;
state. All four methods return the first index or &lt;code&gt;-1&lt;/code&gt;; &lt;code&gt;GlobalSetup&lt;/code&gt; checks&lt;br&gt;
the expected result before measurement.&lt;/p&gt;

&lt;p&gt;The additional benchmark code is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;prefixLengths&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefixLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;

        &lt;span class="n"&gt;prefixLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefixLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;shifts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="n"&gt;shifts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;--;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shifts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the final comparison for the two selected scenarios: MediumRun means&lt;br&gt;
and standard deviations, with fifteen measurement iterations, ten warmups, and&lt;br&gt;
two processes per benchmark. All four implementations received the same text&lt;br&gt;
and needle. KMP and BMH include table construction on every call.&lt;br&gt;
This comparison is an independent run from the historical measurement used in&lt;br&gt;
the opening. Compare values within this table, not directly with the opening's&lt;br&gt;
numbers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Text length&lt;/th&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Naive loop&lt;/th&gt;
&lt;th&gt;&lt;code&gt;IndexOf&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;KMP&lt;/th&gt;
&lt;th&gt;Boyer–Moore–Horspool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;Pseudorandom late match&lt;/td&gt;
&lt;td&gt;3.291 ± 0.093 µs&lt;/td&gt;
&lt;td&gt;0.320 ± 0.016 µs&lt;/td&gt;
&lt;td&gt;5.026 ± 0.189 µs&lt;/td&gt;
&lt;td&gt;10.303 ± 0.223 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;td&gt;Pseudorandom late match&lt;/td&gt;
&lt;td&gt;120.256 ± 7.345 µs&lt;/td&gt;
&lt;td&gt;5.145 ± 0.267 µs&lt;/td&gt;
&lt;td&gt;132.655 ± 6.025 µs&lt;/td&gt;
&lt;td&gt;175.052 ± 8.051 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;Alternating candidates, late mismatch&lt;/td&gt;
&lt;td&gt;113.756 ± 10.486 µs&lt;/td&gt;
&lt;td&gt;7.339 ± 0.273 µs&lt;/td&gt;
&lt;td&gt;7.382 ± 0.476 µs&lt;/td&gt;
&lt;td&gt;23.617 ± 0.225 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;td&gt;Alternating candidates, late mismatch&lt;/td&gt;
&lt;td&gt;1,728.590 ± 66.428 µs&lt;/td&gt;
&lt;td&gt;122.848 ± 5.355 µs&lt;/td&gt;
&lt;td&gt;106.727 ± 6.830 µs&lt;/td&gt;
&lt;td&gt;378.960 ± 8.429 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the pseudorandom late match, &lt;code&gt;IndexOf&lt;/code&gt; had the lowest mean among the four&lt;br&gt;
methods. KMP and BMH were slower than the simple loop with table preparation&lt;br&gt;
included. We did not measure searches with reused tables, so we have not&lt;br&gt;
isolated how much of the difference comes from preprocessing versus searching.&lt;br&gt;
For the 65,536-element adversarial fixture, KMP's mean was approximately 13%&lt;br&gt;
lower than &lt;code&gt;IndexOf&lt;/code&gt;'s: 106.727 versus 122.848 µs. At length 4,096, their means&lt;br&gt;
were effectively similar relative to the dispersion. BMH was slower than&lt;br&gt;
&lt;code&gt;IndexOf&lt;/code&gt; in all four measured cases.&lt;/p&gt;

&lt;p&gt;This illustrates why the answer depends on the algorithm, input, and treatment&lt;br&gt;
of preprocessing. It is not a universal ranking: these are teaching&lt;br&gt;
implementations, and BMH uses &lt;code&gt;Dictionary&amp;lt;char, int&amp;gt;&lt;/code&gt;, not a specialized&lt;br&gt;
low-level table. &lt;code&gt;MemoryDiagnoser&lt;/code&gt; also recorded per-call allocations: KMP&lt;br&gt;
allocated 88 bytes for the 16-element needle and 280 bytes for the 64-element&lt;br&gt;
needle; BMH allocated 472 and 1,552 bytes, respectively. Reusing a preprocessed&lt;br&gt;
table would change the comparison and was not measured here.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reproducing the two selected scenarios
&lt;/h2&gt;

&lt;p&gt;To reproduce the experiment without accessing the article's repository,&lt;br&gt;
create a console project using the .NET 10 SDK. Runtime version &lt;strong&gt;10.0.12&lt;/strong&gt;&lt;br&gt;
must be installed because roll-forward will be disabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new console &lt;span class="nt"&gt;-n&lt;/span&gt; SubstringBenchmark &lt;span class="nt"&gt;--framework&lt;/span&gt; net10.0
&lt;span class="nb"&gt;cd &lt;/span&gt;SubstringBenchmark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;SubstringBenchmark.csproj&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net10.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RuntimeFrameworkVersion&amp;gt;&lt;/span&gt;10.0.12&lt;span class="nt"&gt;&amp;lt;/RuntimeFrameworkVersion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RollForward&amp;gt;&lt;/span&gt;Disable&lt;span class="nt"&gt;&amp;lt;/RollForward&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ImplicitUsings&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/ImplicitUsings&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"BenchmarkDotNet"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"0.15.8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the following structure in &lt;code&gt;Program.cs&lt;/code&gt;. &lt;strong&gt;Inside the class, at the marked&lt;br&gt;
location, copy the six methods already shown in this article:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;SearchNaive&lt;/code&gt;, &lt;code&gt;SearchRuntime&lt;/code&gt;, &lt;code&gt;CreateOrdinaryHaystack&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;CreateAlternatingNeedleWithLateMismatch&lt;/code&gt;, &lt;code&gt;SearchKnuthMorrisPratt&lt;/code&gt;, and&lt;br&gt;
&lt;code&gt;SearchBoyerMooreHorspool&lt;/code&gt;. The four &lt;code&gt;[Benchmark]&lt;/code&gt; wrappers are already included&lt;br&gt;
below; do not copy them again. This avoids duplicating the implementations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;BenchmarkDotNet.Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;BenchmarkDotNet.Running&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SubstringSearchBenchmarks&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MediumRunJob&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MemoryDiagnoser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;DisassemblyDiagnoser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubstringSearchBenchmarks&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;GlobalSetup&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CreateOrdinaryHaystack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HaystackLength&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefghabcdefgh"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;[..&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HaystackLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
                    &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="n"&gt;_needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CreateAlternatingNeedleWithLateMismatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
            &lt;span class="nf"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unexpected setup result."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;|=&lt;/span&gt; &lt;span class="m"&gt;3u&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0x33333333&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
                &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Inconsistent adversarial fixture."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Baseline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// Paste the six methods listed above here.&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--filter&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt; &lt;span class="nt"&gt;--artifacts&lt;/span&gt; artifacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reproduction selects two scenarios × two lengths × four methods,&lt;br&gt;
for &lt;strong&gt;16 MediumRun benchmarks&lt;/strong&gt;. Setup checks the results and adversarial&lt;br&gt;
arithmetic; it does not replace the historical 34,193-case exhaustive and&lt;br&gt;
generated-input validation described earlier. Tables and disassembly are&lt;br&gt;
written to &lt;code&gt;artifacts/results/&lt;/code&gt;. Assembly capture depends on the diagnoser's&lt;br&gt;
support for your system; another CPU or runtime may generate different&lt;br&gt;
instructions. Timings will also vary: reproducing the procedure does not&lt;br&gt;
guarantee reproducing the historical numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dotnet/runtime/blob/v10.0.12/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs" rel="noopener noreferrer"&gt;.NET 10.0.12 — &lt;code&gt;SpanHelpers.Char.cs&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html" rel="noopener noreferrer"&gt;Intel Intrinsics Guide&lt;/a&gt;, for the observed instructions: &lt;code&gt;_mm256_cmpeq_epi16&lt;/code&gt;, &lt;code&gt;_mm256_testz_si256&lt;/code&gt;, &lt;code&gt;_mm256_movemask_epi8&lt;/code&gt;, &lt;code&gt;_tzcnt_u32&lt;/code&gt;, and &lt;code&gt;_blsr_u32&lt;/code&gt;. These describe equivalent semantics, not C/C++ calls made by the C# code.&lt;/li&gt;
&lt;li&gt;Knuth, Morris, and Pratt, &lt;a href="https://doi.org/10.1137/0206024" rel="noopener noreferrer"&gt;“Fast Pattern Matching in Strings”&lt;/a&gt;, &lt;em&gt;SIAM Journal on Computing&lt;/em&gt; 6(2), 1977.&lt;/li&gt;
&lt;li&gt;Boyer and Moore, &lt;a href="https://doi.org/10.1145/359842.359859" rel="noopener noreferrer"&gt;“A Fast String Searching Algorithm”&lt;/a&gt;, &lt;em&gt;Communications of the ACM&lt;/em&gt; 20(10), 1977.&lt;/li&gt;
&lt;li&gt;Horspool, &lt;a href="https://doi.org/10.1002/spe.4380100608" rel="noopener noreferrer"&gt;“Practical fast searching in strings”&lt;/a&gt;, &lt;em&gt;Software: Practice and Experience&lt;/em&gt; 10(6), 1980. The compared implementation is Boyer–Moore–Horspool, not the full Boyer–Moore algorithm.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/simd" rel="noopener noreferrer"&gt;SIMD and hardware intrinsics in .NET&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.memoryextensions.indexof?view=net-10.0" rel="noopener noreferrer"&gt;&lt;code&gt;MemoryExtensions.IndexOf&lt;/code&gt; API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>performance</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Como ReadOnlySpan&lt;char&gt;.IndexOf encontra uma substring com SIMD</title>
      <dc:creator>Pedro Sakuma Travi</dc:creator>
      <pubDate>Sun, 18 Oct 2026 22:36:25 +0000</pubDate>
      <link>https://dev.to/pedrosakuma/como-readonlyspanindexof-encontra-uma-substring-com-simd-2jg1</link>
      <guid>https://dev.to/pedrosakuma/como-readonlyspanindexof-encontra-uma-substring-com-simd-2jg1</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/pedrosakuma/how-readonlyspanindexof-finds-a-substring-with-simd-2i2d"&gt;Read in English&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Este artigo acompanha a sequência de ideias do vídeo: o vídeo anima os estados;&lt;br&gt;
aqui podemos pausar em cada diagrama e consultar o código e o assembly.&lt;br&gt;
O walkthrough usa o mesmo exemplo didático, separado das entradas medidas.&lt;br&gt;
O número do gancho vem de um MediumRun selecionado, mas ainda se refere a uma&lt;br&gt;
máquina e a um cenário específicos. A comparação com KMP e BMH ao final é&lt;br&gt;
material complementar, fora da montagem principal do vídeo.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. O resultado que intriga
&lt;/h2&gt;

&lt;p&gt;Uma busca escrita com um loop parece ter menos custo que uma chamada a uma API&lt;br&gt;
de nível mais alto. Para testar essa intuição, comparamos duas implementações&lt;br&gt;
que procuram &lt;strong&gt;a primeira ocorrência&lt;/strong&gt; de uma substring e retornam seu índice,&lt;br&gt;
ou &lt;code&gt;-1&lt;/code&gt; quando não há match.&lt;/p&gt;

&lt;p&gt;Este é o resultado do caso usado como gancho: uma substring de 16 &lt;code&gt;char&lt;/code&gt;s&lt;br&gt;
inserida no fim de um texto pseudoaleatório de 65.536 &lt;code&gt;char&lt;/code&gt;s.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementação&lt;/th&gt;
&lt;th&gt;Média por busca&lt;/th&gt;
&lt;th&gt;Desvio padrão&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Loop ingênuo&lt;/td&gt;
&lt;td&gt;134,935 µs&lt;/td&gt;
&lt;td&gt;24,518 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;.IndexOf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5,653 µs&lt;/td&gt;
&lt;td&gt;389 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neste cenário e neste host, a média do loop foi cerca de &lt;strong&gt;23,9×&lt;/strong&gt; a média de&lt;br&gt;
&lt;code&gt;IndexOf&lt;/code&gt;. Isso não é uma previsão para qualquer string, CPU ou versão do&lt;br&gt;
runtime. Mais adiante veremos que o loop e o runtime também usam algoritmos&lt;br&gt;
diferentes; o benchmark não isola somente o custo da abstração.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Os dois códigos comparados
&lt;/h2&gt;

&lt;p&gt;O harness usa BenchmarkDotNet; os métodos, entradas, configuração e instruções&lt;br&gt;
para montar uma reprodução estão neste artigo. Cada operação&lt;br&gt;
recebe um &lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;&lt;/code&gt; para o texto e outro para a needle. A comparação&lt;br&gt;
é ordinal: compara unidades &lt;code&gt;char&lt;/code&gt; UTF-16 sem regras culturais. As duas&lt;br&gt;
implementações têm o mesmo contrato: retornar o índice da primeira ocorrência,&lt;br&gt;
ou &lt;code&gt;-1&lt;/code&gt; se não houver match. Em .NET, cada &lt;code&gt;char&lt;/code&gt; representa uma unidade de&lt;br&gt;
código UTF-16, e não necessariamente um grafema percebido como um caractere.&lt;/p&gt;

&lt;p&gt;O baseline implementa busca ingênua (&lt;em&gt;naive/brute-force&lt;/em&gt;): tenta cada posição&lt;br&gt;
e compara a needle caractere a caractere. O segundo método é a chamada à API&lt;br&gt;
do runtime. Estes são os dois métodos que conduzem a explicação principal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
               &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E o BenchmarkDotNet mede os resultados desses métodos por meio destes&lt;br&gt;
wrappers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Baseline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No primeiro wrapper, portanto, medimos o loop ingênuo mostrado acima. No&lt;br&gt;
segundo, medimos &lt;code&gt;ReadOnlySpan&amp;lt;char&amp;gt;.IndexOf&lt;/code&gt; com comparação ordinal. Para&lt;br&gt;
explicar o caminho observado no segundo método, usamos a implementação do&lt;br&gt;
runtime .NET 10.0.12: &lt;a href="https://github.com/dotnet/runtime/blob/v10.0.12/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs" rel="noopener noreferrer"&gt;&lt;code&gt;SpanHelpers.IndexOf(ref char, int, ref char, int)&lt;/code&gt; em&lt;br&gt;
&lt;code&gt;SpanHelpers.Char.cs&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
Nesse host, o método usa filtro de candidatos vetorizado e confirma os&lt;br&gt;
candidatos comparando a substring completa; não é um algoritmo implementado&lt;br&gt;
por nós nem uma garantia de que outras versões ou CPUs escolherão o mesmo&lt;br&gt;
caminho.&lt;/p&gt;

&lt;p&gt;Antes de cronometrar, o &lt;code&gt;GlobalSetup&lt;/code&gt; executa os quatro métodos para cada&lt;br&gt;
entrada e exige que todos retornem o resultado esperado. Assim, por exemplo,&lt;br&gt;
um cenário chamado “miss” não entra no benchmark se uma das buscas encontrar&lt;br&gt;
uma ocorrência acidental. A validação é feita antes das medições:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;naive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomEarlyMatch&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMiddleMatch&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixLate&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMissing&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixMissing&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;naive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;VerifyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O benchmark compara uma busca escalar caractere a caractere com a&lt;br&gt;
implementação otimizada do runtime; não isola somente o custo de chamar uma&lt;br&gt;
API. A pergunta, portanto, é qual trabalho os dois algoritmos fazem, não se&lt;br&gt;
uma sintaxe ou uma abstração é intrinsecamente mais rápida. Ao final, incluímos&lt;br&gt;
KMP e Boyer–Moore–Horspool como uma resposta complementar à pergunta sobre&lt;br&gt;
outros algoritmos; eles não substituem o fio principal do vídeo.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Entradas: o que foi testado?
&lt;/h2&gt;

&lt;p&gt;O harness combina &lt;strong&gt;sete cenários&lt;/strong&gt; com textos de &lt;strong&gt;4.096 e 65.536 &lt;code&gt;char&lt;/code&gt;s&lt;/strong&gt;.&lt;br&gt;
As entradas são construídas uma vez no setup, fora da região cronometrada.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cenário&lt;/th&gt;
&lt;th&gt;Texto e needle&lt;/th&gt;
&lt;th&gt;Match esperado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomEarlyMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Texto pseudoaleatório no alfabeto &lt;code&gt;a&lt;/code&gt;–&lt;code&gt;h&lt;/code&gt;; needle &lt;code&gt;abcdefghabcdefgh&lt;/code&gt; inserida no índice 0.&lt;/td&gt;
&lt;td&gt;índice 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomMiddleMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mesmo gerador e needle, inserida no meio do texto.&lt;/td&gt;
&lt;td&gt;índice &lt;code&gt;HaystackLength / 2&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomLateMatch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mesmo gerador e needle, inserida nos últimos 16 &lt;code&gt;char&lt;/code&gt;s.&lt;/td&gt;
&lt;td&gt;índice &lt;code&gt;HaystackLength - 16&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RandomMissing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Texto do mesmo gerador/alfabeto, sem inserir a needle.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-1&lt;/code&gt;, conferido no setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RepeatedPrefixMissing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Texto formado só por &lt;code&gt;a&lt;/code&gt;; needle &lt;code&gt;aaaaaaab&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RepeatedPrefixLate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Texto formado só por &lt;code&gt;a&lt;/code&gt;, com &lt;code&gt;aaaaaaab&lt;/code&gt; substituindo os oito &lt;code&gt;char&lt;/code&gt;s finais.&lt;/td&gt;
&lt;td&gt;índice &lt;code&gt;HaystackLength - 8&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RepeatedAlternatingLateFalse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Texto &lt;code&gt;ab&lt;/code&gt; alternado; needle de 64 &lt;code&gt;char&lt;/code&gt;s alternados nos primeiros 63 e terminando em &lt;code&gt;a&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-1&lt;/code&gt;; falsos candidatos falham no último &lt;code&gt;char&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O gerador pseudoaleatório é determinístico: começa em &lt;code&gt;0xC0FFEE&lt;/code&gt; e, para cada&lt;br&gt;
posição, atualiza um estado de 32 bits com&lt;br&gt;
&lt;code&gt;state = state * 1664525 + 1013904223&lt;/code&gt;; os três bits mais altos selecionam um&lt;br&gt;
dos oito caracteres &lt;code&gt;a&lt;/code&gt;–&lt;code&gt;h&lt;/code&gt;. Este é o código usado para gerar o texto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;CreateOrdinaryHaystack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;alphabet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefgh"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0xC0FFEE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;1664525&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1013904223&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alphabet&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;29&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nos cenários de match, o trecho correspondente é substituído pela needle.&lt;br&gt;
Para o caso tardio usado no gancho, o código equivale a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefghabcdefgh"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CreateOrdinaryHaystack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;matchIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// RandomLateMatch&lt;/span&gt;
&lt;span class="n"&gt;haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[..&lt;/span&gt;&lt;span class="n"&gt;matchIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;
    &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;matchIndex&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)..];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No cenário ausente, o mesmo alfabeto é mantido, evitando um miss trivial por&lt;br&gt;
caracteres impossíveis: o setup confirma que a needle completa realmente não&lt;br&gt;
aparece.&lt;/p&gt;
&lt;h3&gt;
  
  
  O cenário adversarial do benchmark
&lt;/h3&gt;

&lt;p&gt;Este caso medido é diferente tanto do gancho quanto do exemplo didático das&lt;br&gt;
seções 6–7. O texto alterna &lt;code&gt;a&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt;; a needle alterna também, mas seu último&lt;br&gt;
&lt;code&gt;char&lt;/code&gt; é alterado para &lt;code&gt;a&lt;/code&gt;. A função do benchmark constrói essa needle assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;CreateAlternatingNeedleWithLateMismatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[^&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O runtime compara o primeiro &lt;code&gt;char&lt;/code&gt; (&lt;code&gt;a&lt;/code&gt;) e procura, de trás para a frente, o&lt;br&gt;
último &lt;code&gt;char&lt;/code&gt; da needle que difere dele. Como os &lt;code&gt;char&lt;/code&gt;s 63 e 62 são &lt;code&gt;a&lt;/code&gt;, esse&lt;br&gt;
ponto é o índice 61, que contém &lt;code&gt;b&lt;/code&gt;. No texto alternado, ambos os filtros&lt;br&gt;
passam para todo início par: &lt;code&gt;haystack[i] == 'a'&lt;/code&gt; e&lt;br&gt;
&lt;code&gt;haystack[i + 61] == 'b'&lt;/code&gt;. A substring inteira, porém, falha só no último&lt;br&gt;
&lt;code&gt;char&lt;/code&gt;, porque o texto contém &lt;code&gt;b&lt;/code&gt; no índice relativo 63 e a needle contém &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tamanho do texto&lt;/th&gt;
&lt;th&gt;Candidatos falsos esperados&lt;/th&gt;
&lt;th&gt;Resultado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4.096&lt;/td&gt;
&lt;td&gt;2.017&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65.536&lt;/td&gt;
&lt;td&gt;32.737&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O setup calcula e confere a compactação conceitual de um bit por lane&lt;br&gt;
(&lt;code&gt;0x5555&lt;/code&gt;), a máscara esperada após extrair um bit por byte (&lt;code&gt;0x33333333&lt;/code&gt;) e a&lt;br&gt;
contagem total de candidatos. A primeira compactação não é o vetor de&lt;br&gt;
comparação nem uma variável intermediária do runtime: cada lane aprovada&lt;br&gt;
contém &lt;code&gt;FFFF&lt;/code&gt;. O cálculo é uma validação escalar do fixture, não uma leitura&lt;br&gt;
dos registradores do runtime.&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Medição e resultados
&lt;/h2&gt;

&lt;p&gt;Usamos BenchmarkDotNet 0.15.8, build Release, .NET 10.0.12&lt;br&gt;
(SDK 10.0.401), Linux Ubuntu 24.04.4 x64 e AMD EPYC 7763 a 2,45 GHz. O&lt;br&gt;
BenchmarkDotNet expôs 1 CPU ao processo. O host disponibilizou AVX2 e BMI1; a&lt;br&gt;
captura do assembly usada no walkthrough é desse ambiente.&lt;/p&gt;

&lt;p&gt;O fixture combina dois tamanhos e sete cenários. Cada combinação é executada&lt;br&gt;
pelos quatro métodos, totalizando 56 combinações método/caso na matriz ShortRun.&lt;br&gt;
Os atributos que configuram os benchmarks são:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ShortRunJob&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MemoryDiagnoser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;DisassemblyDiagnoser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubstringSearchBenchmarks&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomEarlyMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMiddleMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomMissing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixMissing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedPrefixLate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A matriz ampla usou &lt;code&gt;ShortRun&lt;/code&gt; (3 aquecimentos, 3 medições). Para o match&lt;br&gt;
tardio e o caso adversarial, também rodamos &lt;code&gt;MediumRun&lt;/code&gt; (10 aquecimentos, 15&lt;br&gt;
medições, 2 processos por benchmark). A tabela mostra as médias e desvios&lt;br&gt;
padrão do MediumRun; as unidades foram convertidas para facilitar a leitura:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Entrada&lt;/th&gt;
&lt;th&gt;Caso&lt;/th&gt;
&lt;th&gt;Ingênua: média ± desvio padrão&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;IndexOf&lt;/code&gt;: média ± desvio padrão&lt;/th&gt;
&lt;th&gt;Razão das médias&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4.096&lt;/td&gt;
&lt;td&gt;Match no fim, texto pseudoaleatório&lt;/td&gt;
&lt;td&gt;3,443 ± 0,238 µs&lt;/td&gt;
&lt;td&gt;323 ± 15 ns&lt;/td&gt;
&lt;td&gt;10,7×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65.536&lt;/td&gt;
&lt;td&gt;Match no fim, texto pseudoaleatório&lt;/td&gt;
&lt;td&gt;134,935 ± 24,518 µs&lt;/td&gt;
&lt;td&gt;5,653 ± 389 ns&lt;/td&gt;
&lt;td&gt;23,9×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4.096&lt;/td&gt;
&lt;td&gt;Muitos candidatos, falha no último &lt;code&gt;char&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;149,369 ± 57,317 µs&lt;/td&gt;
&lt;td&gt;7,645 ± 390 ns&lt;/td&gt;
&lt;td&gt;19,5×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65.536&lt;/td&gt;
&lt;td&gt;Muitos candidatos, falha no último &lt;code&gt;char&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1,925 ± 0,202 ms&lt;/td&gt;
&lt;td&gt;129,186 ± 7,864 µs&lt;/td&gt;
&lt;td&gt;14,9×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O cenário adversarial tem dispersão considerável, especialmente no loop&lt;br&gt;
ingênuo; por isso mostramos a dispersão junto à média e evitamos tratá-lo como&lt;br&gt;
um caso típico. Também não atribuímos todo o ganho a SIMD: o baseline percorre&lt;br&gt;
posições em C#, enquanto &lt;code&gt;IndexOf&lt;/code&gt; usa outro algoritmo, além de instruções&lt;br&gt;
vetoriais. O dado sustenta uma conclusão delimitada: &lt;strong&gt;neste host, para estas&lt;br&gt;
entradas, a implementação do runtime foi mais rápida&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Na execução original, a validação comparou &lt;code&gt;IndexOf&lt;/code&gt;, KMP e BMH com o baseline ingênuo em&lt;br&gt;
34.193 casos determinísticos: todas as strings binárias de até 8 &lt;code&gt;char&lt;/code&gt;s e&lt;br&gt;
needles de até 5, mais 2.000 entradas geradas com caracteres diversos,&lt;br&gt;
incluindo NUL e unidades surrogate. Ele inclui needle vazia, needle maior que o&lt;br&gt;
texto, matches injetados e misses.&lt;/p&gt;

&lt;p&gt;Na captura original, adicionar &lt;code&gt;--job Medium&lt;/code&gt; à classe com &lt;code&gt;[ShortRunJob]&lt;/code&gt;&lt;br&gt;
executou os dois jobs; os números reportados são das linhas &lt;code&gt;Job=MediumRun&lt;/code&gt;.&lt;br&gt;
A reprodução ao final usa apenas &lt;code&gt;[MediumRunJob]&lt;/code&gt;, para executar os dois&lt;br&gt;
cenários selecionados sem repetir a matriz ShortRun.&lt;/p&gt;

&lt;p&gt;O projeto fixa &lt;code&gt;RuntimeFrameworkVersion&lt;/code&gt; em &lt;code&gt;10.0.12&lt;/code&gt; e desativa roll-forward.&lt;br&gt;
Sua configuração e os comandos estão na seção de reprodução, sem depender&lt;br&gt;
de arquivos externos ao artigo.&lt;/p&gt;
&lt;h2&gt;
  
  
  5. A ideia de SIMD
&lt;/h2&gt;

&lt;p&gt;SIMD aplica uma mesma operação a vários elementos de dados. No caminho&lt;br&gt;
observado, os elementos são chars UTF-16 de 16 bits. Um vetor de 256 bits pode&lt;br&gt;
conter 16 lanes &lt;code&gt;char&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane:  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
char: [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso não significa que toda a busca acontece numa única instrução. O vetor&lt;br&gt;
seleciona vários inícios possíveis para verificação; o caminho ainda percorre&lt;br&gt;
blocos, processa máscaras e confirma a substring completa.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Encontrar candidatos
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Uma entrada pequena para acompanhar as contas
&lt;/h3&gt;

&lt;p&gt;Usamos a mesma fixture didática do vídeo: uma needle de &lt;strong&gt;64 unidades UTF-16&lt;/strong&gt;,&lt;br&gt;
inserida no índice &lt;strong&gt;6&lt;/strong&gt; de um texto de &lt;strong&gt;79 unidades&lt;/strong&gt;, preenchido com &lt;code&gt;x&lt;/code&gt;&lt;br&gt;
fora desse trecho. A needle alterna &lt;code&gt;a&lt;/code&gt; e &lt;code&gt;b&lt;/code&gt;, exceto pelo último elemento,&lt;br&gt;
que é &lt;code&gt;a&lt;/code&gt;. Este código reproduz a entrada; não é um cenário cronometrado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;63&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;79&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'x'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;CopyTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;StringComparison&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// result == 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Há &lt;code&gt;79 - 64 + 1 = 16&lt;/code&gt; inícios válidos, de 0 a 15: cabem em uma janela de&lt;br&gt;
16 lanes. O objetivo é explicar o caminho até um match, não representar os&lt;br&gt;
dados responsáveis pelos tempos do benchmark.&lt;/p&gt;
&lt;h3&gt;
  
  
  Escolher dois pontos da needle
&lt;/h3&gt;

&lt;p&gt;O primeiro ponto é &lt;code&gt;value[0] == 'a'&lt;/code&gt;. Para o segundo, o runtime procura de trás&lt;br&gt;
para a frente um elemento diferente do primeiro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;posição na needle:   0    1   ...   61   62   63
valor:               a    b   ...    b    a    a
                     ^              ^
                    ch1            ch2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As posições 63 e 62 contêm &lt;code&gt;a&lt;/code&gt;; a posição 61 contém &lt;code&gt;b&lt;/code&gt;. Portanto,&lt;br&gt;
&lt;code&gt;ch1ch2Distance = 61&lt;/code&gt;. &lt;strong&gt;&lt;code&gt;ch2&lt;/code&gt; não significa necessariamente o último&lt;br&gt;
caractere&lt;/strong&gt;, mas o segundo ponto escolhido para filtrar.&lt;/p&gt;

&lt;p&gt;Os valores são replicados em vetores: &lt;code&gt;ch1&lt;/code&gt; contém 16 cópias de &lt;code&gt;a&lt;/code&gt;, e &lt;code&gt;ch2&lt;/code&gt;,&lt;br&gt;
16 cópias de &lt;code&gt;b&lt;/code&gt;. Para um início &lt;code&gt;i&lt;/code&gt;, perguntamos se &lt;code&gt;text[i] == 'a'&lt;/code&gt; e&lt;br&gt;
&lt;code&gt;text[i + 61] == 'b'&lt;/code&gt;. Se alguma condição falhar, esse início não pode ser&lt;br&gt;
uma ocorrência completa.&lt;/p&gt;
&lt;h3&gt;
  
  
  Offset, lane e endereço não são a mesma coisa
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;offset&lt;/code&gt; é o início da janela de candidatos no texto. A lane &lt;code&gt;j&lt;/code&gt; representa o&lt;br&gt;
início &lt;code&gt;offset + j&lt;/code&gt;. Nesta janela, &lt;code&gt;offset = 0&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lane&lt;/th&gt;
&lt;th&gt;Início candidato&lt;/th&gt;
&lt;th&gt;Primeiro ponto&lt;/th&gt;
&lt;th&gt;Segundo ponto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 + 6 = 6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[6] == 'a'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;text[0 + 6 + 61]&lt;/code&gt;, isto é, &lt;code&gt;text[67] == 'b'&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 + 8 = 8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[8] == 'a'&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;text[0 + 8 + 61]&lt;/code&gt;, isto é, &lt;code&gt;text[69] == 'b'&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O recorte do runtime executa primeiro a comparação do segundo ponto, depois&lt;br&gt;
a do primeiro e finalmente o AND. Abaixo, os tipos das variáveis foram&lt;br&gt;
omitidos e as quebras ajustadas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;cmpCh2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ch2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;searchSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nuint&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ch1ch2Distance&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="n"&gt;cmpCh1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ch1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vector256&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;searchSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nuint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;cmpAnd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmpCh1&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cmpCh2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AsByte&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste ramo, &lt;code&gt;searchSpace&lt;/code&gt; referencia elementos &lt;code&gt;ushort&lt;/code&gt;: os deslocamentos&lt;br&gt;
das cargas são em unidades UTF-16 de 16 bits, &lt;strong&gt;não em bytes&lt;/strong&gt;. As cargas leem&lt;br&gt;
&lt;code&gt;text[61..77]&lt;/code&gt; e &lt;code&gt;text[0..16]&lt;/code&gt;, usando limites finais exclusivos. Somar a&lt;br&gt;
distância na segunda carga mantém os dois pontos de cada candidato na mesma&lt;br&gt;
lane: a lane 6 relaciona &lt;code&gt;text[6]&lt;/code&gt; e &lt;code&gt;text[67]&lt;/code&gt;, não elementos de inícios&lt;br&gt;
diferentes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Comparar e combinar as 16 lanes
&lt;/h3&gt;

&lt;p&gt;Cada igualdade produz &lt;code&gt;FFFF&lt;/code&gt; quando verdadeira e &lt;code&gt;0000&lt;/code&gt; quando falsa.&lt;br&gt;
Na tabela, &lt;strong&gt;1 e 0 são abreviações desses valores de 16 bits&lt;/strong&gt;, não os&lt;br&gt;
valores inteiros gravados no vetor. A operação continua sendo &lt;code&gt;==&lt;/code&gt; em todas&lt;br&gt;
as lanes, inclusive quando seu resultado é falso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane:        0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
text[i+61]:  b  a  b  a  b  a  b  a  a  x  x  x  x  x  x  x
ch2:         b  b  b  b  b  b  b  b  b  b  b  b  b  b  b  b
cmpCh2:      1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0

text[i]:     x  x  x  x  x  x  a  b  a  b  a  b  a  b  a  b
ch1:         a  a  a  a  a  a  a  a  a  a  a  a  a  a  a  a
cmpCh1:      0  0  0  0  0  0  1  0  1  0  1  0  1  0  1  0

cmpCh1:      0  0  0  0  0  0  1  0  1  0  1  0  1  0  1  0
cmpCh2:      1  0  1  0  1  0  1  0  0  0  0  0  0  0  0  0
AND:         0  0  0  0  0  0  1  0  0  0  0  0  0  0  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lane 6 passa nas duas igualdades: &lt;code&gt;a == a&lt;/code&gt; e &lt;code&gt;b == b&lt;/code&gt;. Na lane 8, a&lt;br&gt;
primeira passa (&lt;code&gt;text[8] == 'a'&lt;/code&gt;), mas a segunda falha: &lt;code&gt;text[69]&lt;/code&gt; contém &lt;code&gt;a&lt;/code&gt;,&lt;br&gt;
e &lt;code&gt;a == b&lt;/code&gt; é falso. O AND mantém apenas a lane 6.&lt;/p&gt;

&lt;p&gt;As comparações SIMD processam as lanes em paralelo; a leitura das colunas&lt;br&gt;
6 e 8 apenas explica seus resultados. &lt;code&gt;AsByte()&lt;/code&gt; reinterpreta os mesmos bits&lt;br&gt;
como bytes, sem converter &lt;code&gt;FFFF&lt;/code&gt; no número 1.&lt;/p&gt;

&lt;p&gt;O teste &lt;code&gt;cmpAnd != Vector256&amp;lt;byte&amp;gt;.Zero&lt;/code&gt; produz uma decisão escalar: &lt;strong&gt;há&lt;br&gt;
candidato&lt;/strong&gt;. Ele não informa o índice nem confirma a substring. No assembly&lt;br&gt;
capturado do benchmark, &lt;code&gt;vpcmpeqw&lt;/code&gt;, &lt;code&gt;vpand&lt;/code&gt; e &lt;code&gt;vptest&lt;/code&gt; correspondem às&lt;br&gt;
comparações, combinação e teste. Essa evidência é do host documentado, não&lt;br&gt;
uma garantia de tradução para qualquer máquina.&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Localizar e confirmar o candidato
&lt;/h2&gt;
&lt;h3&gt;
  
  
  De uma lane de 16 bits a dois bits na máscara
&lt;/h3&gt;

&lt;p&gt;O runtime extrai o bit mais significativo de cada byte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmpAnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractMostSignificantBits&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;São 16 elementos de 16 bits, reinterpretados como 32 bytes. Na lane 6, o&lt;br&gt;
resultado verdadeiro contém dois bytes &lt;code&gt;FF&lt;/code&gt;; nos demais elementos, ambos&lt;br&gt;
os bytes são &lt;code&gt;00&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane 6:              FFFF
bytes no vetor:      byte 12 = FF     byte 13 = FF
bits de cada byte:            11111111         11111111
bit mais significativo:      1                1
posição na máscara:          12               13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lane 0 corresponde aos bytes e bits 0–1; a lane 1, a 2–3; a lane 6, a&lt;br&gt;
12–13. Logo, a máscara efetivamente extraída é &lt;strong&gt;&lt;code&gt;0x00003000&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;índice:  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
bit:     0  0  0  0  0  0  0  0  0  0  0  0  1  1  0  0
índice: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
bit:     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui os índices crescem &lt;strong&gt;da esquerda para a direita&lt;/strong&gt;, como no vídeo.&lt;br&gt;
Não é a escrita binária numérica usual: o bit menos significativo está à&lt;br&gt;
esquerda. Cada bit representa um byte do vetor de resultados, não diretamente&lt;br&gt;
um caractere. No assembly observado, a extração corresponde a &lt;code&gt;vpmovmskb&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Contar, converter e somar o offset
&lt;/h3&gt;

&lt;p&gt;O próximo cálculo no código é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;nint&lt;/span&gt; &lt;span class="n"&gt;charPos&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nint&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrailingZeroCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ushort&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A contagem começa no bit 0 e encontra 12 zeros antes do primeiro 1. Portanto,&lt;br&gt;
&lt;code&gt;TrailingZeroCount(0x00003000) = 12&lt;/code&gt;. Dividir por &lt;code&gt;sizeof(ushort)&lt;/code&gt;, que vale 2,&lt;br&gt;
converte a posição do byte representado pelo bit em posição de elemento:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;primeiro bit marcado: 12
charPos:              12 / 2 = 6
início no texto:      offset + charPos = 0 + 6 = 6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;charPos&lt;/code&gt; é relativo à janela; o índice no texto inclui &lt;code&gt;offset&lt;/code&gt;. Os valores&lt;br&gt;
coincidem neste exemplo porque o offset é zero. No assembly capturado, a&lt;br&gt;
contagem corresponde a &lt;code&gt;tzcnt&lt;/code&gt; e a divisão por dois a um deslocamento de bits.&lt;/p&gt;
&lt;h3&gt;
  
  
  Confirmar a sequência inteira
&lt;/h3&gt;

&lt;p&gt;Só agora verificamos a igualdade completa. O recorte do runtime é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;searchSpace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;charPos&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;Unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;nuint&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;valueLength&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;charPos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O teste &lt;code&gt;valueLength == 2&lt;/code&gt; é falso, pois nossa needle tem 64 elementos.&lt;br&gt;
&lt;code&gt;SequenceEqual&lt;/code&gt; compara seus 128 bytes com os do trecho iniciado em&lt;br&gt;
&lt;code&gt;text[6]&lt;/code&gt;. Os intervalos abaixo têm limite final exclusivo:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trecho da needle&lt;/th&gt;
&lt;th&gt;Trecho correspondente do texto&lt;/th&gt;
&lt;th&gt;Igualdade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[0..16]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[6..22]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[16..32]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[22..38]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[32..48]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[38..54]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value[48..64]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text[54..70]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abababababababaa&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Os quatro pares são iguais: a chamada retorna &lt;code&gt;true&lt;/code&gt;, e o método retorna&lt;br&gt;
&lt;strong&gt;&lt;code&gt;offset + charPos = 6&lt;/code&gt;&lt;/strong&gt;. A tabela organiza os dados, não a ordem de&lt;br&gt;
execução das instruções. A confirmação também usa SIMD no assembly capturado&lt;br&gt;
para a needle desse tamanho no benchmark; não precisamos abrir sua&lt;br&gt;
implementação para entender seu papel na busca.&lt;/p&gt;

&lt;p&gt;Se a confirmação falhasse, o runtime limparia os dois bits do candidato e&lt;br&gt;
continuaria com o próximo par marcado, se ainda houvesse algum. Isso não&lt;br&gt;
acontece nesta fixture, que encontra o match.&lt;/p&gt;

&lt;p&gt;Podemos conferir a matemática sem ler registradores internos. Acrescente&lt;br&gt;
este trecho ao exemplo C# que constrói &lt;code&gt;text&lt;/code&gt; e &lt;code&gt;value&lt;/code&gt; na seção 6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;expectedMask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;expectedMask&lt;/span&gt; &lt;span class="p"&gt;|=&lt;/span&gt; &lt;span class="m"&gt;3u&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedMask&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0x00003000&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TrailingZeroCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedMask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ushort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;64&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;SequenceEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fixture didática inconsistente."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;expectedMask&lt;/code&gt; é um cálculo escalar de verificação, não a extração do vetor&lt;br&gt;
usado internamente por &lt;code&gt;IndexOf&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Confirmar, não presumir
&lt;/h2&gt;

&lt;p&gt;O exemplo didático tem uma ocorrência no índice 6. O cenário adversarial&lt;br&gt;
medido na seção 3 mantém a mesma needle, mas usa um texto inteiramente&lt;br&gt;
alternado, sem inserir a ocorrência. Nesse texto, todo início par passa nos&lt;br&gt;
dois pontos do filtro, mas a comparação completa falha no último elemento:&lt;br&gt;
o texto contém &lt;code&gt;b&lt;/code&gt;, enquanto a needle termina em &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Entrada&lt;/th&gt;
&lt;th&gt;Candidatos na primeira janela&lt;/th&gt;
&lt;th&gt;Máscara extraída por byte&lt;/th&gt;
&lt;th&gt;Resultado da busca&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Didática: 79 elementos, ocorrência inserida&lt;/td&gt;
&lt;td&gt;Apenas lane 6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x00003000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adversarial: texto &lt;code&gt;ab&lt;/code&gt; alternado&lt;/td&gt;
&lt;td&gt;Lanes 0, 2, 4, 6, 8, 10, 12 e 14&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x33333333&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No adversarial, poderíamos resumir as lanes aprovadas como &lt;code&gt;0x5555&lt;/code&gt;, usando&lt;br&gt;
um bit por lane. Essa é apenas uma representação conceitual; os resultados&lt;br&gt;
vetoriais são &lt;code&gt;FFFF/0000&lt;/code&gt;, e a variável &lt;code&gt;mask&lt;/code&gt; extraída contém dois bits&lt;br&gt;
marcados por candidato. Por exemplo, depois de rejeitar o início 0, limpar&lt;br&gt;
seus bits 0–1 muda a máscara de &lt;code&gt;0x33333333&lt;/code&gt; para &lt;code&gt;0x33333330&lt;/code&gt;. A próxima&lt;br&gt;
contagem dá 4; &lt;code&gt;4 / 2 = 2&lt;/code&gt; aponta ao candidato seguinte. No assembly observado,&lt;br&gt;
dois &lt;code&gt;blsr&lt;/code&gt; fazem a limpeza dos dois bits.&lt;/p&gt;

&lt;p&gt;No texto de 65.536 chars, há&lt;br&gt;
&lt;code&gt;((65.536 - 64) / 2) + 1 = 32.737&lt;/code&gt; inícios pares candidatos. Todos são falsos&lt;br&gt;
e falham no elemento final. A contagem refere-se às posições distintas que&lt;br&gt;
passam no filtro, não a uma medição de chamadas internas de &lt;code&gt;SequenceEqual&lt;/code&gt;;&lt;br&gt;
a última janela pode sobrepor posições já examinadas.&lt;/p&gt;

&lt;p&gt;O harness recalcula escalarmente, a partir do fixture, a máscara esperada do&lt;br&gt;
primeiro bloco e a contagem total de candidatos no setup, além de verificar&lt;br&gt;
que os quatro métodos retornam &lt;code&gt;-1&lt;/code&gt;. Isso valida os dados e o cálculo do caso,&lt;br&gt;
não lê registradores internos do runtime; essa ligação vem do código&lt;br&gt;
versionado e do assembly capturado. Os primeiros passos esperados são:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Máscara antes&lt;/th&gt;
&lt;th&gt;Zeros à direita&lt;/th&gt;
&lt;th&gt;Posição / 2&lt;/th&gt;
&lt;th&gt;Confirmação&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333333&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;falha no elemento relativo 63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333330&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;falha no elemento relativo 63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333300&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;falha no elemento relativo 63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x33333000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;falha no elemento relativo 63&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Por fim, o resultado de aproximadamente 24× da abertura pertence a uma&lt;br&gt;
terceira entrada: &lt;strong&gt;match tardio pseudoaleatório, com needle de 16 elementos&lt;br&gt;
e texto de 65.536&lt;/strong&gt;. Não é o resultado do adversarial nem da fixture didática.&lt;br&gt;
O exemplo explica o algoritmo; cada medição pertence à sua própria entrada.&lt;/p&gt;
&lt;h2&gt;
  
  
  9. Avançar, terminar e voltar ao resultado
&lt;/h2&gt;

&lt;p&gt;Depois de verificar um bloco, o algoritmo avança por uma largura vetorial. Se&lt;br&gt;
o próximo avanço ultrapassaria o último início que ainda cabe, o loop volta ao&lt;br&gt;
offset do último bloco completo, sobrepondo parte do bloco anterior para&lt;br&gt;
examinar as posições finais sem ler além da entrada. Entradas com menos de&lt;br&gt;
oito inícios possíveis não cabem no caminho vetorial de 128 bits deste host e&lt;br&gt;
seguem o caminho escalar. Os limites e branches exatos estão no código-fonte&lt;br&gt;
do runtime, não são inferidos apenas pelo nome da API.&lt;/p&gt;

&lt;p&gt;No assembly desta execução, o filtro usa AVX2: comparação de words, AND,&lt;br&gt;
teste de vetor e extração de máscara; &lt;code&gt;tzcnt&lt;/code&gt; e &lt;code&gt;blsr&lt;/code&gt; pertencem a BMI1, e a&lt;br&gt;
confirmação também usa comparações vetoriais de bytes. Essa observação vale&lt;br&gt;
para a versão do runtime, JIT e CPU registrados; outras máquinas podem usar&lt;br&gt;
outro caminho. O número inicial mostra que neste experimento o runtime&lt;br&gt;
encontra candidatos em paralelo e supera a busca escalar caractere a&lt;br&gt;
caractere. Não demonstra que menos abstração sempre custa mais ou que SIMD&lt;br&gt;
sempre vence. Para interpretar qualquer benchmark, precisamos saber quais&lt;br&gt;
dados e qual algoritmo foram medidos.&lt;/p&gt;
&lt;h3&gt;
  
  
  Relação com as instruções observadas
&lt;/h3&gt;

&lt;p&gt;Esta tabela resume a desassemblagem capturada no host Linux x64 / EPYC 7763,&lt;br&gt;
.NET 10.0.12, AVX2 e BMI1. Não é uma promessa de tradução um-para-um para&lt;br&gt;
outras CPUs ou versões, nem uma nova captura da fixture didática:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operação&lt;/th&gt;
&lt;th&gt;Instruções observadas&lt;/th&gt;
&lt;th&gt;Papel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Replicar &lt;code&gt;ch1&lt;/code&gt; e &lt;code&gt;ch2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;vmovd&lt;/code&gt;, &lt;code&gt;vpbroadcastw&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Repetir o valor em 16 lanes de 16 bits.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Vector256.Equals&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vpcmpeqw&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Produzir &lt;code&gt;FFFF&lt;/code&gt; ou &lt;code&gt;0000&lt;/code&gt; por lane.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AND dos resultados&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vpand&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manter quem passou nas duas comparações.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Teste do vetor contra zero&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;vptest&lt;/code&gt; e salto&lt;/td&gt;
&lt;td&gt;Evitar extrair máscara quando não há candidato.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ExtractMostSignificantBits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vpmovmskb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extrair 32 bits, um por byte.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TrailingZeroCount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tzcnt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Localizar o primeiro bit marcado.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Divisão por 2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;shr ..., 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Converter posição de byte para elemento UTF-16.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limpar dois bits do candidato rejeitado&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;blsr&lt;/code&gt;, duas vezes&lt;/td&gt;
&lt;td&gt;Prosseguir para outro candidato.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Para a confirmação de 128 bytes do caso adversarial, o assembly observado&lt;br&gt;
compara trechos AVX2 de 32 bytes. Os três primeiros trechos coincidem; o&lt;br&gt;
quarto contém a divergência no elemento final. Isso descreve a captura desse&lt;br&gt;
caso, não uma exigência de que &lt;code&gt;SequenceEqual&lt;/code&gt; sempre execute quatro passos.&lt;/p&gt;
&lt;h2&gt;
  
  
  A título de curiosidade: como se saem KMP e Boyer–Moore?
&lt;/h2&gt;

&lt;p&gt;Depois da conclusão principal, vale a curiosidade: como a comparação se&lt;br&gt;
comportaria contra algoritmos que evitam recomeçar a busca do zero? Para isso,&lt;br&gt;
acrescentamos duas implementações ao mesmo harness:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Knuth–Morris–Pratt (KMP):&lt;/strong&gt; constrói a tabela de prefixos da needle e a usa
para retomar do maior prefixo que ainda pode coincidir. Busca e
pré-processamento têm custo O(n + m) no total, onde &lt;code&gt;n&lt;/code&gt; é o texto e &lt;code&gt;m&lt;/code&gt; a
needle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boyer–Moore–Horspool (BMH):&lt;/strong&gt; compara da direita para a esquerda e, após
uma falha, avança conforme a posição do último caractere da janela na needle.
O pré-processamento custa O(m); a busca costuma saltar posições, mas o pior
caso permanece O(nm).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para esta comparação de &lt;strong&gt;uma busca por needle&lt;/strong&gt;, o tempo cronometrado inclui&lt;br&gt;
construir as tabelas de cada algoritmo em cada chamada. Assim, o KMP aloca e&lt;br&gt;
preenche a tabela de prefixos, e o BMH monta sua tabela esparsa de saltos&lt;br&gt;
(&lt;code&gt;Dictionary&amp;lt;char, int&amp;gt;&lt;/code&gt;) antes de percorrer o texto. O runtime recebe a mesma&lt;br&gt;
needle e o mesmo texto, sem estado pré-processado reutilizado. Os quatro&lt;br&gt;
métodos retornam o primeiro índice ou &lt;code&gt;-1&lt;/code&gt;; o &lt;code&gt;GlobalSetup&lt;/code&gt; confere todos&lt;br&gt;
contra o resultado esperado antes da medição.&lt;/p&gt;

&lt;p&gt;O código adicional do benchmark é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;prefixLengths&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefixLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;

        &lt;span class="n"&gt;prefixLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prefixLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;prefixLength&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefixLength&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsEmpty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;shifts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="n"&gt;shifts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;lastStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;--;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shifts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;
            &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta é a comparação final para os dois cenários escolhidos. São médias e&lt;br&gt;
desvios padrão do MediumRun (15 medições, 10 aquecimentos, 2 processos por&lt;br&gt;
benchmark); todas as quatro implementações receberam o mesmo texto e needle.&lt;br&gt;
As colunas KMP e BMH incluem a construção das tabelas em cada chamada.&lt;br&gt;
Esta rodada comparativa é independente da medição histórica usada no gancho;&lt;br&gt;
os tempos da tabela devem ser comparados entre si, não diretamente com os&lt;br&gt;
números da abertura.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Texto&lt;/th&gt;
&lt;th&gt;Cenário&lt;/th&gt;
&lt;th&gt;Loop ingênuo&lt;/th&gt;
&lt;th&gt;&lt;code&gt;IndexOf&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;KMP&lt;/th&gt;
&lt;th&gt;Boyer–Moore–Horspool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4.096&lt;/td&gt;
&lt;td&gt;Match tardio pseudoaleatório&lt;/td&gt;
&lt;td&gt;3,291 ± 0,093 µs&lt;/td&gt;
&lt;td&gt;0,320 ± 0,016 µs&lt;/td&gt;
&lt;td&gt;5,026 ± 0,189 µs&lt;/td&gt;
&lt;td&gt;10,303 ± 0,223 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65.536&lt;/td&gt;
&lt;td&gt;Match tardio pseudoaleatório&lt;/td&gt;
&lt;td&gt;120,256 ± 7,345 µs&lt;/td&gt;
&lt;td&gt;5,145 ± 0,267 µs&lt;/td&gt;
&lt;td&gt;132,655 ± 6,025 µs&lt;/td&gt;
&lt;td&gt;175,052 ± 8,051 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4.096&lt;/td&gt;
&lt;td&gt;Candidatos alternados, mismatch tardio&lt;/td&gt;
&lt;td&gt;113,756 ± 10,486 µs&lt;/td&gt;
&lt;td&gt;7,339 ± 0,273 µs&lt;/td&gt;
&lt;td&gt;7,382 ± 0,476 µs&lt;/td&gt;
&lt;td&gt;23,617 ± 0,225 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65.536&lt;/td&gt;
&lt;td&gt;Candidatos alternados, mismatch tardio&lt;/td&gt;
&lt;td&gt;1.728,590 ± 66,428 µs&lt;/td&gt;
&lt;td&gt;122,848 ± 5,355 µs&lt;/td&gt;
&lt;td&gt;106,727 ± 6,830 µs&lt;/td&gt;
&lt;td&gt;378,960 ± 8,429 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No match tardio pseudoaleatório, &lt;code&gt;IndexOf&lt;/code&gt; teve a menor média entre os quatro&lt;br&gt;
métodos; KMP e BMH foram mais lentos que o loop simples com a preparação das&lt;br&gt;
tabelas incluída. Não medimos essas buscas com tabelas reutilizadas, portanto&lt;br&gt;
não isolamos quanto da diferença vem do pré-processamento e quanto vem da&lt;br&gt;
busca. No fixture adversarial de 65.536 &lt;code&gt;char&lt;/code&gt;s, KMP&lt;br&gt;
ficou cerca de 13% abaixo da média de &lt;code&gt;IndexOf&lt;/code&gt; (106,727 contra 122,848 µs);&lt;br&gt;
no tamanho 4.096, suas médias ficaram praticamente iguais diante da&lt;br&gt;
dispersão. BMH foi mais lento que &lt;code&gt;IndexOf&lt;/code&gt; nos quatro casos medidos.&lt;/p&gt;

&lt;p&gt;Isso ilustra por que a resposta depende do algoritmo, da entrada e de como o&lt;br&gt;
pré-processamento é contabilizado. Não é um ranking universal: são&lt;br&gt;
implementações didáticas, e o BMH usa uma tabela baseada em&lt;br&gt;
&lt;code&gt;Dictionary&amp;lt;char, int&amp;gt;&lt;/code&gt;, não uma tabela especializada de baixo nível.&lt;br&gt;
&lt;code&gt;MemoryDiagnoser&lt;/code&gt; também registrou alocações por chamada: KMP alocou 88 bytes&lt;br&gt;
para a needle de 16 &lt;code&gt;char&lt;/code&gt;s e 280 bytes para a de 64; BMH alocou 472 e 1.552&lt;br&gt;
bytes, respectivamente. Reutilizar uma tabela pré-processada mudaria essa&lt;br&gt;
comparação e não foi medido aqui.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reprodução dos dois cenários selecionados
&lt;/h2&gt;

&lt;p&gt;Para montar uma reprodução sem acessar o repositório do artigo, crie um&lt;br&gt;
projeto de console com SDK .NET 10. A versão de runtime &lt;strong&gt;10.0.12&lt;/strong&gt; precisa&lt;br&gt;
estar instalada, pois o roll-forward estará desativado:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new console &lt;span class="nt"&gt;-n&lt;/span&gt; SubstringBenchmark &lt;span class="nt"&gt;--framework&lt;/span&gt; net10.0
&lt;span class="nb"&gt;cd &lt;/span&gt;SubstringBenchmark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitua &lt;code&gt;SubstringBenchmark.csproj&lt;/code&gt; por:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net10.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RuntimeFrameworkVersion&amp;gt;&lt;/span&gt;10.0.12&lt;span class="nt"&gt;&amp;lt;/RuntimeFrameworkVersion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;RollForward&amp;gt;&lt;/span&gt;Disable&lt;span class="nt"&gt;&amp;lt;/RollForward&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ImplicitUsings&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/ImplicitUsings&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"BenchmarkDotNet"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"0.15.8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a estrutura abaixo em &lt;code&gt;Program.cs&lt;/code&gt;. &lt;strong&gt;Dentro da classe, no local&lt;br&gt;
indicado, copie os seis métodos já apresentados neste artigo:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;SearchNaive&lt;/code&gt;, &lt;code&gt;SearchRuntime&lt;/code&gt;, &lt;code&gt;CreateOrdinaryHaystack&lt;/code&gt;,&lt;br&gt;
&lt;code&gt;CreateAlternatingNeedleWithLateMismatch&lt;/code&gt;, &lt;code&gt;SearchKnuthMorrisPratt&lt;/code&gt; e&lt;br&gt;
&lt;code&gt;SearchBoyerMooreHorspool&lt;/code&gt;. Os quatro wrappers &lt;code&gt;[Benchmark]&lt;/code&gt; já estão abaixo;&lt;br&gt;
não os copie novamente. Assim não precisamos duplicar as implementações no&lt;br&gt;
texto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;BenchmarkDotNet.Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;BenchmarkDotNet.Running&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SubstringSearchBenchmarks&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MediumRunJob&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MemoryDiagnoser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;DisassemblyDiagnoser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxDepth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SubstringSearchBenchmarks&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt; &lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;GlobalSetup&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CreateOrdinaryHaystack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HaystackLength&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"abcdefghabcdefgh"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;[..&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_haystack&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HaystackLength&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
                    &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="sc"&gt;'a'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="n"&gt;_needle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;CreateAlternatingNeedleWithLateMismatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
            &lt;span class="nf"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Resultado inesperado no setup."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Scenario&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;uint&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;61&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                    &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;|=&lt;/span&gt; &lt;span class="m"&gt;3u&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0x33333333&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt;
                &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;HaystackLength&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Fixture adversarial inconsistente."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Baseline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;Naive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;ReadOnlySpanIndexOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;KnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchKnuthMorrisPratt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Benchmark&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;BoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SearchBoyerMooreHorspool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_haystack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;_needle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="c1"&gt;// Cole aqui os seis métodos indicados acima.&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;SearchCase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;RandomLateMatch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;RepeatedAlternatingLateFalse&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet run &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--filter&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt; &lt;span class="nt"&gt;--artifacts&lt;/span&gt; artifacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa reprodução seleciona dois cenários × dois tamanhos × quatro métodos,&lt;br&gt;
totalizando &lt;strong&gt;16 benchmarks MediumRun&lt;/strong&gt;. O setup verifica os resultados e&lt;br&gt;
a matemática do adversarial; ele não substitui a validação exaustiva histórica&lt;br&gt;
de 34.193 casos descrita anteriormente. As tabelas e a desassemblagem são&lt;br&gt;
gravadas em &lt;code&gt;artifacts/results/&lt;/code&gt;. A captura de assembly depende do suporte&lt;br&gt;
do diagnoser no sistema; outra CPU ou runtime pode gerar outras instruções.&lt;br&gt;
Os tempos também variarão: reproduzir o procedimento não garante reproduzir&lt;br&gt;
os números históricos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dotnet/runtime/blob/v10.0.12/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs" rel="noopener noreferrer"&gt;.NET 10.0.12 — &lt;code&gt;SpanHelpers.Char.cs&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html" rel="noopener noreferrer"&gt;Intel Intrinsics Guide&lt;/a&gt;, para as instruções observadas: &lt;code&gt;_mm256_cmpeq_epi16&lt;/code&gt;, &lt;code&gt;_mm256_testz_si256&lt;/code&gt;, &lt;code&gt;_mm256_movemask_epi8&lt;/code&gt;, &lt;code&gt;_tzcnt_u32&lt;/code&gt; e &lt;code&gt;_blsr_u32&lt;/code&gt;. São referências de semântica equivalente, não chamadas C/C++ feitas pelo código C#.&lt;/li&gt;
&lt;li&gt;Knuth, Morris e Pratt, &lt;a href="https://doi.org/10.1137/0206024" rel="noopener noreferrer"&gt;“Fast Pattern Matching in Strings”&lt;/a&gt;, &lt;em&gt;SIAM Journal on Computing&lt;/em&gt; 6(2), 1977.&lt;/li&gt;
&lt;li&gt;Boyer e Moore, &lt;a href="https://doi.org/10.1145/359842.359859" rel="noopener noreferrer"&gt;“A Fast String Searching Algorithm”&lt;/a&gt;, &lt;em&gt;Communications of the ACM&lt;/em&gt; 20(10), 1977.&lt;/li&gt;
&lt;li&gt;Horspool, &lt;a href="https://doi.org/10.1002/spe.4380100608" rel="noopener noreferrer"&gt;“Practical fast searching in strings”&lt;/a&gt;, &lt;em&gt;Software: Practice and Experience&lt;/em&gt; 10(6), 1980. A implementação comparada é Boyer–Moore–Horspool, não Boyer–Moore completo.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/simd" rel="noopener noreferrer"&gt;SIMD e hardware intrinsics no .NET&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/api/system.memoryextensions.indexof?view=net-10.0" rel="noopener noreferrer"&gt;API &lt;code&gt;MemoryExtensions.IndexOf&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>performance</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Microsoft-Decision-1 in practice: probabilities for AIOps decisions</title>
      <dc:creator>Pedro Sakuma Travi</dc:creator>
      <pubDate>Tue, 13 Oct 2026 14:09:12 +0000</pubDate>
      <link>https://dev.to/pedrosakuma/microsoft-decision-1-in-practice-probabilities-for-aiops-decisions-3kj8</link>
      <guid>https://dev.to/pedrosakuma/microsoft-decision-1-in-practice-probabilities-for-aiops-decisions-3kj8</guid>
      <description>&lt;p&gt;Microsoft-Decision-1 isn't a chat model. You send a &lt;code&gt;state&lt;/code&gt; plus typed questions, and it returns numbers: a probability for yes/no (&lt;code&gt;noul&lt;/code&gt;), a probability per option (&lt;code&gt;choice&lt;/code&gt;), or a position on an ordered scale (&lt;code&gt;score&lt;/code&gt;). No prose, no rationale, about 1 output token per call. That makes it a natural candidate for the decisions around an operations stack: "is this block of logs anomalous?", "which service is the root cause?".&lt;/p&gt;

&lt;p&gt;We tested it on two public AIOps datasets against &lt;code&gt;gpt-4.1-nano&lt;/code&gt;, a reasoning model (&lt;code&gt;gpt-6.1-sol&lt;/code&gt;) and non-LLM baselines. This post walks through the signals, how we framed what to detect, and the results, including a first attempt that did not work. The code is on &lt;a href="https://github.com/pedrosakuma/decision-1-aiops" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5e38tg4h5xrmronsfohe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5e38tg4h5xrmronsfohe.png" alt="Decision-1 results on root-cause analysis and HDFS anomaly detection" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Highlights
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Root-cause ranking was a strong fit.&lt;/strong&gt; Decision-1 picked the root-cause service in 94% of 90 failure cases, beating a "largest metric deviation" heuristic (82%, p=0.013), at about a third of the chat baseline's latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log anomaly detection needed work.&lt;/strong&gt; The first framing scored 49%. With a computed summary, a better question and a calibrated threshold it reached 86% and led the other LLMs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A small trained classifier still wins when you have labels:&lt;/strong&gt; 95% with 50 labeled blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cheap and fast:&lt;/strong&gt; about 240 ms p50, and cents for a full run at the prices we found (unverified).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: HDFS log anomaly detection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The signal: what a block's log looks like
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/logpai/loghub" rel="noopener noreferrer"&gt;Loghub&lt;/a&gt; HDFS_v1 dataset (free for research use; &lt;a href="https://people.eecs.berkeley.edu/~jordan/papers/xu-etal-sosp09.pdf" rel="noopener noreferrer"&gt;Xu et al., SOSP'09&lt;/a&gt;; &lt;a href="https://arxiv.org/abs/2008.06448" rel="noopener noreferrer"&gt;Zhu et al., ISSRE'23&lt;/a&gt;) groups the logs of a Hadoop distributed file system by &lt;em&gt;block&lt;/em&gt;: every block gets an identifier, and everything the cluster logged about it forms one session. Parsed into 29 event templates, the sequence for one block tells a story:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The NameNode &lt;strong&gt;allocates&lt;/strong&gt; the block.&lt;/li&gt;
&lt;li&gt;Three DataNodes (replication factor 3) each &lt;strong&gt;start receiving&lt;/strong&gt; it and, when done, log that they &lt;strong&gt;received&lt;/strong&gt; it.&lt;/li&gt;
&lt;li&gt;Each replica's &lt;strong&gt;PacketResponder terminates&lt;/strong&gt;, acknowledging the write.&lt;/li&gt;
&lt;li&gt;Each DataNode reports the block to the NameNode, which logs the block map &lt;strong&gt;update&lt;/strong&gt; (&lt;code&gt;addStoredBlock&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Later, deletions may appear.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We do not reproduce raw log lines: the dataset is unsanitized and licensed for research. We work with event &lt;em&gt;templates&lt;/em&gt; and counts only. The dataset also has a &lt;code&gt;Type&lt;/code&gt; column derived from the label, so we do not use it (it would leak the answer). Labels come from the dataset's own rules plus manual review.&lt;/p&gt;

&lt;p&gt;Sampling matters: real prevalence of anomalies is about 2.9%. Our test set is balanced (600 normal, 600 anomalous), so accuracy here is &lt;em&gt;not&lt;/em&gt; what you would see in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  What "anomalous" really means
&lt;/h3&gt;

&lt;p&gt;Looking at 300 blocks from our calibration split (150 normal, 150 anomalous) shows that "contains an error" is a bad definition:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Normal&lt;/th&gt;
&lt;th&gt;Anomalous&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Complete lifecycle (1 allocation, 3 receives, 3 acks), no error message&lt;/td&gt;
&lt;td&gt;112&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complete receive/ack, but an error message is present&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Truncated: 1 or 2 receives, no acks&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extra receive attempts (4 or 5)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;38 of 150 normal blocks contain a "got exception while serving" message: a benign event.&lt;/li&gt;
&lt;li&gt;14 anomalous blocks look complete and log no error at all. In the ones we inspected, the NameNode block-map update appears once instead of three times, meaning only one replica was registered.&lt;/li&gt;
&lt;li&gt;Truncated blocks are short, often 4 events, with a "writeBlock received exception".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the real signal is the lifecycle: expected steps, repeated three times, and a count of what is missing. A rule like "any exception event" gets 71% on the test split (it flags the benign exceptions and misses the quiet anomalies).&lt;/p&gt;

&lt;h3&gt;
  
  
  A first attempt that failed
&lt;/h3&gt;

&lt;p&gt;Our first prompt was the obvious one. The state was the list of event templates with counts, and the question was "does this block's activity indicate an anomaly?". Decision-1 scored &lt;strong&gt;49%&lt;/strong&gt; (AUC 0.68), worse than the 71% rule. Looking at the saved outputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its probability correlated 0.43 with the number of events, but only 0.14 with the label.&lt;/li&gt;
&lt;li&gt;Short blocks (10 events or fewer), all anomalies, got a mean P(anomaly) of 0.45. Blocks of 15 to 20 events, 99% normal, got 0.66.&lt;/li&gt;
&lt;li&gt;Error keywords ("exception") pushed the probability up, whether or not they mattered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model reacts to lexical cues and volume, and treats &lt;em&gt;missing&lt;/em&gt; events as healthy. That is a framing problem, not a reason to discard the model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modeling what we want to detect
&lt;/h3&gt;

&lt;p&gt;We changed two things, and tested them on the calibration split (never the test split):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;State:&lt;/strong&gt; we added a computed &lt;code&gt;lifecycle_summary&lt;/code&gt; (expected replicas = 3; allocations; replica writes started and completed; terminated acks; replicas registered with the NameNode; missing lifecycle steps; error events). This is feature engineering from HDFS domain knowledge, not something the model derives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Question:&lt;/strong&gt; instead of "is it abnormal?", ask the positive, structural one: "is the block's lifecycle complete?"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a real (short) block as sent. The first-attempt request carried only the part up to &lt;code&gt;event_counts&lt;/code&gt;; the enriched one adds &lt;code&gt;lifecycle_summary&lt;/code&gt;. This is a hard one: the lifecycle looks complete, and there is one "Unexpected error" event, but the dataset labels the block &lt;strong&gt;anomalous&lt;/strong&gt;. The same pattern is also common among normal blocks (see the table above), which is why error keywords alone are a weak signal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Decision-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"system"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HDFS (Hadoop distributed file system), log events for a single data block"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total_events"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"event_counts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"BLOCK* NameSystem allocateBlock:"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Receiving block src: dest:"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Received block of size from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"PacketResponder for block terminating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"BLOCK* NameSystem addStoredBlock: blockMap updated: is added to size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"BLOCK* NameSystem delete: is added to invalidSet of"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Deleting block file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Unexpected error trying to delete block BlockInfo not found in volumeMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lifecycle_summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"expected_replicas"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"block_allocations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"replica_writes_started"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"replica_writes_completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pipeline_acks_terminated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"replicas_registered_with_namenode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"missing_lifecycle_steps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"exception_or_error_events"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"questions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"noul"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Did this block complete the normal HDFS write lifecycle on all expected replicas (allocated, written, acknowledged and registered)?"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The answer is a single probability that the lifecycle is complete; the anomaly score is &lt;code&gt;1 - P(complete)&lt;/code&gt;. For a truncated block, &lt;code&gt;missing_lifecycle_steps&lt;/code&gt; would instead list entries such as "write completed on every replica".&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant (200 calibration blocks)&lt;/th&gt;
&lt;th&gt;Accuracy @0.5&lt;/th&gt;
&lt;th&gt;AUC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"abnormal?", raw counts&lt;/td&gt;
&lt;td&gt;49.5%&lt;/td&gt;
&lt;td&gt;0.65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"is the lifecycle complete?", raw counts&lt;/td&gt;
&lt;td&gt;60.5%&lt;/td&gt;
&lt;td&gt;0.82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"abnormal?", counts + lifecycle summary&lt;/td&gt;
&lt;td&gt;73.5%&lt;/td&gt;
&lt;td&gt;0.91&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;choice normal / anomalous / uncertain + summary&lt;/td&gt;
&lt;td&gt;79.0%&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"lifecycle complete?" + summary&lt;/td&gt;
&lt;td&gt;70.5%&lt;/td&gt;
&lt;td&gt;0.97&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both the state and the wording matter. The last variant ranks best (AUC 0.97, mean P(complete) 0.96 for normal and 0.48 for anomalous blocks), but 0.5 is the wrong threshold for it, so it needs calibrating.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results on 1,200 held-out blocks
&lt;/h3&gt;

&lt;p&gt;We picked the best variants on the calibration split and scored them on the full test split, with the same enriched state for every LLM and the threshold chosen on the calibration split only:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;"Complete?" @0.5&lt;/th&gt;
&lt;th&gt;"Complete?", calibrated&lt;/th&gt;
&lt;th&gt;Choice with abstain&lt;/th&gt;
&lt;th&gt;AUC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decision-1&lt;/td&gt;
&lt;td&gt;69%&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;86%&lt;/strong&gt; (thr 0.15)&lt;/td&gt;
&lt;td&gt;79%&lt;/td&gt;
&lt;td&gt;0.964&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4.1-nano&lt;/td&gt;
&lt;td&gt;65%&lt;/td&gt;
&lt;td&gt;79%&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;td&gt;0.839&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-6.1-sol (n=100)&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;td&gt;79%&lt;/td&gt;
&lt;td&gt;0.790&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The choice variant never abstained (0 of 1,200). The reasoning model ran on only 100 blocks (CI roughly 70 to 86%), and its self-reported confidence was too coarse for calibration to help.&lt;/p&gt;

&lt;p&gt;Against non-LLM references on the same blocks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Reference&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rule: any exception event&lt;/td&gt;
&lt;td&gt;70.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logistic regression, 50 labeled blocks&lt;/td&gt;
&lt;td&gt;95.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logistic regression, 200 labeled blocks&lt;/td&gt;
&lt;td&gt;97.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logistic regression, 8,000 labeled blocks&lt;/td&gt;
&lt;td&gt;99.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note: the logistic regression is not a like-for-like comparison.&lt;/strong&gt; It is a trained classifier: it needs labeled examples (the rows above are trained on 50, 200 and 8,000 labeled blocks), a training step, and a stable event schema, and it only sees raw event counts. Decision-1 and the other LLMs ran zero-shot with no training; we used labels only to pick a threshold (150 + 150 blocks), and they received our computed lifecycle summary on top of the counts.&lt;/p&gt;

&lt;p&gt;Decision-1 beat the rule (p&amp;lt;0.0001) but &lt;strong&gt;not&lt;/strong&gt; a logistic regression on event counts. If you have labels and a stable schema, train a classifier. A zero-shot decision model fits when you do not have labels, or when the schema changes too often to retrain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: root-cause analysis on microservices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The signal
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/phamquiluan/RCAEval" rel="noopener noreferrer"&gt;RCAEval&lt;/a&gt; RE2-OB (MIT license) injects faults into the &lt;a href="https://github.com/GoogleCloudPlatform/microservices-demo" rel="noopener noreferrer"&gt;Online Boutique&lt;/a&gt; demo (11 microservices on Kubernetes) and records three kinds of telemetry while it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Metrics:&lt;/strong&gt; CPU, memory, sockets, disk, request latency (p50/p90) and error rate per service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traces:&lt;/strong&gt; how long each service's spans take.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs:&lt;/strong&gt; how many log lines per second each service emits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each case injects one fault into one service, at a known moment. There are 5 root-cause services (checkout, currency, email, product catalog, recommendation) and 6 fault types (CPU, memory, disk, socket exhaustion, added delay, packet loss), each repeated 3 times: 90 cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  What an on-call engineer would see
&lt;/h3&gt;

&lt;p&gt;We do not hand the model raw time series. A script reduces each case's telemetry to a compact JSON state, and that state is the only thing Decision-1 sees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Window:&lt;/strong&gt; the 12 minutes before and the 12 minutes after the injection time. The state says an alert fired at the start of the "after" window; in a real incident you would use your alert time, which is less exact than the dataset's.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics:&lt;/strong&gt; for every service and metric (CPU, memory, sockets, disk, latency p50/p90, errors) we compare the after-mean with the before-mean, scaled by how much the metric varied before the fault. Only the 10 largest shifts are kept, each with its before, after and % change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traces:&lt;/strong&gt; mean span duration per service before and after, keeping the 6 largest relative changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs:&lt;/strong&gt; log lines per second per service before and after, keeping the 6 largest relative changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We compute these deltas ourselves because Decision-1 is weak at arithmetic over raw numbers. The metric list is already sorted by that shift score, so the first entry is exactly the pick of the baseline rule below. What Decision-1 adds is combining that list with the trace and log evidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A clear case: CPU fault on checkout.&lt;/strong&gt; The top change is the checkout service's CPU going from 0.43 to 18.3 (+4,160%), followed by its memory (+38%) and sockets (+22%); the entries that follow are changes of a few percent. One service lights up on its own metrics: the signature is easy to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A harder case: added delay on the email service.&lt;/strong&gt; The email service's own p90 latency rises +4,500%, but the service that &lt;em&gt;calls&lt;/em&gt; it, checkout, also slows down (p90 +106%, p50 +195%), and checkout's span time triples (14 to 43 ms) while email's own span time barely moves (0.17 to 0.18 ms). Both services appear in the top changes, and a reader can mistake the caller for the culprit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Packet loss is noisy.&lt;/strong&gt; Loss on the product catalog service pushes latency up on the services that depend on it (recommendation p90 +68,900%), and the frontend starts reporting errors, so the loudest symptoms are not on the service at fault.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we ask
&lt;/h3&gt;

&lt;p&gt;Two questions per case, and each is a &lt;code&gt;choice&lt;/code&gt; question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which of the 11 services is the root cause?&lt;/li&gt;
&lt;li&gt;Which of the 6 fault types was injected?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the whole request for the first question (lists shortened). The case id, which contains the true service and fault, is never sent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Decision-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"system"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Online Boutique microservices on Kubernetes (11 services). An alert fired at the start of the 'after' window; telemetry is summarized as before vs after."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"minutes_before_and_after"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"top_metric_changes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkoutservice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"metric"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"before"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"after"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"change_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4160.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"trace_span_duration_by_service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"checkoutservice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mean_span_ms_before"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mean_span_ms_after"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;340.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"change_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2714.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"log_volume_by_service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"frontend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"log_lines_per_s_before"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;9.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"log_lines_per_s_after"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;14.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"change_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;44.9&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"questions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"choice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Which service is the root cause of the incident?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"criteria"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"adservice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The ad service is the origin of the fault"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"checkoutservice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The checkout service is the origin of the fault"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second call reuses the same state and asks "What kind of fault was injected into the root-cause service?" with the options &lt;code&gt;cpu&lt;/code&gt;, &lt;code&gt;mem&lt;/code&gt;, &lt;code&gt;disk&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;loss&lt;/code&gt; and &lt;code&gt;socket&lt;/code&gt;. The response is a probability per option, and we take the highest. The chat baselines receive the same state and options as prompt text.&lt;/p&gt;

&lt;p&gt;The non-LLM reference is a "largest shift" rule: pick the service of the single metric that moved most relative to its pre-fault variability (the first entry in the state). It needs no training, and it is right 82% of the time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results (90 cases)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Decision-1&lt;/th&gt;
&lt;th&gt;gpt-4.1-nano&lt;/th&gt;
&lt;th&gt;gpt-6.1-sol&lt;/th&gt;
&lt;th&gt;Reference rule&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Root-cause service (11 options)&lt;/td&gt;
&lt;td&gt;94%&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fault type (6 options)&lt;/td&gt;
&lt;td&gt;51%&lt;/td&gt;
&lt;td&gt;47%&lt;/td&gt;
&lt;td&gt;54%&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p50 latency per call&lt;/td&gt;
&lt;td&gt;240 ms&lt;/td&gt;
&lt;td&gt;728 ms&lt;/td&gt;
&lt;td&gt;2,052 ms&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Decision-1 beat the heuristic on the service (McNemar p=0.013). Differences against the two LLMs are not significant (vs gpt-4.1-nano p=0.55, vs gpt-6.1-sol p=0.06), and fault-type differences are not significant for anyone. Only 5 of the 11 services ever appear as a true root cause, which makes the task somewhat easier than it looks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the model helps, and where it does not
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Service (85 of 90 right).&lt;/strong&gt; The heuristic and Decision-1 disagree on 17 cases. In 14, Decision-1 is right and the rule is wrong: the rule had picked a symptom (the frontend in 9 of them, an email or other service in the rest), mostly on packet-loss and delay faults, where the loudest numbers sit downstream of the fault. In 3, the rule is right and Decision-1 is wrong: all three are the email-delay case above, where Decision-1 named checkout, the caller. Its other two errors were a packet-loss case (it chose the frontend) and a product-catalog loss case (it chose recommendation). Those are the same "symptom versus cause" confusions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fault type (46 of 90 right).&lt;/strong&gt; Per-type results show a clear split:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Injected fault&lt;/th&gt;
&lt;th&gt;Correct (of 15)&lt;/th&gt;
&lt;th&gt;Most common wrong answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CPU&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;disk (2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delay&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;memory, disk (1 each)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;CPU (4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disk&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;memory (4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packet loss&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;memory (9), delay (5)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Socket&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;CPU (8)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;CPU and delay leave a distinctive trace. Packet loss and socket exhaustion do not: the same latency and error symptoms show up as other faults, and Decision-1 never answered "loss" once and chose "socket" only twice. Nothing in the state we give it says "packets were dropped", so this is as much a limit of our summary as of the model. The other two LLMs landed at 47% and 54%, so this is a hard task for all of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaway for practice.&lt;/strong&gt; Use it to rank &lt;em&gt;where&lt;/em&gt; to look, not to name the fault. It narrowed 11 services to the right one 94% of the time in a quarter of a second; telling you why is a job for a human, or for richer state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost and latency
&lt;/h2&gt;

&lt;p&gt;Token counts from the main run (1,380 calls for Decision-1 and gpt-4.1-nano, 280 for the reasoning model; calibration calls excluded), at list rates we have not verified (Decision-1 as reported by third-party aggregators, gpt-6.1-sol from OpenAI's list; Azure prices may differ, and hidden reasoning tokens may add to the reasoning model's bill):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input / output tokens&lt;/th&gt;
&lt;th&gt;Approx. cost&lt;/th&gt;
&lt;th&gt;Per call&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decision-1 (about $0.042 per 1M input, output free)&lt;/td&gt;
&lt;td&gt;353k / 1.4k&lt;/td&gt;
&lt;td&gt;~$0.015&lt;/td&gt;
&lt;td&gt;~$0.00001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4.1-nano (~$0.10 in / $0.40 out per 1M)&lt;/td&gt;
&lt;td&gt;402k / 18k&lt;/td&gt;
&lt;td&gt;~$0.05 to 0.07&lt;/td&gt;
&lt;td&gt;~$0.00004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-6.1-sol ($2 in / $10 out per 1M)&lt;/td&gt;
&lt;td&gt;192k / 18k&lt;/td&gt;
&lt;td&gt;~$0.56&lt;/td&gt;
&lt;td&gt;~$0.002&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At equal volume the reasoning model would cost about two orders of magnitude more than Decision-1, plus 2 s of latency per call versus 0.24 s. Check Azure Cost Management for the real bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The HDFS lifecycle summary was written by us from domain knowledge (replication factor 3), so it is feature engineering. We tried five variants and chose after seeing calibration results, which makes the headline 86% somewhat optimistic. The sample is balanced and the reasoning model ran on 100 blocks only.&lt;/li&gt;
&lt;li&gt;Our pattern table comes from a 300-block calibration split; the 14 "quiet" anomalies were inspected by us and are not proof of a general rule.&lt;/li&gt;
&lt;li&gt;RCA has 90 cases and only 5 true root-cause services; samples are small and margins wide. The state is pre-ranked by the same shift score the baseline rule uses, and uses the dataset's exact injection time.&lt;/li&gt;
&lt;li&gt;One baseline per model family, temperature 0, our prompt, no few-shot examples. The chat models' "probability" is self-reported confidence, so it is coarser than Decision-1's.&lt;/li&gt;
&lt;li&gt;We did not verify published scores for these datasets, so we cite none. Prices are unverified.&lt;/li&gt;
&lt;li&gt;Decision-1 returns no explanation, so keep a human in the loop for consequential decisions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Decision-1 works best when the state already contains the facts that matter. Compute lifecycle checks and deltas instead of handing it raw counts.&lt;/li&gt;
&lt;li&gt;Ask the structural question ("is the lifecycle complete?"), not the vague one ("is this abnormal?").&lt;/li&gt;
&lt;li&gt;Calibrate the threshold on held-out labeled data; 0.5 was a poor default.&lt;/li&gt;
&lt;li&gt;With labeled data and a stable schema, a small trained classifier beat every LLM on HDFS. Use a decision model where you have no labels, and for fast gates like root-cause ranking.&lt;/li&gt;
&lt;li&gt;Test every gate on your own data before you automate it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Code and reproduction steps: &lt;a href="https://github.com/pedrosakuma/decision-1-aiops" rel="noopener noreferrer"&gt;pedrosakuma/decision-1-aiops&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Loghub HDFS_v1: &lt;a href="https://github.com/logpai/loghub" rel="noopener noreferrer"&gt;Loghub on GitHub&lt;/a&gt;, &lt;a href="https://zenodo.org/records/8196385" rel="noopener noreferrer"&gt;HDFS_v1 on Zenodo&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Xu et al., &lt;a href="https://people.eecs.berkeley.edu/~jordan/papers/xu-etal-sosp09.pdf" rel="noopener noreferrer"&gt;Detecting Large-Scale System Problems by Mining Console Logs&lt;/a&gt; (SOSP 2009)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Zhu et al., &lt;a href="https://arxiv.org/abs/2008.06448" rel="noopener noreferrer"&gt;Loghub: A Large Collection of System Log Datasets for AI-driven Log Analytics&lt;/a&gt; (ISSRE 2023)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RCAEval: &lt;a href="https://huggingface.co/papers/2412.17015" rel="noopener noreferrer"&gt;paper&lt;/a&gt; (WWW 2025), &lt;a href="https://github.com/phamquiluan/RCAEval" rel="noopener noreferrer"&gt;code&lt;/a&gt;, &lt;a href="https://huggingface.co/datasets/phamquiluan/RCAEval" rel="noopener noreferrer"&gt;dataset on Hugging Face&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/GoogleCloudPlatform/microservices-demo" rel="noopener noreferrer"&gt;Online Boutique demo&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>aiops</category>
      <category>dotnet</category>
      <category>azure</category>
    </item>
    <item>
      <title>The pool that got slower the more we shared it</title>
      <dc:creator>Pedro Sakuma Travi</dc:creator>
      <pubDate>Tue, 14 Jul 2026 18:08:47 +0000</pubDate>
      <link>https://dev.to/pedrosakuma/the-pool-that-got-slower-the-more-we-shared-it-57oh</link>
      <guid>https://dev.to/pedrosakuma/the-pool-that-got-slower-the-more-we-shared-it-57oh</guid>
      <description>&lt;p&gt;&lt;em&gt;How a 15-minute chat with an LLM found a hidden &lt;code&gt;ArrayPool&amp;lt;byte&amp;gt;.Shared&lt;/code&gt;&lt;br&gt;
contention point that no static analyzer would ever flag — and why the fix&lt;br&gt;
had nothing to do with adding a lock.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The ticket
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"CPU on &lt;code&gt;market-data-gateway&lt;/code&gt; climbed ~20% after we added a broadcast fan-out&lt;br&gt;
path last sprint. No new allocations, no GC pressure, nothing obviously&lt;br&gt;
wrong in the diff. Can someone take a look before we scale out more pods?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody had touched anything that &lt;em&gt;looked&lt;/em&gt; like a synchronization primitive.&lt;br&gt;
The diff that shipped the week before only touched a buffer-pooling helper —&lt;br&gt;
swapping a bespoke byte-array cache for the "obviously correct" BCL default,&lt;br&gt;
&lt;code&gt;ArrayPool&amp;lt;byte&amp;gt;.Shared&lt;/code&gt;. That refactor was reviewed and merged specifically&lt;br&gt;
&lt;em&gt;because&lt;/em&gt; it removed custom code in favor of a well-known, heavily optimized&lt;br&gt;
framework type. If anything, it should have been a free win.&lt;/p&gt;

&lt;p&gt;This is the kind of regression static analysis is structurally blind to: no&lt;br&gt;
analyzer rule says "using &lt;code&gt;ArrayPool&amp;lt;T&amp;gt;.Shared&lt;/code&gt; across threads is suspicious."&lt;br&gt;
It's &lt;em&gt;the recommended way&lt;/em&gt; to pool buffers in .NET. The problem isn't in the&lt;br&gt;
code you'd read in a diff — it's in a runtime behavior that only shows up&lt;br&gt;
under a specific, easy-to-miss usage pattern.&lt;/p&gt;
&lt;h2&gt;
  
  
  The investigation, as it actually happened
&lt;/h2&gt;

&lt;p&gt;This is the real value proposition of &lt;a href="https://github.com/pedrosakuma/dotnet-diagnostics" rel="noopener noreferrer"&gt;&lt;code&gt;dotnet-diagnostics-mcp&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
none of what follows required attaching a debugger, adding instrumentation, or&lt;br&gt;
redeploying anything. It's a live conversation with an LLM that has MCP tools&lt;br&gt;
wired to the running process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — orient.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user&amp;gt; Can you check what's going on with pid 41213? CPU looks high.

assistant&amp;gt; Let me look at the process first.
→ inspect_process(view="triage", processId=41213)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"processId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41213&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resolvedProcess"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"market-data-gateway"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"runtime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"net10.0"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CPU 78% (host has 16 cores). No memory growth trend. No recent
               GC pause anomalies. Consider a CPU sample to see where time goes."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"collect_sample(kind=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;cpu&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, processId=41213, durationSeconds=10)"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing screaming "leak," nothing screaming "GC." CPU is just... busy. Time to&lt;br&gt;
see where.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — sample.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; Taking a 10-second CPU sample.
→ collect_sample(kind="cpu", processId=41213, durationSeconds=10, topN=20)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"processId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;41213&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalSamples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18545&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hottest self-time method: System.Threading.Monitor.Enter_Slowpath
              (2933 exclusive, 15.8% of samples). Rank self-time with
              query_snapshot(view=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;top-methods&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;) or walk the call path with
              view=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;call-tree&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"handle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A0CKKWH5VVS9Q68AH3GG"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"query_snapshot(handle=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;A0CKKWH5VVS9Q68AH3GG&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, view=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;caller-callee&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, rootMethodFilter=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Monitor.Enter_Slowpath&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the first real surprise. &lt;strong&gt;15.8% of all CPU samples land inside&lt;br&gt;
&lt;code&gt;Monitor.Enter_Slowpath&lt;/code&gt;.&lt;/strong&gt; Nobody wrote a &lt;code&gt;lock&lt;/code&gt; statement in this service.&lt;br&gt;
&lt;code&gt;grep -r "lock ("&lt;/code&gt; across the whole repo returns nothing relevant. So where is&lt;br&gt;
a contended monitor coming from?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — trace the lock back to its call site.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; There's no explicit lock in this codebase. Let's see who's calling
into the monitor slow path.
→ query_snapshot(handle="A0CKKWH5VVS9Q68AH3GG", view="caller-callee",
                  rootMethodFilter="Monitor.Enter_Slowpath")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"System.Threading.Monitor.Enter_Slowpath(System.Object)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclusiveSamples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2933&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclusivePercent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;15.82&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"callers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MarketData.BufferPool.Return(byte[])"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"samples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1478&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"percent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.97&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MarketData.Broadcaster+&amp;lt;&amp;gt;c__DisplayClass.&amp;lt;ConsumeLoop&amp;gt;b__0()"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"samples"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1455&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"percent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.85&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both callers are &lt;em&gt;our&lt;/em&gt; code — a thin wrapper method calling &lt;code&gt;.Rent()&lt;/code&gt; on one&lt;br&gt;
side, and a per-connection consume loop calling &lt;code&gt;.Return()&lt;/code&gt; on the other. &lt;br&gt;
Not a &lt;code&gt;ThreadPool&lt;/code&gt; internal, not GC. The lock is being taken&lt;br&gt;
&lt;strong&gt;inside &lt;code&gt;ArrayPool&amp;lt;byte&amp;gt;.Shared&lt;/code&gt; itself&lt;/strong&gt;, and it's the &lt;em&gt;pool&lt;/em&gt;, not any&lt;br&gt;
business logic, that's contended.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — read the actual lock, not a guess about it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ArrayPool&amp;lt;byte&amp;gt;.Shared&lt;/code&gt;'s internals are in &lt;code&gt;System.Private.CoreLib&lt;/code&gt; — no&lt;br&gt;
source, no PDB for the private implementation type. This is exactly what the&lt;br&gt;
companion server, &lt;a href="https://github.com/pedrosakuma/dotnet-assembly-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;dotnet-assembly-mcp&lt;/code&gt;&lt;/a&gt;,&lt;br&gt;
is for: static navigation and on-demand decompilation of compiled assemblies,&lt;br&gt;
including the BCL itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; Let's not guess. I'll look up the actual pool implementation
in the runtime binary you're running.
→ find_method(mvidOrPath="System.Private.CoreLib.dll", namePattern="^Return$")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5 match(es) for /^Return$/."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"typeFullName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"System.Buffers.SharedArrayPool`1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"methodName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Return"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"signature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"void System.Buffers.SharedArrayPool`1.Return(!0[], bool)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"handle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"m:e8c78f6b-...:0x060038A7"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; Decompiling the real Return method for this exact runtime build.
→ decompile_method(moduleVersionId="e8c78f6b-...", metadataToken="0x060038A7")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;clearArray&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="n"&gt;SharedArrayPoolThreadLocalArray&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;array2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t_tlsBuckets&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="nf"&gt;InitializeTlsBucketsAndTrimming&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// ... same-thread fast-path slot swap ...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array3&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;flag2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_buckets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="nf"&gt;CreatePerCorePartitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;TryPush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; And the fallback path that pushes to a per-core partition:
→ find_method(mvidOrPath="System.Private.CoreLib.dll", namePattern="^TryPush$")
→ decompile_method(moduleVersionId="e8c78f6b-...", metadataToken="0x060038B3")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MethodImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MethodImplOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AggressiveInlining&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;TryPush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Array&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Monitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... push onto a small fixed-size array-backed stack ...&lt;/span&gt;
    &lt;span class="n"&gt;Monitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There it is — &lt;strong&gt;&lt;code&gt;Monitor.Enter(this)&lt;/code&gt;&lt;/strong&gt;, in the flesh, in the exact binary&lt;br&gt;
this process is running: the actual internal type backing&lt;br&gt;
&lt;code&gt;ArrayPool&amp;lt;byte&amp;gt;.Shared&lt;/code&gt; in this runtime build is &lt;code&gt;SharedArrayPool&amp;lt;T&amp;gt;&lt;/code&gt;, and&lt;br&gt;
its per-core fallback is guarded by a plain CLR monitor. This is why the&lt;br&gt;
call-tree pointed straight at &lt;code&gt;Monitor.Enter_Slowpath&lt;/code&gt;: it's a real, ordinary&lt;br&gt;
monitor, contended by every thread whose &lt;code&gt;Return&lt;/code&gt; misses the per-thread&lt;br&gt;
cache.&lt;/p&gt;

&lt;p&gt;To be clear: &lt;code&gt;dotnet/runtime&lt;/code&gt;'s source is public on GitHub — nothing here was&lt;br&gt;
hidden. The point isn't that the source was unreachable, it's the &lt;em&gt;ergonomics&lt;/em&gt;&lt;br&gt;
of the query. Getting the same answer the "normal" way means: know (or guess)&lt;br&gt;
which internal type backs &lt;code&gt;ArrayPool&amp;lt;T&amp;gt;.Shared&lt;/code&gt; today, find the right tag in&lt;br&gt;
&lt;code&gt;dotnet/runtime&lt;/code&gt; that matches the exact SDK/runtime patch this process is&lt;br&gt;
actually running, navigate to the right file, and read enough surrounding&lt;br&gt;
code to trust you're looking at the live behavior and not a since-changed&lt;br&gt;
version. &lt;code&gt;decompile_method(moduleVersionId, metadataToken)&lt;/code&gt; collapses all of&lt;br&gt;
that into one call, scoped to the exact assembly loaded in the exact process&lt;br&gt;
under investigation — no version-matching, no guessing a type name, no&lt;br&gt;
context-switch out of the chat.&lt;/p&gt;

&lt;p&gt;Checking the &lt;em&gt;application&lt;/em&gt; code (only &lt;em&gt;now&lt;/em&gt;, after both tools already&lt;br&gt;
pointed at the exact mechanism, not before):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// One dedicated broadcaster thread — the ONLY thread that ever Rents.&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FrameSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;FillFromMarketFeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// N per-connection consumer tasks — each may Return a buffer it never Rented.&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-- always a different thread than Rent&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exactly the pattern the tool output implied: &lt;strong&gt;one thread rents, many other&lt;br&gt;
threads return.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this is invisible without live evidence
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ArrayPool&amp;lt;T&amp;gt;.Shared&lt;/code&gt; isn't a naive shared bag — its current .NET 10&lt;br&gt;
implementation, &lt;code&gt;SharedArrayPool&amp;lt;T&amp;gt;&lt;/code&gt;, keeps a &lt;strong&gt;single-slot cache stored&lt;br&gt;
per-thread&lt;/strong&gt; (&lt;code&gt;[ThreadStatic]&lt;/code&gt; buckets): if the &lt;em&gt;same&lt;/em&gt; thread that rented a&lt;br&gt;
buffer also returns it, the operation is a plain field swap, no&lt;br&gt;
synchronization at all. The moment a &lt;em&gt;different&lt;/em&gt; thread returns it, that fast&lt;br&gt;
path can't apply (the slot belongs to another thread), so the buffer falls&lt;br&gt;
through to a small set of &lt;strong&gt;per-core partitions, each guarded by a plain&lt;br&gt;
&lt;code&gt;Monitor&lt;/code&gt;&lt;/strong&gt;. With a handful of cores and dozens of consumer threads all&lt;br&gt;
returning concurrently, those few partitions become a genuine contention&lt;br&gt;
point.&lt;/p&gt;

&lt;p&gt;None of this is a bug in &lt;code&gt;ArrayPool&amp;lt;T&amp;gt;&lt;/code&gt;. It's working exactly as designed —&lt;br&gt;
optimized for the common case (rent-use-return on one thread, e.g. inside a&lt;br&gt;
single request handler), and gracefully degrading, but &lt;em&gt;not silently free&lt;/em&gt;,&lt;br&gt;
for the cross-thread fan-out case. There is no compiler warning, no analyzer&lt;br&gt;
rule, and no code-review heuristic for "you are about to violate an&lt;br&gt;
implicit performance assumption of a BCL type you didn't write." The only way&lt;br&gt;
to know, for certain, what &lt;em&gt;this&lt;/em&gt; process, running &lt;em&gt;this&lt;/em&gt; runtime build, is&lt;br&gt;
actually doing is to watch where the CPU goes and read the exact binary it's&lt;br&gt;
running.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fix and verification
&lt;/h2&gt;

&lt;p&gt;The fix isn't "add a lock" (there's nothing to protect) — it's swap the pool&lt;br&gt;
implementation to one designed for the actual ownership pattern: many threads&lt;br&gt;
returning items nobody-in-particular rented, i.e., a plain lock-free queue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CrossThreadBufferPool&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ConcurrentQueue&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_pool&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryDequeue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Isolated cost, before/after&lt;/strong&gt; (BenchmarkDotNet, 20,000 cross-thread&lt;br&gt;
&lt;code&gt;Return&lt;/code&gt; calls, buffers pre-rented on a background thread outside the timed&lt;br&gt;
region so only &lt;code&gt;Return&lt;/code&gt; itself is measured):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Mean time (20,000 calls)&lt;/th&gt;
&lt;th&gt;vs. contended baseline&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ArrayPool.Shared.Return&lt;/code&gt;, cross-thread (the bug)&lt;/td&gt;
&lt;td&gt;~4.3–5.1 ms&lt;/td&gt;
&lt;td&gt;1x (baseline)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ConcurrentQueue&amp;lt;byte[]&amp;gt;&lt;/code&gt; &lt;code&gt;Return&lt;/code&gt;, cross-thread (the fix)&lt;/td&gt;
&lt;td&gt;~126–146 µs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~34x faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ArrayPool.Shared&lt;/code&gt; full Rent+Return, &lt;strong&gt;same thread&lt;/strong&gt; — theoretical best case&lt;/td&gt;
&lt;td&gt;~115–150 µs&lt;/td&gt;
&lt;td&gt;~34–40x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row is the ceiling: the one scenario with genuinely zero&lt;br&gt;
synchronization, because the per-thread cache slot is always hit. Comparing&lt;br&gt;
it to the &lt;code&gt;ConcurrentQueue&lt;/code&gt; fix shows exactly how much overhead our own fix&lt;br&gt;
still carries: &lt;strong&gt;~126 µs vs. ~115 µs — roughly 10% above the theoretical&lt;br&gt;
best&lt;/strong&gt;, for a data structure built to be used safely by an arbitrary number&lt;br&gt;
of unrelated threads. That's the honest cost of "general-purpose&lt;br&gt;
thread-safe," and it's a rounding error next to the 34x we recovered.&lt;/p&gt;

&lt;p&gt;A single cross-thread &lt;code&gt;Return&lt;/code&gt; call on the &lt;em&gt;unfixed&lt;/em&gt; pool costs more than an&lt;br&gt;
entire same-thread Rent+Return round trip. That's how disproportionate the&lt;br&gt;
fast-path miss is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live re-check after the fix&lt;/strong&gt; — same 2-thread (1 producer / 1 consumer)&lt;br&gt;
topology, same CPU sampler, before touching anything else:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;ArrayPool.Shared&lt;/code&gt; (cross-thread)&lt;/th&gt;
&lt;th&gt;Lock-free pool (cross-thread)&lt;/th&gt;
&lt;th&gt;Same-thread control&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;~3.2M ops/s&lt;/td&gt;
&lt;td&gt;~6.6M ops/s&lt;/td&gt;
&lt;td&gt;~20M ops/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Monitor.Enter_Slowpath&lt;/code&gt; in CPU sample&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;15.8%&lt;/strong&gt; exclusive&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0%&lt;/strong&gt; — gone entirely&lt;/td&gt;
&lt;td&gt;n/a (no shared pool contention path)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; With the lock-free pool under the same load:
→ collect_sample(kind="cpu", processId=41213, durationSeconds=8, topN=20)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hottest self-time method: System.Threading.Thread.Sleep(int32)
              (3972 exclusive, 40.6% of samples). No Monitor frames in the
              top 20 hotspots."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No &lt;code&gt;Monitor.Enter_Slowpath&lt;/code&gt; anywhere in the profile. The contention didn't&lt;br&gt;
move — it disappeared, because the pool that produced it is gone.&lt;/p&gt;
&lt;h2&gt;
  
  
  The obvious follow-up question: is pooling even worth it here?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ArrayPool&amp;lt;T&amp;gt;.Shared&lt;/code&gt; itself exists as an optimization over the naive&lt;br&gt;
baseline — just calling &lt;code&gt;new byte[size]&lt;/code&gt; and letting the GC reclaim it. A&lt;br&gt;
fair objection to everything above: if the &lt;em&gt;shared&lt;/em&gt; pool is this contended&lt;br&gt;
under cross-thread &lt;code&gt;Return&lt;/code&gt;, maybe the honest fix is to drop pooling&lt;br&gt;
entirely, not swap in a different pool. Mean latency might even look&lt;br&gt;
competitive, since a plain allocation has zero synchronization of any kind —&lt;br&gt;
but the expectation is that Gen0/Gen1 GC pressure would show up in the tail&lt;br&gt;
(P99), not the mean.&lt;/p&gt;

&lt;p&gt;We tested it — same 2-thread producer/consumer topology, only the pool&lt;br&gt;
implementation swapped for one that allocates fresh on every &lt;code&gt;Rent&lt;/code&gt; and does&lt;br&gt;
nothing on &lt;code&gt;Return&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Throughput&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;Monitor&lt;/code&gt; contention&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;ArrayPool.Shared&lt;/code&gt;, cross-thread&lt;/td&gt;
&lt;td&gt;~3.2M ops/s&lt;/td&gt;
&lt;td&gt;15.8% (Monitor)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lock-free queue pool, cross-thread&lt;/td&gt;
&lt;td&gt;~6.6M ops/s&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;No pooling&lt;/strong&gt; (&lt;code&gt;new byte[size]&lt;/code&gt; every call)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~180K ops/s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No pooling isn't a tail-latency-only regression — it's &lt;strong&gt;~18x slower on raw&lt;br&gt;
throughput&lt;/strong&gt;, worse than the contended &lt;code&gt;ArrayPool.Shared&lt;/code&gt; baseline we started&lt;br&gt;
from. The reason shows up immediately in a live GC pause capture over the&lt;br&gt;
same window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; Let's check what removing the pool entirely does to GC.
→ collect_events(kind="gc", processId=41213, durationSeconds=10)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"134 collection(s), max pause 69.9ms, total pause 5118.1ms."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; Breaking that down:
→ query_snapshot(handle="...", view="pauseHistogram")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalCollections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"maxPauseTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"00:00:00.0698743"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buckets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;1ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1-10ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10-100ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100-1000ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=1s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant&amp;gt; And by generation:
→ query_snapshot(handle="...", view="byGeneration")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"bucket"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gen1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"totalPause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"00:00:05.1180759"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"meanPause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"00:00:00.0381945"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxPause"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"00:00:00.0698743"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;134 gen1 collections in a 10-second window — 13.4 per second, every single&lt;br&gt;
one landing in the 10–100ms bucket — for 5.12 seconds of accumulated pause&lt;br&gt;
time inside those 10 seconds.&lt;/strong&gt; Over half the wall clock is GC pause, not&lt;br&gt;
application throughput. That's not a tail-latency footnote; it dominates the&lt;br&gt;
mean too, once allocation volume is high enough to keep pushing 4KB buffers&lt;br&gt;
into gen0 fast enough to promote and collect on a ~130ms cadence.&lt;/p&gt;

&lt;p&gt;So the honest ranking, worst to best, for this specific cross-thread&lt;br&gt;
fan-out pattern is: &lt;strong&gt;no pooling (worst, by both mean and tail) → shared pool&lt;br&gt;
with cross-thread &lt;code&gt;Return&lt;/code&gt; (contended but bounded) → a pool built for the&lt;br&gt;
actual ownership shape (best on every axis measured)&lt;/strong&gt;. &lt;code&gt;ArrayPool&amp;lt;T&amp;gt;.Shared&lt;/code&gt;&lt;br&gt;
being contended here doesn't mean pooling was the wrong call — it means the&lt;br&gt;
&lt;em&gt;specific&lt;/em&gt; pool's ownership assumption (same-thread Rent/Return) didn't match&lt;br&gt;
this workload's shape. The fix was never "go back to allocating"; it was&lt;br&gt;
"pool it the way this workload actually uses it."&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Static analysis, linters, and code review are excellent at catching &lt;em&gt;shapes&lt;/em&gt;&lt;br&gt;
of bugs — a missing &lt;code&gt;await&lt;/code&gt;, a &lt;code&gt;lock&lt;/code&gt; around the wrong object, an &lt;code&gt;O(n²)&lt;/code&gt;&lt;br&gt;
loop. They cannot catch a case where the code is a textbook-correct call into&lt;br&gt;
a well-designed BCL type, and the only thing wrong is a runtime ownership&lt;br&gt;
pattern that BCL type happens to be sensitive to. You either know this&lt;br&gt;
specific gotcha already, or you find it by watching the process — there is no&lt;br&gt;
third option.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet-diagnostics-mcp&lt;/code&gt; exists so that "watching the process" is a normal&lt;br&gt;
step in an LLM-driven investigation, not a specialized skill gated behind&lt;br&gt;
whoever on the team happens to know &lt;code&gt;dotnet-trace&lt;/code&gt; by heart. Every dynamic&lt;br&gt;
step above — &lt;code&gt;inspect_process&lt;/code&gt;, &lt;code&gt;collect_sample&lt;/code&gt;, &lt;code&gt;query_snapshot&lt;/code&gt; — is a&lt;br&gt;
single MCP tool call an assistant can make on its own, against a real running&lt;br&gt;
.NET process, with no code changes and no redeploy. And when the trail leads&lt;br&gt;
into a BCL type nobody on the team has source for, its companion server,&lt;br&gt;
&lt;a href="https://github.com/pedrosakuma/dotnet-assembly-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;dotnet-assembly-mcp&lt;/code&gt;&lt;/a&gt;,&lt;br&gt;
picks up exactly where live tracing stops: real decompiled source of the&lt;br&gt;
exact binary the process is running, not a recollection of how some type&lt;br&gt;
&lt;em&gt;used to&lt;/em&gt; work.&lt;/p&gt;

&lt;p&gt;The reproduction and all numbers in this post are in a small, standalone,&lt;br&gt;
open repro you can run yourself — no proprietary code involved. The&lt;br&gt;
investigation pattern itself (fix unrelated to this repro) is inspired by a&lt;br&gt;
real production change in &lt;a href="https://github.com/pedrosakuma/B3MarketDataPlatform" rel="noopener noreferrer"&gt;&lt;code&gt;B3MarketDataPlatform&lt;/code&gt;&lt;/a&gt;,&lt;br&gt;
a public repo, commit &lt;a href="https://github.com/pedrosakuma/B3MarketDataPlatform/commit/ac2dc9f" rel="noopener noreferrer"&gt;&lt;code&gt;ac2dc9f&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;code&gt;dotnet-diagnostics-mcp&lt;/code&gt; is open source: &lt;a href="https://github.com/pedrosakuma/dotnet-diagnostics" rel="noopener noreferrer"&gt;github.com/pedrosakuma/dotnet-diagnostics&lt;/a&gt;.&lt;br&gt;
It ships both an MCP server (for your LLM client of choice) and a standalone&lt;br&gt;
CLI (&lt;code&gt;dotnet-diagnostics-cli&lt;/code&gt;) for scripting the same investigations by hand.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>performance</category>
      <category>opensource</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
