Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
benchmark.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <iomanip>
16 #include <iostream>
17 #include <sstream>
18 
19 #include "util/benchmark.h"
20 #include "util/cpu-info.h"
21 #include "util/debug-util.h"
22 #include "util/stopwatch.h"
23 
24 #include "common/names.h"
25 
26 namespace impala {
27 
28 double Benchmark::Measure(BenchmarkFunction function, void* args,
29  int max_time, int batch_size) {
30  int64_t target_cycles = CpuInfo::cycles_per_ms() * max_time;
31  int64_t iters = 0;
32 
33  // Run it with the default batch size to roughly estimate how many iterations
34  // it will take
35  StopWatch sw;
36  sw.Start();
37  function(batch_size, args);
38  sw.Stop();
39  iters += batch_size;
40 
41  if (sw.ElapsedTime() < target_cycles) {
42  int64_t iters_guess = (target_cycles / sw.ElapsedTime()) * batch_size;
43  // Shoot for 110% of the guess. Going a little over is not a big deal.
44  iters_guess *= 1.1;
45  // Modify the batch size based on the guess. We ran the function a small number
46  // of times to estimate how fast the function is. Run the remaining iterations at
47  // in 20% increments.
48  // TODO: we can make this more sophisticated if need to be dynamically ramp up and
49  // ramp down the sizes.
50  batch_size = (iters_guess - iters) / 5;
51  }
52 
53  while (sw.ElapsedTime() < target_cycles) {
54  sw.Start();
55  function(batch_size, args);
56  sw.Stop();
57  iters += batch_size;
58  }
59 
60  double ms_elapsed = sw.ElapsedTime() / CpuInfo::cycles_per_ms();
61  return iters / ms_elapsed;
62 }
63 
64 Benchmark::Benchmark(const string& name) : name_(name) {
65 #ifndef NDEBUG
66  LOG(ERROR) << "WARNING: Running benchmark in DEBUG mode.";
67 #endif
68 }
69 
70 int Benchmark::AddBenchmark(const string& name, BenchmarkFunction fn, void* args,
71  int baseline_idx) {
72  if (baseline_idx == -1) baseline_idx = benchmarks_.size();
73  CHECK_LE(baseline_idx, benchmarks_.size());
74  BenchmarkResult benchmark;
75  benchmark.name = name;
76  benchmark.fn = fn;
77  benchmark.args = args;
78  benchmark.baseline_idx = baseline_idx;
79  benchmarks_.push_back(benchmark);
80  return benchmarks_.size() - 1;
81 }
82 
84  if (benchmarks_.empty()) return "";
85 
86  // Run a warmup to iterate through the data
87  benchmarks_[0].fn(10, benchmarks_[0].args);
88 
89  stringstream ss;
90  for (int i = 0; i < benchmarks_.size(); ++i) {
91  benchmarks_[i].rate = Measure(benchmarks_[i].fn, benchmarks_[i].args);
92  }
93 
94  int function_out_width = 30;
95  int rate_out_width = 20;
96  int comparison_out_width = 20;
97  int padding = 0;
98  int total_width = function_out_width + rate_out_width + comparison_out_width + padding;
99 
100  ss << name_ << ":"
101  << setw(function_out_width - name_.size() - 1) << "Function"
102  << setw(rate_out_width) << "Rate (iters/ms)"
103  << setw(comparison_out_width) << "Comparison" << endl;
104  for (int i = 0; i < total_width; ++i) {
105  ss << '-';
106  }
107  ss << endl;
108 
109  int previous_baseline_idx = -1;
110  for (int i = 0; i < benchmarks_.size(); ++i) {
111  double base_line = benchmarks_[benchmarks_[i].baseline_idx].rate;
112  if (previous_baseline_idx != benchmarks_[i].baseline_idx && i > 0) ss << endl;
113  ss << setw(function_out_width) << benchmarks_[i].name
114  << setw(rate_out_width) << setprecision(4) << benchmarks_[i].rate
115  << setw(comparison_out_width - 1) << setprecision(4)
116  << (benchmarks_[i].rate / base_line) << "X" << endl;
117  previous_baseline_idx = benchmarks_[i].baseline_idx;
118  }
119 
120  return ss.str();
121 }
122 
123 // TODO: maybe add other things like amount of RAM, etc
125  stringstream ss;
126  ss << "Machine Info: " << CpuInfo::model_name();
127  return ss.str();
128 }
129 
130 }
int AddBenchmark(const std::string &name, BenchmarkFunction fn, void *args, int baseline_idx=0)
Definition: benchmark.cc:70
uint64_t ElapsedTime() const
Returns time in cpu ticks.
Definition: stopwatch.h:50
static std::string GetMachineInfo()
Output machine/build configuration as a string.
Definition: benchmark.cc:124
std::string Measure()
Runs all the benchmarks and returns the result in a formatted string.
Definition: benchmark.cc:83
std::string name_
Definition: benchmark.h:75
std::vector< BenchmarkResult > benchmarks_
Definition: benchmark.h:76
static std::string model_name()
Returns the model name of the cpu (e.g. Intel i7-2600)
Definition: cpu-info.h:86
Benchmark(const std::string &name)
Name of the microbenchmark. This is outputted in the result.
Definition: benchmark.cc:64
static int64_t cycles_per_ms()
Returns the number of cpu cycles per millisecond.
Definition: cpu-info.h:74
uint8_t padding[64-sizeof(int)]
string name
Definition: cpu-info.cc:50