timingbench/bench.go

110 lines
2.5 KiB
Go

package timingbench
import (
"context"
"errors"
"fmt"
"sort"
"time"
"github.com/schollz/progressbar/v3"
"gonum.org/v1/gonum/stat"
)
// TimingResult holds the timing results for a function execution.
type TimingResult struct {
Min time.Duration
Max time.Duration
Mean time.Duration
Median time.Duration
StdDev time.Duration
StartTime time.Time
EndTime time.Time
Duration time.Duration
Iterations int
}
// String returns a formatted string representation of the TimingResult.
func (r TimingResult) String() string {
return fmt.Sprintf(
"Timing Results:\n"+
"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. It supports context for cancellation.
func TimeFunction(ctx context.Context, fn func(), iterations int) (TimingResult, error) {
if iterations <= 0 {
return TimingResult{}, errors.New(
"iterations must be greater than 0")
}
times := make([]float64, 0, iterations)
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++ {
select {
case <-ctx.Done():
return TimingResult{}, ctx.Err()
default:
iterStart := time.Now().UTC()
fn()
elapsed := time.Since(iterStart)
times = append(times, float64(elapsed))
_ = bar.Add(1)
}
}
endTime := time.Now().UTC()
totalDuration := endTime.Sub(startTime)
sort.Float64s(times)
min := time.Duration(times[0])
max := time.Duration(times[len(times)-1])
mean := time.Duration(stat.Mean(times, nil))
median := time.Duration(stat.Quantile(0.5, stat.Empirical, times, nil))
stdDev := time.Duration(stat.StdDev(times, nil))
return TimingResult{
Min: min,
Max: max,
Mean: mean,
Median: median,
StdDev: stdDev,
StartTime: startTime,
EndTime: endTime,
Duration: totalDuration,
Iterations: iterations,
}, nil
}