Advertisement
mquinlan

FindBytesBench

Sep 23rd, 2024
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.73 KB | Source Code | 0 0
  1. using System.Numerics;
  2. using BenchmarkDotNet.Attributes;
  3. using BenchmarkDotNet.Running;
  4.  
  5. namespace FindBytesBench;
  6.  
  7. public class Program
  8. {
  9.     private const int ArraySize = 1_000_000;
  10.     private const byte TargetValue = 0x55;
  11.    
  12.     private static readonly byte[] bytes = new byte[ArraySize];
  13.    
  14.     [Benchmark]
  15.     public List<int> SequentialTest()
  16.     {
  17.         var result = new List<int>();
  18.         for (var i = 0; i < ArraySize; i++)
  19.         {
  20.             if (bytes[i] == TargetValue) result.Add(i);
  21.         }
  22.         return result;
  23.     }
  24.  
  25.     [Benchmark]
  26.     public List<int> LINQTest()
  27.         => bytes
  28.             .Select((b, i) => (b, i))
  29.             .Where(t => t.b == TargetValue)
  30.             .Select(t => t.i)
  31.             .ToList();
  32.  
  33.     [Benchmark]
  34.     public List<int> VectorTest()
  35.     {
  36.         var result = new List<int>();
  37.         var vectorSize = Vector<byte>.Count;
  38.         var targetVector = new Vector<byte>(TargetValue);
  39.         var i = 0;
  40.         for (; i <= ArraySize - vectorSize; i += vectorSize)
  41.         {
  42.             var chunk = new Vector<byte>(bytes, i);
  43.             var comparison = Vector.Equals(targetVector, chunk);
  44.             if (comparison != Vector<byte>.Zero)
  45.             {
  46.                 for (var j = 0; j < vectorSize; j++)
  47.                 {
  48.                     if (comparison[j] != 0) result.Add(i + j);
  49.                 }
  50.             }
  51.         }
  52.         for (; i < ArraySize; i++)
  53.         {
  54.             if (bytes[i] == TargetValue) result.Add(i);
  55.         }
  56.         return result;
  57.     }
  58.  
  59.     [Benchmark]
  60.     public List<int> ParallelTest()
  61.     {
  62.         var vectorSize = Vector<byte>.Count;
  63.         var targetVector = new Vector<byte>(TargetValue);
  64.         var partitionCount = ArraySize / vectorSize;
  65.         var results = new List<int>();
  66.         Parallel.For(0, partitionCount, () => new List<int>(), (i, _, localList) =>
  67.         {
  68.             var start = i * vectorSize;
  69.             var chunk = new Vector<byte>(new ReadOnlySpan<byte>(bytes, start, vectorSize));
  70.             var comparison = Vector.Equals(targetVector, chunk);
  71.             if (comparison != Vector<byte>.Zero)
  72.             {
  73.                 for (var j = 0; j < vectorSize; j++)
  74.                 {
  75.                     if (comparison[j] != 0) localList.Add(start + j);
  76.                 }
  77.             }
  78.             return localList;
  79.         }, localList =>
  80.         {
  81.             lock (results)
  82.             {
  83.                 results.AddRange(localList);
  84.             }
  85.         });
  86.         for (var i = partitionCount * vectorSize; i < ArraySize; i++)
  87.         {
  88.             if (bytes[i] == TargetValue) results.Add(i);
  89.         }
  90.         return results;
  91.     }
  92.    
  93.     [Benchmark]
  94.     public List<int> IndexOfTest()
  95.     {
  96.         var result = new List<int>();
  97.         var i = -1;
  98.         while (true)
  99.         {
  100.             i = Array.IndexOf(bytes, TargetValue, i + 1);
  101.             if (i is -1) break;
  102.             result.Add(i);
  103.         }
  104.         return result;
  105.     }
  106.    
  107.     [Benchmark]
  108.     public List<int> SpanTest()
  109.     {
  110.         var result = new List<int>();
  111.         var i = 0;
  112.         while (bytes.AsSpan(i).IndexOf(TargetValue) is var di and >= 0)
  113.         {
  114.             result.Add(i + di);
  115.             i += di + 1;
  116.         }
  117.         return result;
  118.     }
  119.    
  120.     static void Main()
  121.     {
  122.         for (var i = 0; i < ArraySize - 1; i++) bytes[i] = (byte)i;
  123.         bytes[ArraySize - 1] = TargetValue;
  124.         Validate();
  125.         _ = BenchmarkRunner.Run<Program>();
  126.  
  127.         static void Validate()
  128.         {
  129.             var program = new Program();
  130.             var sequentialResult = program.SequentialTest();
  131.             var linqResult = program.LINQTest();
  132.             var vectorResult = program.VectorTest();
  133.             var parallelResult = program.ParallelTest();
  134.             var indexOfResult = program.IndexOfTest();
  135.             var spanResult = program.SpanTest();
  136.             CompareResults(sequentialResult, linqResult, vectorResult, parallelResult, indexOfResult, spanResult);
  137.            
  138.             static void CompareResults(params List<int>[] lists)
  139.             {
  140.                 if (lists.Length is 0) return;
  141.                 var a = lists[0];
  142.                 if (a.Count is 0) throw new Exception();
  143.                 var aSet = new HashSet<int>(a);
  144.                 if (a.Count != aSet.Count) throw new Exception();
  145.                 for (var i = 1; i < lists.Length; i++)
  146.                 {
  147.                     var b = lists[i];
  148.                     if (a.Count != b.Count) throw new Exception();
  149.                     var bSet = new HashSet<int>(b);
  150.                     if (!aSet.SetEquals(bSet)) throw new Exception();
  151.                 }
  152.             }
  153.         }
  154.     }
  155. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement