Skip to content

all: replace math/rand with math/rand/v2 #6732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions baggage/baggage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package baggage

import (
"fmt"
"math/rand"
"math/rand/v2"
"slices"
"strings"
"testing"
Expand All @@ -17,12 +17,8 @@ import (
"go.opentelemetry.io/otel/internal/baggage"
)

var rng *rand.Rand

func init() {
// Seed with a static value to ensure deterministic results.
rng = rand.New(rand.NewSource(1))
}
// Seed with a static value to ensure deterministic results.
var rng = rand.New(rand.NewChaCha8([32]byte{}))

func TestValidateKeyChar(t *testing.T) {
// ASCII only
Expand Down Expand Up @@ -255,7 +251,7 @@ func key(n int) string {

b := make([]rune, n)
for i := range b {
b[i] = r[rng.Intn(len(r))]
b[i] = r[rng.IntN(len(r))]
}
return string(b)
}
Expand Down
4 changes: 2 additions & 2 deletions bridge/opencensus/internal/ocmetric/metric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"errors"
"fmt"
"math"
"math/rand"
"math/rand/v2"
"reflect"
"strconv"
"testing"
Expand Down Expand Up @@ -1189,7 +1189,7 @@ func BenchmarkConvertExemplar(b *testing.B) {
for i := range data {
a := make(ocmetricdata.Attachments, attchmentsN)
for j := 0; j < attchmentsN; j++ {
a[strconv.Itoa(j)] = rand.Int63()
a[strconv.Itoa(j)] = rand.Int64()
}
data[i] = &ocmetricdata.Exemplar{
Value: rand.NormFloat64(),
Expand Down
8 changes: 5 additions & 3 deletions bridge/opentracing/internal/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package internal // import "go.opentelemetry.io/otel/bridge/opentracing/internal

import (
"context"
"math/rand"
"math/rand/v2"
"reflect"
"sync"
"time"
Expand Down Expand Up @@ -44,7 +44,7 @@ type MockTracer struct {
TraceFlags trace.TraceFlags

randLock sync.Mutex
rand *rand.Rand
rand *rand.ChaCha8
}

var (
Expand All @@ -53,13 +53,15 @@ var (
)

func NewMockTracer() *MockTracer {
u := rand.Uint32()
seed := [32]byte{byte(u), byte(u >> 8), byte(u >> 16), byte(u >> 24)}
return &MockTracer{
FinishedSpans: nil,
SpareTraceIDs: nil,
SpareSpanIDs: nil,
SpareContextKeyValues: nil,

rand: rand.New(rand.NewSource(time.Now().Unix())),
rand: rand.NewChaCha8(seed),
}
}

Expand Down
6 changes: 3 additions & 3 deletions metric/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"context"
"database/sql"
"fmt"
"math/rand"
"math/rand/v2"
"net/http"
"runtime"
"time"
Expand Down Expand Up @@ -159,7 +159,7 @@ func ExampleMeter_gauge() {
getCPUFanSpeed := func() int64 {
// Generates a random fan speed for demonstration purpose.
// In real world applications, replace this to get the actual fan speed.
return int64(1500 + rand.Intn(1000))
return int64(1500 + rand.IntN(1000))
}

fanSpeedSubscription := make(chan int64, 1)
Expand All @@ -170,7 +170,7 @@ func ExampleMeter_gauge() {
// Synchronous gauges are used when the measurement cycle is
// synchronous to an external change.
// Simulate that external cycle here.
time.Sleep(time.Duration(rand.Intn(3)) * time.Second)
time.Sleep(time.Duration(rand.IntN(3)) * time.Second)
fanSpeed := getCPUFanSpeed()
fanSpeedSubscription <- fanSpeed
}
Expand Down
36 changes: 9 additions & 27 deletions sdk/metric/exemplar/fixed_size_reservoir.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package exemplar // import "go.opentelemetry.io/otel/sdk/metric/exemplar"
import (
"context"
"math"
"math/rand"
"math/rand/v2"
"time"

"go.opentelemetry.io/otel/attribute"
Expand Down Expand Up @@ -44,18 +44,11 @@ type FixedSizeReservoir struct {
// w is the largest random number in a distribution that is used to compute
// the next next.
w float64

// rng is used to make sampling decisions.
//
// Do not use crypto/rand. There is no reason for the decrease in performance
// given this is not a security sensitive decision.
rng *rand.Rand
}

func newFixedSizeReservoir(s *storage) *FixedSizeReservoir {
r := &FixedSizeReservoir{
storage: s,
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
}
r.reset()
return r
Expand All @@ -64,26 +57,15 @@ func newFixedSizeReservoir(s *storage) *FixedSizeReservoir {
// randomFloat64 returns, as a float64, a uniform pseudo-random number in the
// open interval (0.0,1.0).
func (r *FixedSizeReservoir) randomFloat64() float64 {
// TODO: This does not return a uniform number. rng.Float64 returns a
// uniformly random int in [0,2^53) that is divided by 2^53. Meaning it
// returns multiples of 2^-53, and not all floating point numbers between 0
// and 1 (i.e. for values less than 2^-4 the 4 last bits of the significand
// are always going to be 0).
//
// An alternative algorithm should be considered that will actually return
// a uniform number in the interval (0,1). For example, since the default
// rand source provides a uniform distribution for Int63, this can be
// converted following the prototypical code of Mersenne Twister 64 (Takuji
// Nishimura and Makoto Matsumoto:
// http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/VERSIONS/C-LANG/mt19937-64.c)
// TODO: Use an algorithm that avoids rejection sampling. For example:
//
// (float64(rng.Int63()>>11) + 0.5) * (1.0 / 4503599627370496.0)
//
// There are likely many other methods to explore here as well.

f := r.rng.Float64()
// const precision = 1 << 53 // 2^53
// // Generate an integer in [1, 2^53 - 1]
// v := rand.Uint64() % (precision - 1) + 1
// return float64(v) / float64(precision)
f := rand.Float64()
for f == 0 {
f = r.rng.Float64()
f = rand.Float64()
}
return f
}
Expand Down Expand Up @@ -146,7 +128,7 @@ func (r *FixedSizeReservoir) Offer(ctx context.Context, t time.Time, n Value, a
} else {
if r.count == r.next {
// Overwrite a random existing measurement with the one offered.
idx := int(r.rng.Int63n(int64(cap(r.store))))
idx := int(rand.Int64N(int64(cap(r.store))))
r.store[idx] = newMeasurement(ctx, t, n, a)
r.advance()
}
Expand Down
8 changes: 5 additions & 3 deletions sdk/metric/exemplar/fixed_size_reservoir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ package exemplar
import (
"context"
"math"
"math/rand"
"math/rand/v2"
"slices"
"testing"
"time"

"github.com/stretchr/testify/assert"
)
Expand All @@ -28,7 +27,10 @@ func TestNewFixedSizeReservoirSamplingCorrectness(t *testing.T) {
intensity := 0.1
sampleSize := 1000

rng := rand.New(rand.NewSource(time.Now().UnixNano()))
u := rand.Uint32()
seed := [32]byte{byte(u), byte(u >> 8), byte(u >> 16), byte(u >> 24)}
t.Logf("rng seed: %x", seed)
rng := rand.New(rand.NewChaCha8(seed))

data := make([]float64, sampleSize*1000)
for i := range data {
Expand Down
8 changes: 4 additions & 4 deletions sdk/resource/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package resource_test

import (
"fmt"
"math/rand"
"math/rand/v2"
"testing"

"go.opentelemetry.io/otel/attribute"
Expand All @@ -21,18 +21,18 @@ func makeAttrs(n int) (_, _ *resource.Resource) {
for i := 0; i < n; i++ {
var k string
for {
k = fmt.Sprint("k", rand.Intn(1000000000))
k = fmt.Sprint("k", rand.IntN(1000000000))
if !used[k] {
used[k] = true
break
}
}
l1[i] = attribute.String(k, fmt.Sprint("v", rand.Intn(1000000000)))
l1[i] = attribute.String(k, fmt.Sprint("v", rand.IntN(1000000000)))

if rand.Float64() < conflict {
l2[i] = l1[i]
} else {
l2[i] = attribute.String(k, fmt.Sprint("v", rand.Intn(1000000000)))
l2[i] = attribute.String(k, fmt.Sprint("v", rand.IntN(1000000000)))
}
}
return resource.NewSchemaless(l1...), resource.NewSchemaless(l2...)
Expand Down
26 changes: 7 additions & 19 deletions sdk/trace/id_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ package trace // import "go.opentelemetry.io/otel/sdk/trace"

import (
"context"
crand "crypto/rand"
"encoding/binary"
"math/rand"
"sync"
"math/rand/v2"

"go.opentelemetry.io/otel/trace"
)
Expand All @@ -29,20 +27,15 @@ type IDGenerator interface {
// must never be done outside of a new major release.
}

type randomIDGenerator struct {
sync.Mutex
randSource *rand.Rand
}
type randomIDGenerator struct{}

var _ IDGenerator = &randomIDGenerator{}

// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID {
gen.Lock()
defer gen.Unlock()
sid := trace.SpanID{}
for {
_, _ = gen.randSource.Read(sid[:])
binary.NativeEndian.PutUint64(sid[:], rand.Uint64())
if sid.IsValid() {
break
}
Expand All @@ -53,18 +46,17 @@ func (gen *randomIDGenerator) NewSpanID(ctx context.Context, traceID trace.Trace
// NewIDs returns a non-zero trace ID and a non-zero span ID from a
// randomly-chosen sequence.
func (gen *randomIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) {
gen.Lock()
defer gen.Unlock()
tid := trace.TraceID{}
sid := trace.SpanID{}
for {
_, _ = gen.randSource.Read(tid[:])
binary.NativeEndian.PutUint64(tid[:8], rand.Uint64())
binary.NativeEndian.PutUint64(tid[8:], rand.Uint64())
if tid.IsValid() {
break
}
}
for {
_, _ = gen.randSource.Read(sid[:])
binary.NativeEndian.PutUint64(sid[:], rand.Uint64())
if sid.IsValid() {
break
}
Expand All @@ -73,9 +65,5 @@ func (gen *randomIDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.
}

func defaultIDGenerator() IDGenerator {
gen := &randomIDGenerator{}
var rngSeed int64
_ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed)
gen.randSource = rand.New(rand.NewSource(rngSeed))
return gen
return &randomIDGenerator{}
}
2 changes: 1 addition & 1 deletion sdk/trace/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"math/rand/v2"
"testing"

"github.com/stretchr/testify/assert"
Expand Down
2 changes: 1 addition & 1 deletion sdk/trace/sampling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ package trace
import (
"context"
"fmt"
"math/rand"
"math/rand/v2"
"testing"

"github.com/stretchr/testify/assert"
Expand Down
Loading