...

Source file src/go.mongodb.org/mongo-driver/benchmark/harness_results.go

Documentation: go.mongodb.org/mongo-driver/benchmark

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package benchmark
     8  
     9  import (
    10  	"fmt"
    11  	"time"
    12  
    13  	"github.com/montanaflynn/stats"
    14  )
    15  
    16  type BenchResult struct {
    17  	Name       string
    18  	Trials     int
    19  	Duration   time.Duration
    20  	Raw        []Result
    21  	DataSize   int
    22  	Operations int
    23  	hasErrors  *bool
    24  }
    25  
    26  type Metric struct {
    27  	Name  string      `json:"name"`
    28  	Value interface{} `json:"value"`
    29  }
    30  
    31  func (r *BenchResult) EvergreenPerfFormat() ([]interface{}, error) {
    32  	timings := r.timings()
    33  
    34  	median, err := stats.Median(timings)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	min, err := stats.Min(timings)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	max, err := stats.Max(timings)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	out := []interface{}{
    50  		map[string]interface{}{
    51  			"info": map[string]interface{}{
    52  				"test_name": r.Name + "-throughput",
    53  				"args": map[string]interface{}{
    54  					"threads": 1,
    55  				},
    56  			},
    57  			"metrics": []Metric{
    58  				{Name: "seconds", Value: r.Duration.Round(time.Millisecond).Seconds()},
    59  				{Name: "ops_per_second", Value: r.getThroughput(median)},
    60  				{Name: "ops_per_second_min", Value: r.getThroughput(min)},
    61  				{Name: "ops_per_second_max", Value: r.getThroughput(max)},
    62  			},
    63  		},
    64  	}
    65  
    66  	if r.DataSize > 0 {
    67  		out = append(out, interface{}(map[string]interface{}{
    68  			"info": map[string]interface{}{
    69  				"test_name": r.Name + "-MB-adjusted",
    70  				"args": map[string]interface{}{
    71  					"threads": 1,
    72  				},
    73  			},
    74  			"metrics": []Metric{
    75  				{Name: "seconds", Value: r.Duration.Round(time.Millisecond).Seconds()},
    76  				{Name: "ops_per_second", Value: r.adjustResults(median)},
    77  				{Name: "ops_per_second_min", Value: r.adjustResults(min)},
    78  				{Name: "ops_per_second_max", Value: r.adjustResults(max)},
    79  			},
    80  		}))
    81  	}
    82  
    83  	return out, nil
    84  }
    85  
    86  func (r *BenchResult) timings() []float64 {
    87  	out := []float64{}
    88  	for _, r := range r.Raw {
    89  		out = append(out, r.Duration.Seconds())
    90  	}
    91  	return out
    92  }
    93  
    94  func (r *BenchResult) totalDuration() time.Duration {
    95  	var out time.Duration
    96  	for _, trial := range r.Raw {
    97  		out += trial.Duration
    98  	}
    99  	return out
   100  }
   101  
   102  func (r *BenchResult) adjustResults(data float64) float64 { return float64(r.DataSize) / data }
   103  func (r *BenchResult) getThroughput(data float64) float64 { return float64(r.Operations) / data }
   104  func (r *BenchResult) roundedRuntime() time.Duration      { return roundDurationMS(r.Duration) }
   105  
   106  func (r *BenchResult) String() string {
   107  	return fmt.Sprintf("name=%s, trials=%d, secs=%s", r.Name, r.Trials, r.Duration)
   108  }
   109  
   110  func (r *BenchResult) HasErrors() bool {
   111  	if r.hasErrors == nil {
   112  		var val bool
   113  		for _, res := range r.Raw {
   114  			if res.Error != nil {
   115  				val = true
   116  				break
   117  			}
   118  		}
   119  		r.hasErrors = &val
   120  	}
   121  
   122  	return *r.hasErrors
   123  }
   124  
   125  func (r *BenchResult) errReport() []string {
   126  	errs := []string{}
   127  	for _, res := range r.Raw {
   128  		if res.Error != nil {
   129  			errs = append(errs, res.Error.Error())
   130  		}
   131  	}
   132  	return errs
   133  }
   134  
   135  type Result struct {
   136  	Duration   time.Duration
   137  	Iterations int
   138  	Error      error
   139  }
   140  
   141  func roundDurationMS(d time.Duration) time.Duration {
   142  	rounded := d.Round(time.Millisecond)
   143  	if rounded == 1<<63-1 {
   144  		return 0
   145  	}
   146  	return rounded
   147  }
   148  

View as plain text