Compare commits

..

2 Commits

Author SHA1 Message Date
fb13c5c56a works now, good enough for my use case 2024-05-18 19:51:45 -07:00
82cfc3c88e latest 2024-05-18 18:49:03 -07:00
5 changed files with 145 additions and 41 deletions

View File

@ -2,3 +2,10 @@ default: test
test: test:
go test -v -count=1 ./... go test -v -count=1 ./...
fmt:
go fmt ./...
lint:
golangci-lint run
sh -c 'test -z "$$(gofmt -l .)"'

View File

@ -7,6 +7,7 @@ import (
"sort" "sort"
"time" "time"
"github.com/schollz/progressbar/v3"
"gonum.org/v1/gonum/stat" "gonum.org/v1/gonum/stat"
) )
@ -16,6 +17,7 @@ type TimingResult struct {
Max time.Duration Max time.Duration
Mean time.Duration Mean time.Duration
Median time.Duration Median time.Duration
StdDev time.Duration
StartTime time.Time StartTime time.Time
EndTime time.Time EndTime time.Time
Duration time.Duration Duration time.Duration
@ -25,32 +27,64 @@ type TimingResult struct {
// String returns a formatted string representation of the TimingResult. // String returns a formatted string representation of the TimingResult.
func (r TimingResult) String() string { func (r TimingResult) String() string {
return fmt.Sprintf( return fmt.Sprintf(
"Start Time: %v, End Time: %v, Duration: %v, Iterations: %d, Min: %v, Max: %v, Mean: %v, Median: %v", "Timing Results:\n"+
r.StartTime, r.EndTime, r.Duration, r.Iterations, r.Min, r.Max, r.Mean, r.Median, "Start Time: %v\n"+
"End Time: %v\n"+
"Total Duration: %v\n"+
"Iterations: %d\n"+
"Min Duration: %v\n"+
"Max Duration: %v\n"+
"Mean Duration: %v\n"+
"Median Duration: %v\n"+
"Standard Deviation: %v\n",
r.StartTime.Format(time.RFC3339),
r.EndTime.Format(time.RFC3339),
r.Duration,
r.Iterations,
r.Min,
r.Max,
r.Mean,
r.Median,
r.StdDev,
) )
} }
// TimeFunction runs the given function fn a specified number of times and returns the timing results. // TimeFunction runs the given function fn a specified number of times
// It supports context for cancellation. // and returns the timing results. It supports context for cancellation.
func TimeFunction(ctx context.Context, fn func() error, iterations int) (TimingResult, error) { func TimeFunction(
ctx context.Context,
fn func(),
iterations int,
) (TimingResult, error) {
if iterations <= 0 { if iterations <= 0 {
return TimingResult{}, errors.New("iterations must be greater than 0") return TimingResult{}, errors.New(
"iterations must be greater than 0")
} }
times := make([]float64, 0, iterations) times := make([]float64, 0, iterations)
startTime := time.Now().UTC() startTime := time.Now().UTC()
// Create a progress bar with throttling
bar := progressbar.NewOptions(iterations,
progressbar.OptionSetDescription("Processing..."),
progressbar.OptionShowCount(),
progressbar.OptionShowIts(),
progressbar.OptionSetPredictTime(true),
progressbar.OptionClearOnFinish(),
progressbar.OptionThrottle(100*time.Millisecond), // Update every 100ms
)
for i := 0; i < iterations; i++ { for i := 0; i < iterations; i++ {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return TimingResult{}, ctx.Err() return TimingResult{}, ctx.Err()
default: default:
iterStart := time.Now().UTC() iterStart := time.Now().UTC()
if err := fn(); err != nil { fn()
return TimingResult{}, err
}
elapsed := time.Since(iterStart) elapsed := time.Since(iterStart)
times = append(times, float64(elapsed)) times = append(times, float64(elapsed))
bar.Add(1)
} }
} }
@ -63,12 +97,14 @@ func TimeFunction(ctx context.Context, fn func() error, iterations int) (TimingR
max := time.Duration(times[len(times)-1]) max := time.Duration(times[len(times)-1])
mean := time.Duration(stat.Mean(times, nil)) mean := time.Duration(stat.Mean(times, nil))
median := time.Duration(stat.Quantile(0.5, stat.Empirical, times, nil)) median := time.Duration(stat.Quantile(0.5, stat.Empirical, times, nil))
stdDev := time.Duration(stat.StdDev(times, nil))
return TimingResult{ return TimingResult{
Min: min, Min: min,
Max: max, Max: max,
Mean: mean, Mean: mean,
Median: median, Median: median,
StdDev: stdDev,
StartTime: startTime, StartTime: startTime,
EndTime: endTime, EndTime: endTime,
Duration: totalDuration, Duration: totalDuration,

View File

@ -59,7 +59,6 @@ func quickSort(arr []int) {
for i := range arr { for i := range arr {
if arr[i] < arr[right] { if arr[i] < arr[right] {
arr[i], arr[left] = arr[left], arr[i] arr[i], arr[left] = arr[left], arr[i]
left++ left++
} }
@ -71,40 +70,12 @@ func quickSort(arr []int) {
quickSort(arr[left+1:]) quickSort(arr[left+1:])
} }
// multiplyMatrices performs matrix multiplication of two randomly generated matrices.
func multiplyMatrices(size int) {
matrixA := make([][]int, size)
matrixB := make([][]int, size)
result := make([][]int, size)
for i := 0; i < size; i++ {
matrixA[i] = make([]int, size)
matrixB[i] = make([]int, size)
result[i] = make([]int, size)
for j := 0; j < size; j++ {
matrixA[i][j] = rand.Intn(100)
matrixB[i][j] = rand.Intn(100)
}
}
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
sum := 0
for k := 0; k < size; k++ {
sum += matrixA[i][k] * matrixB[k][j]
}
result[i][j] = sum
}
}
}
// sampleFunction performs a mix of different operations to introduce variability in runtime. // sampleFunction performs a mix of different operations to introduce variability in runtime.
func sampleFunction() error { func sampleFunction() {
randomSleep() randomSleep()
generatePrimes(500 + rand.Intn(1500)) generatePrimes(500 + rand.Intn(1500))
sortRandomSlice(500 + rand.Intn(1500)) sortRandomSlice(500 + rand.Intn(1500))
multiplyMatrices(20 + rand.Intn(10)) multiplyMatrices(20 + rand.Intn(10))
return nil
} }
func TestTimeFunction(t *testing.T) { func TestTimeFunction(t *testing.T) {
@ -112,7 +83,7 @@ func TestTimeFunction(t *testing.T) {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
// Define the number of iterations. // Define the number of iterations.
iterations := 1000 iterations := 700
// Create a context with a timeout for cancellation. // Create a context with a timeout for cancellation.
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
@ -127,3 +98,58 @@ func TestTimeFunction(t *testing.T) {
// Print the timing results. // Print the timing results.
t.Logf(result.String()) t.Logf(result.String())
} }
func multiplyMatrices(size int) int {
matrixA := make([][]int, size)
matrixB := make([][]int, size)
result := make([][]int, size)
for i := 0; i < size; i++ {
matrixA[i] = make([]int, size)
matrixB[i] = make([]int, size)
result[i] = make([]int, size)
for j := 0; j < size; j++ {
matrixA[i][j] = rand.Intn(10)
matrixB[i][j] = rand.Intn(10)
}
}
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
sum := 0
for k := 0; k < size; k++ {
sum += matrixA[i][k] * matrixB[k][j]
}
result[i][j] = sum
}
}
// sum the result matrix
sum := 0
for i := 0; i < size; i++ {
for j := 0; j < size; j++ {
sum += result[i][j]
}
}
return sum
}
func TestMatrixMultiply(t *testing.T) {
// Define the matrix size and number of iterations.
matrixSize := 11
iterations := 1000000
// Create a context with a timeout for cancellation.
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// Measure the execution times of the matrix multiplication function.
result, err := TimeFunction(ctx, func() {
_ = multiplyMatrices(matrixSize)
}, iterations)
if err != nil {
t.Fatalf("Error measuring function: %v", err)
}
// Print the timing results.
t.Logf(result.String())
}

12
go.mod
View File

@ -2,4 +2,14 @@ module git.eeqj.de/sneak/timingbench
go 1.22.2 go 1.22.2
require gonum.org/v1/gonum v0.15.0 // indirect require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/schollz/progressbar/v3 v3.14.2 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
)

25
go.sum
View File

@ -1,2 +1,27 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw=
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/schollz/progressbar/v3 v3.14.2 h1:EducH6uNLIWsr560zSV1KrTeUb/wZGAHqyMFIEa99ks=
github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=