github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/send/benchmark/harness_case.go (about)

     1  package send
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path/filepath"
     7  	"runtime"
     8  	"strings"
     9  	"time"
    10  )
    11  
    12  type caseDefinition struct {
    13  	name       string
    14  	bench      benchCase
    15  	count      int
    16  	numOps     int
    17  	size       int
    18  	iterations int
    19  	runtime    time.Duration
    20  
    21  	cumulativeRuntime time.Duration
    22  	elapsed           time.Duration
    23  	startAt           time.Time
    24  	isRunning         bool
    25  }
    26  
    27  // TimerManager is a subset of the testing.B tool, used to manage
    28  // setup code.
    29  type TimerManager interface {
    30  	ResetTimer()
    31  	StartTimer()
    32  	StopTimer()
    33  }
    34  
    35  func (c *caseDefinition) ResetTimer() {
    36  	c.startAt = time.Now()
    37  	c.elapsed = 0
    38  	c.isRunning = true
    39  }
    40  
    41  func (c *caseDefinition) StartTimer() {
    42  	c.startAt = time.Now()
    43  	c.isRunning = true
    44  }
    45  
    46  func (c *caseDefinition) StopTimer() {
    47  	if !c.isRunning {
    48  		panic("StopTimer called on stopped timer")
    49  	}
    50  	c.elapsed += time.Since(c.startAt)
    51  	c.isRunning = false
    52  }
    53  
    54  func (c *caseDefinition) roundedRuntime() time.Duration {
    55  	return c.runtime.Round(time.Millisecond)
    56  }
    57  
    58  func (c *caseDefinition) Run(ctx context.Context) *benchResult {
    59  	out := &benchResult{
    60  		dataSize:   c.size * c.numOps * c.count,
    61  		name:       c.name,
    62  		operations: c.numOps * c.count,
    63  	}
    64  	var cancel context.CancelFunc
    65  	ctx, cancel = context.WithTimeout(ctx, executionTimeout)
    66  	defer cancel()
    67  
    68  	fmt.Println("=== RUN", out.name)
    69  	if c.iterations == 0 {
    70  		c.iterations = minIterations
    71  	}
    72  
    73  benchRepeat:
    74  	for {
    75  		if ctx.Err() != nil {
    76  			break
    77  		}
    78  		if out.trials >= c.iterations || c.cumulativeRuntime >= c.runtime || c.cumulativeRuntime >= executionTimeout {
    79  			break
    80  		}
    81  
    82  		res := result{
    83  			iterations: c.count,
    84  		}
    85  
    86  		start := time.Now()
    87  		res.err = c.bench(ctx, c, c.count, c.size, c.numOps)
    88  		realTestLength := time.Since(start)
    89  
    90  		res.duration = c.elapsed
    91  		c.cumulativeRuntime += realTestLength
    92  
    93  		switch res.err {
    94  		case context.DeadlineExceeded:
    95  			break benchRepeat
    96  		case context.Canceled:
    97  			break benchRepeat
    98  		case nil:
    99  			out.trials++
   100  			c.elapsed = 0
   101  			out.raw = append(out.raw, res)
   102  		default:
   103  			continue
   104  		}
   105  
   106  	}
   107  
   108  	out.duration = out.totalDuration()
   109  	fmt.Printf("    --- REPORT: count=%d trials=%d iters=%d required_runtime=%s cumulative_runtime=%s\n",
   110  		c.count, out.trials, c.iterations, c.runtime, c.cumulativeRuntime)
   111  	if out.hasErrors() {
   112  		fmt.Printf("    --- ERRORS: %s\n", strings.Join(out.errReport(), "\n       "))
   113  		fmt.Printf("--- FAIL: %s (%s)\n", out.name, out.roundedRuntime())
   114  	} else {
   115  		fmt.Printf("--- PASS: %s (%s)\n", out.name, out.roundedRuntime())
   116  	}
   117  
   118  	return out
   119  
   120  }
   121  
   122  func (c *caseDefinition) String() string {
   123  	return fmt.Sprintf("name=%s, count=%d, iters=%d timeout=%s, required_runtime=%d",
   124  		c.name, c.count, c.iterations, executionTimeout, c.runtime)
   125  }
   126  
   127  func getProjectRoot() string { return filepath.Dir(filepath.Dir(getDirectoryOfFile())) }
   128  
   129  func getDirectoryOfFile() string {
   130  	_, file, _, _ := runtime.Caller(1)
   131  
   132  	return filepath.Dir(file)
   133  }