Commit b3f0d71e by Dominic Hamon

benchmark_min_time now works as expected

parent a94b0a67
...@@ -233,7 +233,6 @@ class State { ...@@ -233,7 +233,6 @@ class State {
bool MaybeStop(); bool MaybeStop();
void NewInterval(); void NewInterval();
bool AllStarting(); bool AllStarting();
bool RunAnotherInterval() const;
void Run(); void Run();
......
...@@ -29,11 +29,9 @@ DEFINE_string(benchmark_filter, ".", ...@@ -29,11 +29,9 @@ DEFINE_string(benchmark_filter, ".",
"If this flag is the string \"all\", all benchmarks linked " "If this flag is the string \"all\", all benchmarks linked "
"into the process are run."); "into the process are run.");
DEFINE_int32(benchmark_min_iters, 100, DEFINE_int32(benchmark_iterations, 0,
"Minimum number of iterations per benchmark"); "Total number of iterations per benchmark. 0 means the benchmarks "
"are time-based.");
DEFINE_int32(benchmark_max_iters, 1000000000,
"Maximum number of iterations per benchmark");
DEFINE_double(benchmark_min_time, 0.5, DEFINE_double(benchmark_min_time, 0.5,
"Minimum number of seconds we should run benchmark before " "Minimum number of seconds we should run benchmark before "
...@@ -69,15 +67,13 @@ DECLARE_string(heap_check); ...@@ -69,15 +67,13 @@ DECLARE_string(heap_check);
: NULL ) : NULL )
namespace benchmark { namespace benchmark {
namespace { namespace {
// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta. // kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
static const char kBigSIUnits[] = "kMGTPEZY"; const char kBigSIUnits[] = "kMGTPEZY";
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi. // Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
static const char kBigIECUnits[] = "KMGTPEZY"; const char kBigIECUnits[] = "KMGTPEZY";
// milli, micro, nano, pico, femto, atto, zepto, yocto. // milli, micro, nano, pico, femto, atto, zepto, yocto.
static const char kSmallSIUnits[] = "munpfazy"; const char kSmallSIUnits[] = "munpfazy";
// We require that all three arrays have the same size. // We require that all three arrays have the same size.
static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits), static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits),
...@@ -427,9 +423,8 @@ void UseRealTime() { ...@@ -427,9 +423,8 @@ void UseRealTime() {
void PrintUsageAndExit() { void PrintUsageAndExit() {
fprintf(stdout, "benchmark [--benchmark_filter=<regex>]\n" fprintf(stdout, "benchmark [--benchmark_filter=<regex>]\n"
// TODO " [--benchmark_min_iters=<min_iters>]\n" // TODO " [--benchmark_iterations=<iterations>]\n"
// TODO " [--benchmark_max_iters=<max_iters>]\n" " [--benchmark_min_time=<min_time>]\n"
// TODO " [--benchmark_min_time=<min_time>]\n"
// " [--benchmark_memory_usage]\n" // " [--benchmark_memory_usage]\n"
// TODO " [--benchmark_repetitions=<num_repetitions>]\n" // TODO " [--benchmark_repetitions=<num_repetitions>]\n"
" [--color_print={true|false}]\n" " [--color_print={true|false}]\n"
...@@ -441,16 +436,16 @@ void ParseCommandLineFlags(int* argc, const char** argv) { ...@@ -441,16 +436,16 @@ void ParseCommandLineFlags(int* argc, const char** argv) {
for (int i = 1; i < *argc; ++i) { for (int i = 1; i < *argc; ++i) {
if (ParseStringFlag(argv[i], "benchmark_filter", if (ParseStringFlag(argv[i], "benchmark_filter",
&FLAGS_benchmark_filter) || &FLAGS_benchmark_filter) ||
/* TODO(dominic) /* TODO
ParseInt32Flag(argv[i], "benchmark_min_iters", ParseInt32Flag(argv[i], "benchmark_iterations",
&FLAGS_benchmark_min_iters) || &FLAGS_benchmark_iterations) ||
ParseInt32Flag(argv[i], "benchmark_max_iters", */
&FLAGS_benchmark_max_iters) ||
ParseDoubleFlag(argv[i], "benchmark_min_time", ParseDoubleFlag(argv[i], "benchmark_min_time",
&FLAGS_benchmark_min_time) || &FLAGS_benchmark_min_time) ||
// TODO(dominic) // TODO(dominic)
// ParseBoolFlag(argv[i], "gbenchmark_memory_usage", // ParseBoolFlag(argv[i], "gbenchmark_memory_usage",
// &FLAGS_gbenchmark_memory_usage) || // &FLAGS_gbenchmark_memory_usage) ||
/*
ParseInt32Flag(argv[i], "benchmark_repetitions", ParseInt32Flag(argv[i], "benchmark_repetitions",
&FLAGS_benchmark_repetitions) || &FLAGS_benchmark_repetitions) ||
*/ */
...@@ -504,7 +499,7 @@ class State::FastClock { ...@@ -504,7 +499,7 @@ class State::FastClock {
t = MyCPUUsage() + ChildrenCPUUsage(); t = MyCPUUsage() + ChildrenCPUUsage();
break; break;
} }
return static_cast<int64_t>(t * 1e6); return static_cast<int64_t>(t * kNumMicrosPerSecond);
} }
// Reinitialize if necessary (since clock type may be change once benchmark // Reinitialize if necessary (since clock type may be change once benchmark
...@@ -577,6 +572,10 @@ struct State::SharedState { ...@@ -577,6 +572,10 @@ struct State::SharedState {
SharedState(const internal::Benchmark::Instance* b, int t) SharedState(const internal::Benchmark::Instance* b, int t)
: instance(b), starting(0), stopping(0), threads(t) { : instance(b), starting(0), stopping(0), threads(t) {
pthread_mutex_init(&mu, nullptr);
}
~SharedState() {
pthread_mutex_destroy(&mu);
} }
DISALLOW_COPY_AND_ASSIGN(SharedState); DISALLOW_COPY_AND_ASSIGN(SharedState);
}; };
...@@ -907,13 +906,17 @@ State::State(FastClock* clock, SharedState* s, int t) ...@@ -907,13 +906,17 @@ State::State(FastClock* clock, SharedState* s, int t)
pause_time_(0.0), pause_time_(0.0),
total_iterations_(0), total_iterations_(0),
interval_micros_( interval_micros_(
static_cast<int64_t>(1e6 * FLAGS_benchmark_min_time / static_cast<int64_t>(kNumMicrosPerSecond * FLAGS_benchmark_min_time /
FLAGS_benchmark_repetitions)) { FLAGS_benchmark_repetitions)) {
CHECK(clock != nullptr);
CHECK(s != nullptr);
} }
bool State::KeepRunning() { bool State::KeepRunning() {
// Fast path // Fast path
if (!clock_->HasReached(stop_time_micros_ + pause_time_)) { if ((FLAGS_benchmark_iterations == 0 &&
!clock_->HasReached(stop_time_micros_ + pause_time_)) ||
iterations_ < FLAGS_benchmark_iterations) {
++iterations_; ++iterations_;
return true; return true;
} }
...@@ -1029,12 +1032,12 @@ void State::NewInterval() { ...@@ -1029,12 +1032,12 @@ void State::NewInterval() {
} }
bool State::FinishInterval() { bool State::FinishInterval() {
if (iterations_ < FLAGS_benchmark_min_iters / FLAGS_benchmark_repetitions && if (FLAGS_benchmark_iterations != 0 &&
interval_micros_ < 5000000) { iterations_ < FLAGS_benchmark_iterations / FLAGS_benchmark_repetitions) {
interval_micros_ *= 2; interval_micros_ *= 2;
#ifdef DEBUG #ifdef DEBUG
std::cout << "Interval was too short; trying again for " std::cout << "Not enough iterations in interval; "
<< interval_micros_ << " useconds.\n"; << "Trying again for " << interval_micros_ << " useconds.\n";
#endif #endif
is_continuation_ = false; is_continuation_ = false;
NewInterval(); NewInterval();
...@@ -1058,11 +1061,25 @@ bool State::FinishInterval() { ...@@ -1058,11 +1061,25 @@ bool State::FinishInterval() {
bool keep_going = false; bool keep_going = false;
{ {
mutex_lock l(&shared_->mu); mutex_lock l(&shared_->mu);
// Either replace the last or add a new data point.
if (is_continuation_) if (is_continuation_)
shared_->runs.back() = data; shared_->runs.back() = data;
else else
shared_->runs.push_back(data); shared_->runs.push_back(data);
keep_going = RunAnotherInterval();
if (FLAGS_benchmark_iterations != 0) {
// If we need more iterations, run another interval as a continuation.
keep_going = total_iterations_ < FLAGS_benchmark_iterations;
is_continuation_ = keep_going;
} else {
// If this is a repetition, run another interval as a new data point.
keep_going =
shared_->runs.size() <
static_cast<size_t>(FLAGS_benchmark_repetitions);
is_continuation_ = !keep_going;
}
if (!keep_going) { if (!keep_going) {
++shared_->stopping; ++shared_->stopping;
if (shared_->stopping < shared_->threads) { if (shared_->stopping < shared_->threads) {
...@@ -1076,23 +1093,11 @@ bool State::FinishInterval() { ...@@ -1076,23 +1093,11 @@ bool State::FinishInterval() {
} }
} }
if (state_ == STATE_RUNNING) { if (state_ == STATE_RUNNING)
is_continuation_ = true;
NewInterval(); NewInterval();
}
return keep_going; return keep_going;
} }
bool State::RunAnotherInterval() const {
if (total_iterations_ < FLAGS_benchmark_min_iters)
return true;
if (total_iterations_ > FLAGS_benchmark_max_iters)
return false;
if (static_cast<int>(shared_->runs.size()) >= FLAGS_benchmark_repetitions)
return false;
return true;
}
bool State::MaybeStop() { bool State::MaybeStop() {
mutex_lock l(&shared_->mu); mutex_lock l(&shared_->mu);
if (shared_->stopping < shared_->threads) { if (shared_->stopping < shared_->threads) {
......
...@@ -5,22 +5,14 @@ ...@@ -5,22 +5,14 @@
namespace benchmark { namespace benchmark {
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
// Window's _sleep takes milliseconds argument. // Window's _sleep takes milliseconds argument.
void SleepForMilliseconds(int milliseconds) { void SleepForMilliseconds(int milliseconds) {
_sleep(milliseconds); _sleep(milliseconds);
} }
void SleepForSeconds(double seconds) { void SleepForSeconds(double seconds) {
SleepForMilliseconds(static_cast<int>(seconds * 1000)); SleepForMilliseconds(static_cast<int>(kNumMillisPerSecond * seconds));
} }
#else // OS_WINDOWS #else // OS_WINDOWS
static const int64_t kNumMillisPerSecond = 1000LL;
static const int64_t kNumMicrosPerMilli = 1000LL;
static const int64_t kNumMicrosPerSecond = kNumMillisPerSecond * 1000LL;
static const int64_t kNumNanosPerMicro = 1000LL;
void SleepForMicroseconds(int64_t microseconds) { void SleepForMicroseconds(int64_t microseconds) {
struct timespec sleep_time; struct timespec sleep_time;
sleep_time.tv_sec = microseconds / kNumMicrosPerSecond; sleep_time.tv_sec = microseconds / kNumMicrosPerSecond;
...@@ -36,7 +28,6 @@ void SleepForMilliseconds(int milliseconds) { ...@@ -36,7 +28,6 @@ void SleepForMilliseconds(int milliseconds) {
void SleepForSeconds(double seconds) { void SleepForSeconds(double seconds) {
SleepForMicroseconds(static_cast<int64_t>(seconds * kNumMicrosPerSecond)); SleepForMicroseconds(static_cast<int64_t>(seconds * kNumMicrosPerSecond));
} }
#endif // OS_WINDOWS #endif // OS_WINDOWS
} // end namespace benchmark } // end namespace benchmark
...@@ -4,6 +4,11 @@ ...@@ -4,6 +4,11 @@
#include <stdint.h> #include <stdint.h>
namespace benchmark { namespace benchmark {
const int64_t kNumMillisPerSecond = 1000LL;
const int64_t kNumMicrosPerMilli = 1000LL;
const int64_t kNumMicrosPerSecond = kNumMillisPerSecond * 1000LL;
const int64_t kNumNanosPerMicro = 1000LL;
void SleepForMicroseconds(int64_t microseconds); void SleepForMicroseconds(int64_t microseconds);
void SleepForMilliseconds(int milliseconds); void SleepForMilliseconds(int milliseconds);
void SleepForSeconds(double seconds); void SleepForSeconds(double seconds);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment