I'm trying to find the fastest way to multiply every element in an array by a given number, in this case 2. So far I have written a SIMD instruction that performs at 33 ns multiplying every number in an array of size 1000 by 2.
The techniques used so far are: SIMD instructions, MemoryMarshal method for the loop, Spans, Vector256 Unsafe loading and storing, BitHacks for the multiplication and calculating upper limit of SIMD instructions.
Does anyone know of anything else I can try? You an view each iteration of what I've tried in the following thread. I've learned so much already I am definitely going to attempt another challenge soon.
var testSpace = TestSpaceManager.BigArrayOfInts.Value;
Vector<int> multiplier = new(2);
Span<int> result = stackalloc int[testSpace.Length];
testSpace.CopyTo(result);
var batchSize = Vector<int>.Count;
var remainder = testSpace.Length % batchSize;
var upperLimit = testSpace.Length - remainder;
for (int i = 0; i < upperLimit; i += batchSize)
{
var currentSlice = result.Slice(i, batchSize);
Vector<int> v = new (currentSlice);
(v*multiplier).CopyTo(currentSlice);
}
for (int i = upperLimit; i < testSpace.Length; i++) result[i] *= 2;
The testSpace
is a lazy initialised array of size 1000.
I have included a the Benchmarks of the 11 ways of achieving this task where the version above is 'SIMD_no_heap_allocation'. Please see the thread for the code of the other versions and to see how far we have come.
Times in ns:
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|------------------------------------------------------ |-------------:|-----------:|-----------:|-------:|-------:|----------:|
| PLINQ | 22,086.67 ns | 301.232 ns | 235.182 ns | 2.9907 | 0.0305 | 17968 B |
| LINQ | 1,674.13 ns | 3.968 ns | 3.518 ns | 0.6485 | - | 4072 B |
| for_loop | 597.42 ns | 2.075 ns | 1.839 ns | 0.6409 | - | 4024 B |
| memory_marshall_method_bit_hacked | 373.40 ns | 0.442 ns | 0.392 ns | - | - | - |
| SIMD | 208.13 ns | 0.870 ns | 0.727 ns | 0.6413 | - | 4024 B |
| SIMD_no_heap_allocation | 209.12 ns | 0.448 ns | 0.374 ns | - | - | - |
| SIMD_no_heap_allocation_bit_hacked | 129.27 ns | 0.766 ns | 0.679 ns | - | - | - |
| SIMD_memory_marshall_method | 59.86 ns | 0.942 ns | 0.925 ns | - | - | - |
| SIMD_Vector256_Memory_marshal | 58.63 ns | 0.171 ns | 0.160 ns | - | - | - |
| SIMD_Vector256_Memory_Marshal_unrolled | 37.67 ns | 0.114 ns | 0.101 ns | - | - | - |
| SIMD_Vector256_Memory_Marshal_unrolled_quicker_bounds | 33.85 ns | 0.110 ns | 0.103 ns | - | - | - |