| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package rangefunc_test |
| |
| import ( |
| "slices" |
| "testing" |
| ) |
| |
| // These benchmarks, Tiny and Medium, do NOT all run in the same amount |
| // of time. |
| |
| var gsum int |
| |
| func makeValues() []int { |
| values := make([]int, 64) |
| for i := range values { |
| values[i] = i + 1 |
| } |
| return values |
| } |
| |
| func BenchmarkTinyIterIter(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| // DO NOT MODERNIZE THIS LOOP. |
| for k := 0; k < b.N; k++ { |
| // DO NOT MODERNIZE THIS LOOP. |
| var sum int = 1 |
| for i := len(values) - 1; i >= 0; i-- { |
| sum *= values[i] |
| } |
| } |
| } |
| |
| func BenchmarkTinyIterIterSink(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| var sum int = 1 |
| // DO NOT MODERNIZE THIS LOOP. |
| for k := 0; k < b.N; k++ { |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| sum *= values[i] |
| } |
| } |
| gsum = sum |
| } |
| |
| // BenchmarkTinyIterRangeSink should run as quickly as BenchmarkTinyIterIterSink. |
| func BenchmarkTinyIterRangeSink(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| var sum int = 1 |
| // DO NOT MODERNIZE THIS LOOP. |
| for k := 0; k < b.N; k++ { |
| for _, v := range slices.Backward(values) { |
| sum *= v |
| } |
| } |
| gsum = sum |
| } |
| |
| func BenchmarkTinyBloopIter(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| for b.Loop() { |
| var sum int = 1 |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| sum *= values[i] |
| } |
| } |
| } |
| |
| // BenchmarkTinyBloopRange should run as quickly as BenchmarkTinyBloopIter. |
| func BenchmarkTinyBloopRange(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| for b.Loop() { |
| var sum int = 1 |
| for _, v := range slices.Backward(values) { |
| sum *= v |
| } |
| } |
| } |
| |
| func BenchmarkMediumIterIterSink(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| var sum int |
| // DO NOT MODERNIZE THIS LOOP. |
| for k := 0; k < b.N; k++ { |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| v := values[i] |
| sum += (v * (v + 1) * (v + 2)) / (v + 3) |
| sum += (v * (v + 4) * (v + 3)) / (v + 2) |
| sum += (v * (v + 5) * (v + 2)) / (v + 1) |
| } |
| } |
| gsum = sum |
| } |
| |
| func BenchmarkMediumIterRangeSink(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| var sum int |
| // DO NOT MODERNIZE THIS LOOP. |
| for k := 0; k < b.N; k++ { |
| for _, v := range slices.Backward(values) { |
| sum += (v * (v + 1) * (v + 2)) / (v + 3) |
| sum += (v * (v + 4) * (v + 3)) / (v + 2) |
| sum += (v * (v + 5) * (v + 2)) / (v + 1) |
| } |
| } |
| gsum = sum |
| } |
| |
| func BenchmarkMediumBLoopIterSink(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| var sum int |
| for b.Loop() { |
| for _, v := range slices.Backward(values) { |
| sum += (v * (v + 1) * (v + 2)) / (v + 3) |
| sum += (v * (v + 4) * (v + 3)) / (v + 2) |
| sum += (v * (v + 5) * (v + 2)) / (v + 1) |
| } |
| } |
| gsum = sum |
| } |
| |
| func BenchmarkMediumBLoopIter(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| for b.Loop() { |
| var sum int |
| for _, v := range slices.Backward(values) { |
| sum += (v * (v + 1) * (v + 2)) / (v + 3) |
| sum += (v * (v + 4) * (v + 3)) / (v + 2) |
| sum += (v * (v + 5) * (v + 2)) / (v + 1) |
| } |
| } |
| } |
| |
| func BenchmarkMediumBLoopIter_a_CSE_slow(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| // This runs somewhat slower because b.Loop will keep i alive. |
| // |
| // This relies on compiler common-subexpression-elimination to turn |
| // "values[i]" into a temporary that is NOT tracked by b.Loop. |
| for b.Loop() { |
| var sum int |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| sum += (values[i] * (values[i] + 1) * (values[i] + 2)) / (values[i] + 3) |
| sum += (values[i] * (values[i] + 4) * (values[i] + 3)) / (values[i] + 2) |
| sum += (values[i] * (values[i] + 5) * (values[i] + 2)) / (values[i] + 1) |
| } |
| } |
| } |
| |
| func BenchmarkMediumBLoopIter_b_CSE_slow(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| // This runs somewhat slower because b.Loop will keep i alive. |
| // |
| // This relies on compiler common-subexpression-elimination to turn |
| // "values[i]" into a temporary that is NOT tracked by b.Loop. |
| var sum int |
| for b.Loop() { |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| sum += (values[i] * (values[i] + 1) * (values[i] + 2)) / (values[i] + 3) |
| sum += (values[i] * (values[i] + 4) * (values[i] + 3)) / (values[i] + 2) |
| sum += (values[i] * (values[i] + 5) * (values[i] + 2)) / (values[i] + 1) |
| } |
| } |
| } |
| |
| func BenchmarkMediumBLoopIter_slow(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| // This runs slower because b.Loop will also keep i and v alive. |
| for b.Loop() { |
| var sum int |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| v := values[i] |
| sum += (v * (v + 1) * (v + 2)) / (v + 3) |
| sum += (v * (v + 4) * (v + 3)) / (v + 2) |
| sum += (v * (v + 5) * (v + 2)) / (v + 1) |
| } |
| } |
| } |
| |
| func BenchmarkMediumBLoopIterSink_slow(b *testing.B) { |
| values := makeValues() |
| b.ReportAllocs() |
| var sum int |
| // This runs slower because b.Loop will also keep i and v alive. |
| for b.Loop() { |
| // DO NOT MODERNIZE THIS LOOP. |
| for i := len(values) - 1; i >= 0; i-- { |
| v := values[i] |
| sum += (v * (v + 1) * (v + 2)) / (v + 3) |
| sum += (v * (v + 4) * (v + 3)) / (v + 2) |
| sum += (v * (v + 5) * (v + 2)) / (v + 1) |
| } |
| } |
| gsum = sum |
| } |