(no title)
buybackoff | 5 months ago
internal static class ArrayExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T RefAtUnsafe<T>(this T[] array, nint index)
{
#if DEBUG
return ref array[index];
#else
Debug.Assert((uint)index < array.Length, "RefAtUnsafe: (uint)index < array.Length");
return ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nuint)index);
#endif
}
}
then your example turns into: public static void AddBatch(int[] a, int[] b, int count)
{
// Storing a reference is often more expensive that re-taking it in a loop, requires benchmarking
for (nint i = 0; i < (uint)count; i++)
a.RefAtUnsafe(i) += b.RefAtUnsafe(i);
}
The JITted assembly: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8AB...I'm convinced C# is so much better for high perf code, because yes it can do everything (including easy-to-use x-arch SIMD), but it lets one not bother about things that do not matter and use safe code. It's so pragmatic.
See also the top comments from a recent thread, I totally agree. https://news.ycombinator.com/item?id=45253012
BTW, do not use [MethodImpl(MethodImplOptions.AggressiveOptimization)], it disables TieredPGO, which is a huge thing for latest .NET versions.
bengarney|5 months ago
My argument isn't that C# is bad or performance is unachievable. It's that the mental overhead to write something that has consistent, high performance in C/C++ is very low. In other words, for the amount of mental effort, knowledge, and iteration it takes to write something fast + maintainable in C#, would I be better served by just writing it in C/C++?
The linked assembly is almost certainly non-optimal; compare to -O3 of the C version: https://godbolt.org/z/f5qKhrq1G - I automatically get SIMD usage and many other optimizations.
You can certainly make the argument that if X, Y, Z is done, your thing would be fast/faster. But that's exactly my argument. I don't want to do X, Y, Z to get good results if I don't have to (`return ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nuint)index);` and using/not using `[MethodImpl(MethodImplOptions.AggressiveOptimization)]` are non-trivial mental overhead!).
I want to write `foo.bar` and get good, alloc free, optimized results... and more importantly, results that behave the same everywhere I deploy them, not dependent on language version, JIT specifics, etc.
If I was operating in a domain where I could not ever take the C/C++ path, these features of C# are of course very welcome. And in general more power/expressiveness is very good. But circling back, I wonder if my energy is better spent doing a C version than contorting C# to do what I want.
buybackoff|5 months ago