Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit dee2f26

Browse files
committed
optimize SampleXXX function by SIMD
SampleCalc4KSampleSum-32 3.38µs ± 3% 0.47µs ± 1% -86.02% (p=0.100 n=3+3) SampleCalc4KSampleMax-32 5.35µs ± 5% 0.86µs ± 1% -83.83% (p=0.100 n=3+3) SampleCalc4KSampleMin-32 5.25µs ± 4% 0.88µs ± 2% -83.26% (p=0.100 n=3+3) SampleCalc4KSampleMean-32 2.53µs ±10% 0.44µs ±11% -82.76% (p=0.100 n=3+3) SampleCalc4KSampleStdDev-32 7.16µs ± 3% 5.22µs ± 2% -27.06% (p=0.100 n=3+3) SampleCalc4KSampleVariance-32 7.34µs ± 1% 5.32µs ± 2% -27.54% (p=0.100 n=3+3) SampleCalc4KSamplePercentile-32 262µs ± 6% 270µs ± 4% ~ (p=1.000 n=3+3)
1 parent cc35c56 commit dee2f26

File tree

4 files changed

+2093
-43
lines changed

4 files changed

+2093
-43
lines changed

sample.go

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,20 @@ import (
66
"sort"
77
"sync"
88
"time"
9+
10+
"golang.org/x/sys/cpu"
911
)
1012

1113
const rescaleThreshold = time.Hour
1214

15+
var x86HasSSE42, x86HasAVX, x86HasAVX2 bool
16+
17+
func init() {
18+
x86HasSSE42 = cpu.X86.HasSSE42
19+
x86HasAVX = cpu.X86.HasAVX
20+
x86HasAVX2 = cpu.X86.HasAVX2
21+
}
22+
1323
// Samples maintain a statistically-significant selection of values from
1424
// a stream.
1525
type Sample interface {
@@ -233,18 +243,8 @@ func (NilSample) Values() []int64 { return []int64{} }
233243
func (NilSample) Variance() float64 { return 0.0 }
234244

235245
// SampleMax returns the maximum value of the slice of int64.
236-
func SampleMax(values []int64) int64 {
237-
if 0 == len(values) {
238-
return 0
239-
}
240-
var max int64 = math.MinInt64
241-
for _, v := range values {
242-
if max < v {
243-
max = v
244-
}
245-
}
246-
return max
247-
}
246+
//go:noescape
247+
func SampleMax(values []int64) int64
248248

249249
// SampleMean returns the mean value of the slice of int64.
250250
func SampleMean(values []int64) float64 {
@@ -255,18 +255,8 @@ func SampleMean(values []int64) float64 {
255255
}
256256

257257
// SampleMin returns the minimum value of the slice of int64.
258-
func SampleMin(values []int64) int64 {
259-
if 0 == len(values) {
260-
return 0
261-
}
262-
var min int64 = math.MaxInt64
263-
for _, v := range values {
264-
if min > v {
265-
min = v
266-
}
267-
}
268-
return min
269-
}
258+
//go:noescape
259+
func SampleMin(values []int64) int64
270260

271261
// SamplePercentiles returns an arbitrary percentile of the slice of int64.
272262
func SamplePercentile(values int64Slice, p float64) float64 {
@@ -372,27 +362,12 @@ func SampleStdDev(values []int64) float64 {
372362
}
373363

374364
// SampleSum returns the sum of the slice of int64.
375-
func SampleSum(values []int64) int64 {
376-
var sum int64
377-
for _, v := range values {
378-
sum += v
379-
}
380-
return sum
381-
}
365+
//go:noescape
366+
func SampleSum(values []int64) int64
382367

383368
// SampleVariance returns the variance of the slice of int64.
384-
func SampleVariance(values []int64) float64 {
385-
if 0 == len(values) {
386-
return 0.0
387-
}
388-
m := SampleMean(values)
389-
var sum float64
390-
for _, v := range values {
391-
d := float64(v) - m
392-
sum += d * d
393-
}
394-
return sum / float64(len(values))
395-
}
369+
//go:noescape
370+
func SampleVariance(values []int64) float64
396371

397372
// A uniform sample using Vitter's Algorithm R.
398373
//
@@ -614,3 +589,54 @@ type int64Slice []int64
614589
func (p int64Slice) Len() int { return len(p) }
615590
func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
616591
func (p int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
592+
593+
// sampleMax returns the maximum value of the slice of int64.
594+
func sampleMax(values []int64) int64 {
595+
if 0 == len(values) {
596+
return 0
597+
}
598+
var max int64 = math.MinInt64
599+
for _, v := range values {
600+
if max < v {
601+
max = v
602+
}
603+
}
604+
return max
605+
}
606+
607+
// sampleMin returns the minimum value of the slice of int64.
608+
func sampleMin(values []int64) int64 {
609+
if 0 == len(values) {
610+
return 0
611+
}
612+
var min int64 = math.MaxInt64
613+
for _, v := range values {
614+
if min > v {
615+
min = v
616+
}
617+
}
618+
return min
619+
}
620+
621+
// sampleSum returns the sum of the slice of int64.
622+
func sampleSum(values []int64) int64 {
623+
var sum int64
624+
for _, v := range values {
625+
sum += v
626+
}
627+
return sum
628+
}
629+
630+
// sampleVariance returns the variance of the slice of int64.
631+
func sampleVariance(values []int64) float64 {
632+
if 0 == len(values) {
633+
return 0.0
634+
}
635+
m := SampleMean(values)
636+
var sum float64
637+
for _, v := range values {
638+
d := float64(v) - m
639+
sum += d * d
640+
}
641+
return sum / float64(len(values))
642+
}

0 commit comments

Comments
 (0)