123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- // Copyright (C) MongoDB, Inc. 2017-present.
- //
- // Licensed under the Apache License, Version 2.0 (the "License"); you may
- // not use this file except in compliance with the License. You may obtain
- // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
- package benchmark
- import (
- "fmt"
- "time"
- "github.com/montanaflynn/stats"
- )
- type BenchResult struct {
- Name string
- Trials int
- Duration time.Duration
- Raw []Result
- DataSize int
- Operations int
- hasErrors *bool
- }
- func (r *BenchResult) EvergreenPerfFormat() ([]interface{}, error) {
- timings := r.timings()
- median, err := stats.Median(timings)
- if err != nil {
- return nil, err
- }
- min, err := stats.Min(timings)
- if err != nil {
- return nil, err
- }
- max, err := stats.Max(timings)
- if err != nil {
- return nil, err
- }
- out := []interface{}{
- map[string]interface{}{
- "name": r.Name + "-throughput",
- "results": map[string]interface{}{
- "1": map[string]interface{}{
- "seconds": r.Duration.Round(time.Millisecond).Seconds(),
- "ops_per_second": r.getThroughput(median),
- "ops_per_second_values": []float64{
- r.getThroughput(min),
- r.getThroughput(max),
- },
- },
- },
- },
- }
- if r.DataSize > 0 {
- out = append(out, interface{}(map[string]interface{}{
- "name": r.Name + "-MB-adjusted",
- "results": map[string]interface{}{
- "1": map[string]interface{}{
- "seconds": r.Duration.Round(time.Millisecond).Seconds(),
- "ops_per_second": r.adjustResults(median),
- "ops_per_second_values": []float64{
- r.adjustResults(min),
- r.adjustResults(max),
- },
- },
- },
- }))
- }
- return out, nil
- }
- func (r *BenchResult) timings() []float64 {
- out := []float64{}
- for _, r := range r.Raw {
- out = append(out, r.Duration.Seconds())
- }
- return out
- }
- func (r *BenchResult) totalDuration() time.Duration {
- var out time.Duration
- for _, trial := range r.Raw {
- out += trial.Duration
- }
- return out
- }
- func (r *BenchResult) adjustResults(data float64) float64 { return float64(r.DataSize) / data }
- func (r *BenchResult) getThroughput(data float64) float64 { return float64(r.Operations) / data }
- func (r *BenchResult) roundedRuntime() time.Duration { return roundDurationMS(r.Duration) }
- func (r *BenchResult) String() string {
- return fmt.Sprintf("name=%s, trials=%d, secs=%s", r.Name, r.Trials, r.Duration)
- }
- func (r *BenchResult) HasErrors() bool {
- if r.hasErrors == nil {
- var val bool
- for _, res := range r.Raw {
- if res.Error != nil {
- val = true
- break
- }
- }
- r.hasErrors = &val
- }
- return *r.hasErrors
- }
- func (r *BenchResult) errReport() []string {
- errs := []string{}
- for _, res := range r.Raw {
- if res.Error != nil {
- errs = append(errs, res.Error.Error())
- }
- }
- return errs
- }
- type Result struct {
- Duration time.Duration
- Iterations int
- Error error
- }
- func roundDurationMS(d time.Duration) time.Duration {
- rounded := d.Round(time.Millisecond)
- if rounded == 1<<63-1 {
- return 0
- }
- return rounded
- }
|