4 ms·
I use an extension for arrays, something like: internal static class ArrayExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)]
by buybackoff 1y ago
I use an extension for arrays, something like:
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:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABABgAJiBGAOgCUBXAOwwEt8YaBhCfAB1YAbGFADKIgG6swMXAG4AsACgylWoxbtOASRYiIfcVCkz5y4gGZKAJnJdyAb2XkXlK9SSUU5AIIATPwAhbAwwAAsAClYWAG0AXXJsNHJojHjyYGTU8khmDABKZ1cnJVcy8lgAMxSWCuxyAF4KmGqAWRh8aABPVuwoXDDsQRoAcRgMHygobC6AERDsOhaRGCYZCOx8xVLylyqajArgRua2ju7e/sHhsYmpmfmMReXYNZgI4C2i3crocgimNlWCdSMkmCcAal8rkWHIUuQADzkJhw1gAajRhR2uzKAFUmLhsJVOP4/BF9tMsvlyGimvjCcSaKTyS0jlTtmUAL7fcg8yxqTzEbyk4KhMLWKKxBJJA7pTIHHIQPJYsolHHkAD0GvIogw0GiAHNEqcVm8UrhyBBKhhVuROrByDAEHxVrhWBIYOQMINDrA4E8ANaGlKHaLGwQQAzJWAARwYrFgFuAq3C+D6QaYBp5ZV+UH+gNqwKapFRiP+8ZY0KVsJSGJV6tc9KJJICLLO9p6fQGQ1G40m0zmCyWxNe602VJpdIJzaZrf27Q7l27Nz790HT2HpvWn3ZPO52N5B/5Hi8vgCovCFklaWlWSlGTvhxhBR5apxWp1eqgwfqVS3ntYC0rRtcF7U9J0XQJd1PW9EJmn9bAMyNVhQ3BeoIyjZo4wTWQMhTMI0ygJDs1cXN8yBEFSyRCIKwKZ9UTrEjdmwegWh8DAm2JKJqVpDJWMqdjOPeVgvgPfcyj5dwqE8ZgGU9IUzyCEJwgAVmvdIZVSOVH0VZVXyY8hKlYBAYD8f5UgAKkSAAFE5NgMoyTLM68rOAWymk+Ay3wbQzoGvFIGhLeEkXo2tMQM9VsGsmJWASXi3JiuIORxcTXFSw992UVIRCYIYBRsXw1wAUQQEC3QgAllG88gYnab0ID8bR+EECI6rCBqmr4QQAHk+DYCrcCZA0DUTN0PV0QRokNfI4kk/L9gAFXIYdBOnYkEQWgA+CJvUA8gFo0tcwSBJg/CdesXBKABiVhqlmIrAlxEYDOIAB2U5EjXGLTqdJLlCumBBFwGAXve/YhNnMl53OKBOyuHtbn7B4hxeFN3j6Ad8mSAFaPyaIzoQUSAdO2692UTkgA=== 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 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 1y agoThe world falls into two categories for me. "Must be fast" and "I don't care (much)". C/C++ is ideal for the first one, and C# is awesome for the second. 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 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 1y agoIt just looks like you are much more fluent in C/C++ than in C#.