News for hackers. Stuff that matters.
Re:Faster Sorting with Go Generics by tedunangst on Saturday April 02, 2022 @01:22PM (#30889925)
> The first thing to note is that there is no dynamic dispatch to the Less method. Each loop iteration invokes cmpstring directly.

Except about 95% of the arrays I sort aren't comparable with just <. It's less clear how the unmentioned sort.Slice() will improve.

Re:Faster Sorting with Go Generics by eliben on Saturday April 02, 2022 @05:20PM (#30891782)
The change mentioned at the top of the post (https://go-review.googlesource.com/c/exp/+/378134) also has a benchmark to compare sorting structs using sort.Slice vs a new generic approach that uses a comparison function:

    name           old time/op  new time/op  delta
    SortStructs-8  18.6ms ± 2%  15.9ms ± 3%  -14.43%  (p=0.000 n=10+10)
14.4% is the speedup of the generic version.

The article explains why this happens (towards the end).

Re:Faster Sorting with Go Generics by tedunangst on Saturday April 02, 2022 @07:25PM (#30892590)
Unsolicited commentary: I think my commitment to a thorough reading was limited by my interest in the performance of bubble sort. On the other hand, the code for sort.Search also fits in a blog post, and it's a function I have called inside a loop.
Re:Faster Sorting with Go Generics by eliben on Saturday April 02, 2022 @11:53PM (#30894278)
That's a good point, thank you for bringing it up. Finding the right examples is really tricky. sort.Search is binary search and hence a bit tricky to benchmark properly because of how ridiculously fast it is. Only a handful of comparison calls are made even for huge slices.
Re:Faster Sorting with Go Generics by klabb3 on Saturday April 02, 2022 @05:34PM (#30891883)
My understanding is that pointer types all use dynamic dispatch in practice, because they share the same "gcshape" under the hood, today. Obviously this is very coarse grained.

However, the article points out this will likely change in the future, since the compiler now has enough information to do so. The Go team made a good call imo resisting to optimize this. Now, they can observe how generics are used in the global Go community and then optimize using real world code.

In fact, optimize is an understatement, because dyn dispatch vs monomorphization is a trade-off between compilation time + binary size vs speed (as C++ and Rust programmers know too well). Optimizing early based on microbenchmarks would likely have given an advantage in favor of monomorphization, but may not be suitable for average-to-large binaries in the a generic-heavy future. I assume the team wants to find a good balance for the 99%, and avoid compiler flags, hint-syntax, profile guided optimizations and so on if they can..

Re:Faster Sorting with Go Generics by morelisp on Saturday April 02, 2022 @01:27PM (#30889961)
You'll still have a dynamic Less() equivalent - unless the sorting function gets inlined, which sounds unlikely. But sort.Slice() relies on reflection to do the swapping, which performs even worse than a call to a virtual Swap(). That would now be an ordinary index swap within the sort function. So you'll probably still see major speedups with bubbleSortFunc or some equivalent.
Re:Faster Sorting with Go Generics by masklinn on Saturday April 02, 2022 @03:42PM (#30891069)
> You'll still have a dynamic Less() equivalent - unless the sorting function gets inlined, which sounds unlikely.

Sorting or ordering?

Using a custom comparator is covered later on, and shows that the ordering function (the custom comparator) is not inlined because of how Go 1.18 groups GC shapes.

However an article from a few days ago (https://planetscale.com/blog/generics-can-make-your-go-code-...) showed that it can be made to work, in some cases, by parametrising the function on the callback. This leads to the sorting function being monomorphised on the callback, and thus the callback (likely) getting inlined.

Re:Faster Sorting with Go Generics by rmk on Saturday April 02, 2022 @02:31PM (#30890501)
The article argues that even a function call to a “less” function benefits from the elimination of bounds checking.