I
I
Ilya2022-03-28 17:07:25
go
Ilya, 2022-03-28 17:07:25

Why is the generic type method in Go so much slower than the native one?

Indeed, according to the developers, generics are assembled into separate types at the compilation stage, and not at runtime.
The result of the benchmarks is either an unoptimized implementation, or a hard bug, or I misunderstood the words of the developers.
I demonstrate on a toy example of a function, the essence of which is simple:

func sumincr(arr []float64, incr float64) (sum float64) {
  for _, x := range arr {
    sum += x + incr
  }
  return sum
}

Bench code in sandbox due to volume
https://go.dev/play/p/3wYzYzsIT_8
Results:go test -bench=. -count=2
goos: windows
goarch: amd64
pkg: github.com/ogau/evo/bugtesting
cpu: AMD Ryzen 3 PRO 2200G with Radeon Vega Graphics
BenchmarkNativeFunc-4            4113319               298.7 ns/op
BenchmarkNativeFunc-4            3958936               295.3 ns/op
BenchmarkNativeMethod-4          4124042               290.2 ns/op
BenchmarkNativeMethod-4          3952284               295.9 ns/op
BenchmarkGenericFunc-4           2836564               409.9 ns/op
BenchmarkGenericFunc-4           2877542               423.8 ns/op
BenchmarkGenericMethod-4          443005              2628 ns/op
BenchmarkGenericMethod-4          399085              2555 ns/op

It is easy to calculate that a function that fully uses the generic mechanism with a type method consumes ~ 8.5 times more CPU time.
By the way, what accidentally struck me during the tests is that if you change the order of the benchmarks, the results become unpredictable (rechecked many times):
goos: windows
goarch: amd64
pkg: github.com/ogau/evo/bugtesting
cpu: AMD Ryzen 3 PRO 2200G with Radeon Vega Graphics
BenchmarkGenericMethod-4          476750              2654 ns/op
BenchmarkGenericMethod-4          427164              2593 ns/op
BenchmarkNativeFunc-4            2104059               571.9 ns/op
BenchmarkNativeFunc-4            2003337               565.6 ns/op
BenchmarkNativeMethod-4          2121109               579.8 ns/op
BenchmarkNativeMethod-4          2095996               575.0 ns/op
BenchmarkGenericFunc-4           2091612               574.3 ns/op
BenchmarkGenericFunc-4           2085957               574.6 ns/op

I will duplicate the question on StackOverflow, I will attach the link later.
UPD: https://stackoverflow.com/questions/71649364/why-i...

Answer the question

In order to leave comments, you need to log in

2 answer(s)
I
Ilya, 2022-03-29
@hugga

From the discussion https://github.com/golang/go/issues/50182 , it is clear that the generics performance issue is not new.
When running benchmarks with flags, I get the expected ± equal execution time of functions:
go test -bench=. -count=2 -gcflags=all=-d=unified

BenchmarkNativeFunc-4            2029149               600.5 ns/op
BenchmarkNativeFunc-4            2018277               591.7 ns/op
BenchmarkNativeMethod-4          1962086               592.0 ns/op
BenchmarkNativeMethod-4          2024234               603.9 ns/op
BenchmarkGenericFunc-4           1985313               573.4 ns/op
BenchmarkGenericFunc-4           2053454               585.1 ns/op
BenchmarkGenericMethod-4         2067790               591.3 ns/op
BenchmarkGenericMethod-4         2054346               612.2 ns/op

which forces the use of stenciling (stencil on individual types) when compiling, instead of the dictionary approach of implementing generics (current implementation).
It remains to wait for optimizations in language updates

A
Andrey Tsvetkov, 2022-03-28
@yellow79

I believe that the problem is with the implementation. There is no desire to look in your functions for who is right and who is wrong. let's do it, you write two implementations of the same action, but one is generic, the other is the old fashioned way. Then write a benchmark for these two functions.
Judging by the results of benchmarks, the results with generics consume much more memory, the reason is 100% in this

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question