File: benchmark.cc

package info (click to toggle)
re2 20210201%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,868 kB
  • sloc: cpp: 20,723; python: 358; makefile: 315; perl: 224; sh: 217; ansic: 7
file content (131 lines) | stat: -rw-r--r-- 2,998 bytes parent folder | download | duplicates (15)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2009 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <chrono>

#include "util/benchmark.h"
#include "util/flags.h"
#include "re2/re2.h"

#ifdef _WIN32
#define snprintf _snprintf
#endif

using ::testing::Benchmark;

static Benchmark* benchmarks[10000];
static int nbenchmarks;

void Benchmark::Register() {
  lo_ = std::max(1, lo_);
  hi_ = std::max(lo_, hi_);
  benchmarks[nbenchmarks++] = this;
}

static int64_t nsec() {
  return std::chrono::duration_cast<std::chrono::nanoseconds>(
             std::chrono::steady_clock::now().time_since_epoch())
      .count();
}

static int64_t t0;
static int64_t ns;
static int64_t bytes;
static int64_t items;

void StartBenchmarkTiming() {
  if (t0 == 0) {
    t0 = nsec();
  }
}

void StopBenchmarkTiming() {
  if (t0 != 0) {
    ns += nsec() - t0;
    t0 = 0;
  }
}

void SetBenchmarkBytesProcessed(int64_t b) { bytes = b; }

void SetBenchmarkItemsProcessed(int64_t i) { items = i; }

static void RunFunc(Benchmark* b, int iters, int arg) {
  t0 = nsec();
  ns = 0;
  bytes = 0;
  items = 0;
  b->func()(iters, arg);
  StopBenchmarkTiming();
}

static int round(int n) {
  int base = 1;
  while (base * 10 < n) base *= 10;
  if (n < 2 * base) return 2 * base;
  if (n < 5 * base) return 5 * base;
  return 10 * base;
}

static void RunBench(Benchmark* b, int arg) {
  int iters, last;

  // Run once just in case it's expensive.
  iters = 1;
  RunFunc(b, iters, arg);
  while (ns < (int)1e9 && iters < (int)1e9) {
    last = iters;
    if (ns / iters == 0) {
      iters = (int)1e9;
    } else {
      iters = (int)1e9 / static_cast<int>(ns / iters);
    }
    iters = std::max(last + 1, std::min(iters + iters / 2, 100 * last));
    iters = round(iters);
    RunFunc(b, iters, arg);
  }

  char mb[100];
  char suf[100];
  mb[0] = '\0';
  suf[0] = '\0';
  if (ns > 0 && bytes > 0)
    snprintf(mb, sizeof mb, "\t%7.2f MB/s",
             ((double)bytes / 1e6) / ((double)ns / 1e9));
  if (b->has_arg()) {
    if (arg >= (1 << 20)) {
      snprintf(suf, sizeof suf, "/%dM", arg / (1 << 20));
    } else if (arg >= (1 << 10)) {
      snprintf(suf, sizeof suf, "/%dK", arg / (1 << 10));
    } else {
      snprintf(suf, sizeof suf, "/%d", arg);
    }
  }
  printf("%s%s\t%8d\t%10lld ns/op%s\n", b->name(), suf, iters,
         (long long)ns / iters, mb);
  fflush(stdout);
}

static bool WantBench(const char* name, int argc, const char** argv) {
  if (argc == 1) return true;
  for (int i = 1; i < argc; i++) {
    if (RE2::PartialMatch(name, argv[i]))
      return true;
  }
  return false;
}

int main(int argc, const char** argv) {
  for (int i = 0; i < nbenchmarks; i++) {
    Benchmark* b = benchmarks[i];
    if (!WantBench(b->name(), argc, argv))
      continue;
    for (int arg = b->lo(); arg <= b->hi(); arg <<= 1)
      RunBench(b, arg);
  }
}