timingbench/bench.go

110 lines
2.5 KiB
Go
Raw Normal View History

2024-05-19 01:37:05 +00:00
package timingbench
import (
"context"
"errors"
"fmt"
"sort"
"time"
2024-05-19 02:51:45 +00:00
"github.com/schollz/progressbar/v3"
2024-05-19 01:37:05 +00:00
"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
2024-05-19 01:49:03 +00:00
StdDev time.Duration
2024-05-19 01:37:05 +00:00
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(
2024-05-19 01:49:03 +00:00
"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,
2024-05-19 01:37:05 +00:00
)
}
2024-05-19 02:51:45 +00:00
// TimeFunction runs the given function fn a specified number of times
// and returns the timing results. It supports context for cancellation.
2024-05-22 21:20:31 +00:00
func TimeFunction(ctx context.Context, fn func(), iterations int) (TimingResult, error) {
2024-05-19 01:37:05 +00:00
if iterations <= 0 {
2024-05-19 02:51:45 +00:00
return TimingResult{}, errors.New(
"iterations must be greater than 0")
2024-05-19 01:37:05 +00:00
}
times := make([]float64, 0, iterations)
startTime := time.Now().UTC()
2024-05-19 02:51:45 +00:00
// 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
)
2024-05-19 01:37:05 +00:00
for i := 0; i < iterations; i++ {
select {
case <-ctx.Done():
return TimingResult{}, ctx.Err()
default:
iterStart := time.Now().UTC()
2024-05-19 02:51:45 +00:00
fn()
2024-05-19 01:37:05 +00:00
elapsed := time.Since(iterStart)
times = append(times, float64(elapsed))
2024-05-19 02:51:45 +00:00
2024-05-22 21:20:31 +00:00
_ = bar.Add(1)
2024-05-19 01:37:05 +00:00
}
}
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))
2024-05-19 01:49:03 +00:00
stdDev := time.Duration(stat.StdDev(times, nil))
2024-05-19 01:37:05 +00:00
return TimingResult{
Min: min,
Max: max,
Mean: mean,
Median: median,
2024-05-19 01:49:03 +00:00
StdDev: stdDev,
2024-05-19 01:37:05 +00:00
StartTime: startTime,
EndTime: endTime,
Duration: totalDuration,
Iterations: iterations,
}, nil
}