mirror of
https://github.com/google/benchmark.git
synced 2025-03-14 03:10:22 +08:00
Refactor benchmark.cc into benchmark_register.cc and benchmark.cc (#287)
* Refactor benchmark.cc into benchmark_register.cc and benchmark_run.cc The benchmark.cc file is getting really big and it contains a bunch of unrelated components. This patch separates the files into two separate parts. The "runtime" parts and the "registration" parts. This patch also removes the PIMPL used by Benchmark. Previously we couldn't have STL types in the interface but now we can. Therefore there is no reason to keep BenchmarkImp. * add missing include * rework windows timers again * Guard timespec on older Windows versions * Remove old thread safety annotation workarounds
This commit is contained in:
parent
9c26168126
commit
d038472c18
@ -147,9 +147,14 @@ if (BENCHMARK_USE_LIBCXX)
|
||||
endif(BENCHMARK_USE_LIBCXX)
|
||||
|
||||
# C++ feature checks
|
||||
# Determine the correct regular expression engine to use
|
||||
cxx_feature_check(STD_REGEX)
|
||||
cxx_feature_check(GNU_POSIX_REGEX)
|
||||
cxx_feature_check(POSIX_REGEX)
|
||||
if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
|
||||
message(FATAL_ERROR "Failed to determine the source files for the regular expression backend")
|
||||
endif()
|
||||
|
||||
cxx_feature_check(STEADY_CLOCK)
|
||||
# Ensure we have pthreads
|
||||
find_package(Threads REQUIRED)
|
||||
|
@ -154,6 +154,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
@ -273,6 +274,17 @@ typedef double(BigOFunc)(int);
|
||||
namespace internal {
|
||||
class ThreadTimer;
|
||||
class ThreadManager;
|
||||
|
||||
#if defined(BENCHMARK_HAS_CXX11)
|
||||
enum ReportMode : unsigned {
|
||||
#else
|
||||
enum ReportMode {
|
||||
#endif
|
||||
RM_Unspecified, // The mode has not been manually specified
|
||||
RM_Default, // The mode is user-specified as default.
|
||||
RM_ReportAggregatesOnly
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// State is passed to a running Benchmark and contains state for the
|
||||
@ -616,9 +628,25 @@ protected:
|
||||
Benchmark(Benchmark const&);
|
||||
void SetName(const char* name);
|
||||
|
||||
int ArgsCnt() const;
|
||||
|
||||
static void AddRange(std::vector<int>* dst, int lo, int hi, int mult);
|
||||
|
||||
private:
|
||||
friend class BenchmarkFamilies;
|
||||
BenchmarkImp* imp_;
|
||||
|
||||
std::string name_;
|
||||
ReportMode report_mode_;
|
||||
std::vector< std::vector<int> > args_; // Args for all benchmark runs
|
||||
TimeUnit time_unit_;
|
||||
int range_multiplier_;
|
||||
double min_time_;
|
||||
int repetitions_;
|
||||
bool use_real_time_;
|
||||
bool use_manual_time_;
|
||||
BigO complexity_;
|
||||
BigOFunc* complexity_lambda_;
|
||||
std::vector<int> thread_counts_;
|
||||
|
||||
Benchmark& operator=(Benchmark const&);
|
||||
};
|
||||
|
@ -6,35 +6,13 @@ if (DEFINED BENCHMARK_CXX_LINKER_FLAGS)
|
||||
list(APPEND CMAKE_MODULE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
# Define the source files
|
||||
set(SOURCE_FILES "benchmark.cc" "colorprint.cc" "commandlineflags.cc"
|
||||
"console_reporter.cc" "csv_reporter.cc"
|
||||
"json_reporter.cc" "reporter.cc" "sleep.cc"
|
||||
"string_util.cc" "sysinfo.cc" "complexity.cc" "timers.cc")
|
||||
# Add headers to the list of source files. cmake does not require this,
|
||||
# but IDEs such as Visual Studio need this to add the headers
|
||||
# to the generated project.
|
||||
set(_d "${PROJECT_SOURCE_DIR}/include/benchmark")
|
||||
list(APPEND SOURCE_FILES "${_d}/benchmark.h" "${_d}/benchmark_api.h"
|
||||
"${_d}/macros.h" "${_d}/reporter.h" "arraysize.h" "check.h"
|
||||
"colorprint.h" "commandlineflags.h" "complexity.h"
|
||||
"cycleclock.h" "internal_macros.h" "log.h" "mutex.h"
|
||||
"re.h" "sleep.h" "stat.h" "string_util.h" "sysinfo.h" "timers.h")
|
||||
unset(_d)
|
||||
|
||||
# Determine the correct regular expression engine to use
|
||||
if(HAVE_STD_REGEX)
|
||||
set(RE_FILES "re_std.cc")
|
||||
elseif(HAVE_GNU_POSIX_REGEX)
|
||||
set(RE_FILES "re_posix.cc")
|
||||
elseif(HAVE_POSIX_REGEX)
|
||||
set(RE_FILES "re_posix.cc")
|
||||
else()
|
||||
message(FATAL_ERROR "Failed to determine the source files for the regular expression backend")
|
||||
endif()
|
||||
|
||||
add_library(benchmark ${SOURCE_FILES} ${RE_FILES})
|
||||
file(GLOB
|
||||
SOURCE_FILES
|
||||
*.cc
|
||||
${PROJECT_SOURCE_DIR}/include/benchmark/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||
|
||||
add_library(benchmark ${SOURCE_FILES})
|
||||
set_target_properties(benchmark PROPERTIES
|
||||
OUTPUT_NAME "benchmark"
|
||||
VERSION ${GENERIC_LIB_VERSION}
|
||||
|
530
src/benchmark.cc
530
src/benchmark.cc
@ -14,6 +14,7 @@
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "internal_macros.h"
|
||||
#include "benchmark_api_internal.h"
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
#include <sys/time.h>
|
||||
@ -87,7 +88,6 @@ DEFINE_int32(v, 0, "The level of verbose logging to output");
|
||||
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
namespace internal {
|
||||
|
||||
void UseCharPointer(char const volatile*) {}
|
||||
@ -96,34 +96,19 @@ void UseCharPointer(char const volatile*) {}
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsZero(double n) {
|
||||
return std::abs(n) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
|
||||
static const int kRangeMultiplier = 8;
|
||||
// The size of a benchmark family determines is the number of inputs to repeat
|
||||
// the benchmark on. If this is "large" then warn the user during configuration.
|
||||
static const size_t kMaxFamilySize = 100;
|
||||
static const size_t kMaxIterations = 1000000000;
|
||||
|
||||
} // end namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
// NOTE: This is a dummy "mutex" type used to denote the actual mutex
|
||||
// returned by GetBenchmarkMutex(). This is only used to placate the thread
|
||||
// safety warnings by giving the return of GetBenchmarkLock() a name.
|
||||
struct CAPABILITY("mutex") BenchmarkLockType {};
|
||||
BenchmarkLockType BenchmarkLockVar;
|
||||
|
||||
class ThreadManager {
|
||||
public:
|
||||
ThreadManager(int num_threads)
|
||||
: alive_threads_(num_threads), start_stop_barrier_(num_threads) {}
|
||||
|
||||
Mutex& GetBenchmarkMutex() const
|
||||
RETURN_CAPABILITY(::benchmark::internal::BenchmarkLockVar) {
|
||||
Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) {
|
||||
return benchmark_mutex_;
|
||||
}
|
||||
|
||||
@ -224,504 +209,6 @@ class ThreadTimer {
|
||||
|
||||
};
|
||||
|
||||
|
||||
enum ReportMode : unsigned {
|
||||
RM_Unspecified, // The mode has not been manually specified
|
||||
RM_Default, // The mode is user-specified as default.
|
||||
RM_ReportAggregatesOnly
|
||||
};
|
||||
|
||||
// Information kept per benchmark we may want to run
|
||||
struct Benchmark::Instance {
|
||||
std::string name;
|
||||
Benchmark* benchmark;
|
||||
ReportMode report_mode;
|
||||
std::vector<int> arg;
|
||||
TimeUnit time_unit;
|
||||
int range_multiplier;
|
||||
bool use_real_time;
|
||||
bool use_manual_time;
|
||||
BigO complexity;
|
||||
BigOFunc* complexity_lambda;
|
||||
bool last_benchmark_instance;
|
||||
int repetitions;
|
||||
double min_time;
|
||||
int threads; // Number of concurrent threads to use
|
||||
bool multithreaded; // Is benchmark multi-threaded?
|
||||
};
|
||||
|
||||
// Class for managing registered benchmarks. Note that each registered
|
||||
// benchmark identifies a family of related benchmarks to run.
|
||||
class BenchmarkFamilies {
|
||||
public:
|
||||
static BenchmarkFamilies* GetInstance();
|
||||
|
||||
// Registers a benchmark family and returns the index assigned to it.
|
||||
size_t AddBenchmark(std::unique_ptr<Benchmark> family);
|
||||
|
||||
// Extract the list of benchmark instances that match the specified
|
||||
// regular expression.
|
||||
bool FindBenchmarks(const std::string& re,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* Err);
|
||||
private:
|
||||
BenchmarkFamilies() {}
|
||||
|
||||
std::vector<std::unique_ptr<Benchmark>> families_;
|
||||
Mutex mutex_;
|
||||
};
|
||||
|
||||
|
||||
class BenchmarkImp {
|
||||
public:
|
||||
explicit BenchmarkImp(const char* name);
|
||||
~BenchmarkImp();
|
||||
|
||||
void Arg(int x);
|
||||
void Unit(TimeUnit unit);
|
||||
void Range(int start, int limit);
|
||||
void DenseRange(int start, int limit, int step = 1);
|
||||
void Args(const std::vector<int>& args);
|
||||
void Ranges(const std::vector<std::pair<int, int>>& ranges);
|
||||
void RangeMultiplier(int multiplier);
|
||||
void MinTime(double n);
|
||||
void Repetitions(int n);
|
||||
void ReportAggregatesOnly(bool v);
|
||||
void UseRealTime();
|
||||
void UseManualTime();
|
||||
void Complexity(BigO complexity);
|
||||
void ComplexityLambda(BigOFunc* complexity);
|
||||
void Threads(int t);
|
||||
void ThreadRange(int min_threads, int max_threads);
|
||||
void DenseThreadRange(int min_threads, int max_threads, int stride);
|
||||
void ThreadPerCpu();
|
||||
void SetName(const char* name);
|
||||
|
||||
static void AddRange(std::vector<int>* dst, int lo, int hi, int mult);
|
||||
|
||||
int ArgsCnt() const { return args_.empty() ? -1 : static_cast<int>(args_.front().size()); }
|
||||
|
||||
private:
|
||||
friend class BenchmarkFamilies;
|
||||
|
||||
std::string name_;
|
||||
ReportMode report_mode_;
|
||||
std::vector< std::vector<int> > args_; // Args for all benchmark runs
|
||||
TimeUnit time_unit_;
|
||||
int range_multiplier_;
|
||||
double min_time_;
|
||||
int repetitions_;
|
||||
bool use_real_time_;
|
||||
bool use_manual_time_;
|
||||
BigO complexity_;
|
||||
BigOFunc* complexity_lambda_;
|
||||
std::vector<int> thread_counts_;
|
||||
|
||||
BenchmarkImp& operator=(BenchmarkImp const&);
|
||||
};
|
||||
|
||||
BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
|
||||
static BenchmarkFamilies instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
|
||||
size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
|
||||
MutexLock l(mutex_);
|
||||
size_t index = families_.size();
|
||||
families_.push_back(std::move(family));
|
||||
return index;
|
||||
}
|
||||
|
||||
bool BenchmarkFamilies::FindBenchmarks(
|
||||
const std::string& spec,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* ErrStream) {
|
||||
CHECK(ErrStream);
|
||||
auto& Err = *ErrStream;
|
||||
// Make regular expression out of command-line flag
|
||||
std::string error_msg;
|
||||
Regex re;
|
||||
if (!re.Init(spec, &error_msg)) {
|
||||
Err << "Could not compile benchmark re: " << error_msg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special list of thread counts to use when none are specified
|
||||
const std::vector<int> one_thread = {1};
|
||||
|
||||
MutexLock l(mutex_);
|
||||
for (std::unique_ptr<Benchmark>& bench_family : families_) {
|
||||
// Family was deleted or benchmark doesn't match
|
||||
if (!bench_family) continue;
|
||||
BenchmarkImp* family = bench_family->imp_;
|
||||
|
||||
if (family->ArgsCnt() == -1) {
|
||||
family->Args({});
|
||||
}
|
||||
const std::vector<int>* thread_counts =
|
||||
(family->thread_counts_.empty()
|
||||
? &one_thread
|
||||
: &static_cast<const std::vector<int>&>(family->thread_counts_));
|
||||
const size_t family_size = family->args_.size() * thread_counts->size();
|
||||
// The benchmark will be run at least 'family_size' different inputs.
|
||||
// If 'family_size' is very large warn the user.
|
||||
if (family_size > kMaxFamilySize) {
|
||||
Err << "The number of inputs is very large. " << family->name_
|
||||
<< " will be repeated at least " << family_size << " times.\n";
|
||||
}
|
||||
// reserve in the special case the regex ".", since we know the final
|
||||
// family size.
|
||||
if (spec == ".")
|
||||
benchmarks->reserve(family_size);
|
||||
|
||||
for (auto const& args : family->args_) {
|
||||
for (int num_threads : *thread_counts) {
|
||||
|
||||
Benchmark::Instance instance;
|
||||
instance.name = family->name_;
|
||||
instance.benchmark = bench_family.get();
|
||||
instance.report_mode = family->report_mode_;
|
||||
instance.arg = args;
|
||||
instance.time_unit = family->time_unit_;
|
||||
instance.range_multiplier = family->range_multiplier_;
|
||||
instance.min_time = family->min_time_;
|
||||
instance.repetitions = family->repetitions_;
|
||||
instance.use_real_time = family->use_real_time_;
|
||||
instance.use_manual_time = family->use_manual_time_;
|
||||
instance.complexity = family->complexity_;
|
||||
instance.complexity_lambda = family->complexity_lambda_;
|
||||
instance.threads = num_threads;
|
||||
instance.multithreaded = !(family->thread_counts_.empty());
|
||||
|
||||
// Add arguments to instance name
|
||||
for (auto const& arg : args) {
|
||||
AppendHumanReadable(arg, &instance.name);
|
||||
}
|
||||
|
||||
if (!IsZero(family->min_time_)) {
|
||||
instance.name += StringPrintF("/min_time:%0.3f", family->min_time_);
|
||||
}
|
||||
if (family->repetitions_ != 0) {
|
||||
instance.name += StringPrintF("/repeats:%d", family->repetitions_);
|
||||
}
|
||||
if (family->use_manual_time_) {
|
||||
instance.name += "/manual_time";
|
||||
} else if (family->use_real_time_) {
|
||||
instance.name += "/real_time";
|
||||
}
|
||||
|
||||
// Add the number of threads used to the name
|
||||
if (!family->thread_counts_.empty()) {
|
||||
instance.name += StringPrintF("/threads:%d", instance.threads);
|
||||
}
|
||||
|
||||
if (re.Match(instance.name)) {
|
||||
instance.last_benchmark_instance = (&args == &family->args_.back());
|
||||
benchmarks->push_back(std::move(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BenchmarkImp::BenchmarkImp(const char* name)
|
||||
: name_(name), report_mode_(RM_Unspecified), time_unit_(kNanosecond),
|
||||
range_multiplier_(kRangeMultiplier), min_time_(0.0), repetitions_(0),
|
||||
use_real_time_(false), use_manual_time_(false),
|
||||
complexity_(oNone) {
|
||||
}
|
||||
|
||||
BenchmarkImp::~BenchmarkImp() {
|
||||
}
|
||||
|
||||
void BenchmarkImp::Arg(int x) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
args_.push_back({x});
|
||||
}
|
||||
|
||||
void BenchmarkImp::Unit(TimeUnit unit) {
|
||||
time_unit_ = unit;
|
||||
}
|
||||
|
||||
void BenchmarkImp::Range(int start, int limit) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
std::vector<int> arglist;
|
||||
AddRange(&arglist, start, limit, range_multiplier_);
|
||||
|
||||
for (int i : arglist) {
|
||||
args_.push_back({i});
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkImp::DenseRange(int start, int limit, int step) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
CHECK_GE(start, 0);
|
||||
CHECK_LE(start, limit);
|
||||
for (int arg = start; arg <= limit; arg+= step) {
|
||||
args_.push_back({arg});
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkImp::Args(const std::vector<int>& args)
|
||||
{
|
||||
args_.push_back(args);
|
||||
}
|
||||
|
||||
void BenchmarkImp::Ranges(const std::vector<std::pair<int, int>>& ranges) {
|
||||
std::vector<std::vector<int>> arglists(ranges.size());
|
||||
std::size_t total = 1;
|
||||
for (std::size_t i = 0; i < ranges.size(); i++) {
|
||||
AddRange(&arglists[i], ranges[i].first, ranges[i].second, range_multiplier_);
|
||||
total *= arglists[i].size();
|
||||
}
|
||||
|
||||
std::vector<std::size_t> ctr(arglists.size(), 0);
|
||||
|
||||
for (std::size_t i = 0; i < total; i++) {
|
||||
std::vector<int> tmp;
|
||||
tmp.reserve(arglists.size());
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
tmp.push_back(arglists[j].at(ctr[j]));
|
||||
}
|
||||
|
||||
args_.push_back(std::move(tmp));
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
if (ctr[j] + 1 < arglists[j].size()) {
|
||||
++ctr[j];
|
||||
break;
|
||||
}
|
||||
ctr[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BenchmarkImp::RangeMultiplier(int multiplier) {
|
||||
CHECK(multiplier > 1);
|
||||
range_multiplier_ = multiplier;
|
||||
}
|
||||
|
||||
void BenchmarkImp::MinTime(double t) {
|
||||
CHECK(t > 0.0);
|
||||
min_time_ = t;
|
||||
}
|
||||
|
||||
|
||||
void BenchmarkImp::Repetitions(int n) {
|
||||
CHECK(n > 0);
|
||||
repetitions_ = n;
|
||||
}
|
||||
|
||||
void BenchmarkImp::ReportAggregatesOnly(bool value) {
|
||||
report_mode_ = value ? RM_ReportAggregatesOnly : RM_Default;
|
||||
}
|
||||
|
||||
void BenchmarkImp::UseRealTime() {
|
||||
CHECK(!use_manual_time_) << "Cannot set UseRealTime and UseManualTime simultaneously.";
|
||||
use_real_time_ = true;
|
||||
}
|
||||
|
||||
void BenchmarkImp::UseManualTime() {
|
||||
CHECK(!use_real_time_) << "Cannot set UseRealTime and UseManualTime simultaneously.";
|
||||
use_manual_time_ = true;
|
||||
}
|
||||
|
||||
void BenchmarkImp::Complexity(BigO complexity){
|
||||
complexity_ = complexity;
|
||||
}
|
||||
|
||||
void BenchmarkImp::ComplexityLambda(BigOFunc* complexity) {
|
||||
complexity_lambda_ = complexity;
|
||||
}
|
||||
|
||||
void BenchmarkImp::Threads(int t) {
|
||||
CHECK_GT(t, 0);
|
||||
thread_counts_.push_back(t);
|
||||
}
|
||||
|
||||
void BenchmarkImp::ThreadRange(int min_threads, int max_threads) {
|
||||
CHECK_GT(min_threads, 0);
|
||||
CHECK_GE(max_threads, min_threads);
|
||||
|
||||
AddRange(&thread_counts_, min_threads, max_threads, 2);
|
||||
}
|
||||
|
||||
void BenchmarkImp::DenseThreadRange(int min_threads, int max_threads,
|
||||
int stride) {
|
||||
CHECK_GT(min_threads, 0);
|
||||
CHECK_GE(max_threads, min_threads);
|
||||
CHECK_GE(stride, 1);
|
||||
|
||||
for (auto i = min_threads; i < max_threads; i += stride) {
|
||||
thread_counts_.push_back(i);
|
||||
}
|
||||
thread_counts_.push_back(max_threads);
|
||||
}
|
||||
|
||||
void BenchmarkImp::ThreadPerCpu() {
|
||||
static int num_cpus = NumCPUs();
|
||||
thread_counts_.push_back(num_cpus);
|
||||
}
|
||||
|
||||
void BenchmarkImp::SetName(const char* name) {
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
void BenchmarkImp::AddRange(std::vector<int>* dst, int lo, int hi, int mult) {
|
||||
CHECK_GE(lo, 0);
|
||||
CHECK_GE(hi, lo);
|
||||
CHECK_GE(mult, 2);
|
||||
|
||||
// Add "lo"
|
||||
dst->push_back(lo);
|
||||
|
||||
static const int kint32max = std::numeric_limits<int32_t>::max();
|
||||
|
||||
// Now space out the benchmarks in multiples of "mult"
|
||||
for (int32_t i = 1; i < kint32max/mult; i *= mult) {
|
||||
if (i >= hi) break;
|
||||
if (i > lo) {
|
||||
dst->push_back(i);
|
||||
}
|
||||
}
|
||||
// Add "hi" (if different from "lo")
|
||||
if (hi != lo) {
|
||||
dst->push_back(hi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Benchmark::Benchmark(const char* name)
|
||||
: imp_(new BenchmarkImp(name))
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark::~Benchmark() {
|
||||
delete imp_;
|
||||
}
|
||||
|
||||
Benchmark::Benchmark(Benchmark const& other)
|
||||
: imp_(new BenchmarkImp(*other.imp_))
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Arg(int x) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1);
|
||||
imp_->Arg(x);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Unit(TimeUnit unit) {
|
||||
imp_->Unit(unit);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Range(int start, int limit) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1);
|
||||
imp_->Range(start, limit);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Ranges(const std::vector<std::pair<int, int>>& ranges)
|
||||
{
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == static_cast<int>(ranges.size()));
|
||||
imp_->Ranges(ranges);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::DenseRange(int start, int limit, int step) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == 1);
|
||||
imp_->DenseRange(start, limit, step);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Args(const std::vector<int>& args) {
|
||||
CHECK(imp_->ArgsCnt() == -1 || imp_->ArgsCnt() == static_cast<int>(args.size()));
|
||||
imp_->Args(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
|
||||
custom_arguments(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::RangeMultiplier(int multiplier) {
|
||||
imp_->RangeMultiplier(multiplier);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Benchmark* Benchmark::Repetitions(int t) {
|
||||
imp_->Repetitions(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
|
||||
imp_->ReportAggregatesOnly(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::MinTime(double t) {
|
||||
imp_->MinTime(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::UseRealTime() {
|
||||
imp_->UseRealTime();
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::UseManualTime() {
|
||||
imp_->UseManualTime();
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Complexity(BigO complexity) {
|
||||
imp_->Complexity(complexity);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
|
||||
imp_->Complexity(oLambda);
|
||||
imp_->ComplexityLambda(complexity);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Threads(int t) {
|
||||
imp_->Threads(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
|
||||
imp_->ThreadRange(min_threads, max_threads);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark *Benchmark::DenseThreadRange(int min_threads, int max_threads,
|
||||
int stride) {
|
||||
imp_->DenseThreadRange(min_threads, max_threads, stride);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ThreadPerCpu() {
|
||||
imp_->ThreadPerCpu();
|
||||
return this;
|
||||
}
|
||||
|
||||
void Benchmark::SetName(const char* name) {
|
||||
imp_->SetName(name);
|
||||
}
|
||||
|
||||
void FunctionBenchmark::Run(State& st) {
|
||||
func_(st);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
namespace {
|
||||
|
||||
// Execute one thread of benchmark b for the specified number of iterations.
|
||||
@ -883,7 +370,8 @@ std::vector<BenchmarkReporter::Run> RunBenchmark(
|
||||
return reports;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
|
||||
State::State(size_t max_iters, const std::vector<int>& ranges, int thread_i,
|
||||
int n_threads, internal::ThreadTimer* timer,
|
||||
@ -1072,8 +560,7 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter,
|
||||
}
|
||||
|
||||
std::vector<internal::Benchmark::Instance> benchmarks;
|
||||
auto families = internal::BenchmarkFamilies::GetInstance();
|
||||
if (!families->FindBenchmarks(spec, &benchmarks, &Err)) return 0;
|
||||
if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0;
|
||||
|
||||
if (FLAGS_benchmark_list_tests) {
|
||||
for (auto const& benchmark : benchmarks)
|
||||
@ -1141,13 +628,6 @@ void ParseCommandLineFlags(int* argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
|
||||
std::unique_ptr<Benchmark> bench_ptr(bench);
|
||||
BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
|
||||
families->AddBenchmark(std::move(bench_ptr));
|
||||
return bench;
|
||||
}
|
||||
|
||||
int InitializeStreams() {
|
||||
static std::ios_base::Init init;
|
||||
return 0;
|
||||
|
47
src/benchmark_api_internal.h
Normal file
47
src/benchmark_api_internal.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef BENCHMARK_API_INTERNAL_H
|
||||
#define BENCHMARK_API_INTERNAL_H
|
||||
|
||||
#include "benchmark/benchmark_api.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
// Information kept per benchmark we may want to run
|
||||
struct Benchmark::Instance {
|
||||
std::string name;
|
||||
Benchmark* benchmark;
|
||||
ReportMode report_mode;
|
||||
std::vector<int> arg;
|
||||
TimeUnit time_unit;
|
||||
int range_multiplier;
|
||||
bool use_real_time;
|
||||
bool use_manual_time;
|
||||
BigO complexity;
|
||||
BigOFunc* complexity_lambda;
|
||||
bool last_benchmark_instance;
|
||||
int repetitions;
|
||||
double min_time;
|
||||
int threads; // Number of concurrent threads to use
|
||||
bool multithreaded; // Is benchmark multi-threaded?
|
||||
};
|
||||
|
||||
bool FindBenchmarksInternal(const std::string& re,
|
||||
std::vector<Benchmark::Instance>* benchmarks, std::ostream* Err);
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsZero(double n) {
|
||||
return std::abs(n) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_API_INTERNAL_H
|
416
src/benchmark_register.cc
Normal file
416
src/benchmark_register.cc
Normal file
@ -0,0 +1,416 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "internal_macros.h"
|
||||
#include "benchmark_api_internal.h"
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "check.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "complexity.h"
|
||||
#include "log.h"
|
||||
#include "mutex.h"
|
||||
#include "re.h"
|
||||
#include "stat.h"
|
||||
#include "string_util.h"
|
||||
#include "sysinfo.h"
|
||||
#include "timers.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
namespace {
|
||||
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
|
||||
static const int kRangeMultiplier = 8;
|
||||
// The size of a benchmark family determines is the number of inputs to repeat
|
||||
// the benchmark on. If this is "large" then warn the user during configuration.
|
||||
static const size_t kMaxFamilySize = 100;
|
||||
} // end namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
//=============================================================================//
|
||||
// BenchmarkFamilies
|
||||
//=============================================================================//
|
||||
|
||||
// Class for managing registered benchmarks. Note that each registered
|
||||
// benchmark identifies a family of related benchmarks to run.
|
||||
class BenchmarkFamilies {
|
||||
public:
|
||||
static BenchmarkFamilies* GetInstance();
|
||||
|
||||
// Registers a benchmark family and returns the index assigned to it.
|
||||
size_t AddBenchmark(std::unique_ptr<Benchmark> family);
|
||||
|
||||
// Extract the list of benchmark instances that match the specified
|
||||
// regular expression.
|
||||
bool FindBenchmarks(const std::string& re,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* Err);
|
||||
private:
|
||||
BenchmarkFamilies() {}
|
||||
|
||||
std::vector<std::unique_ptr<Benchmark>> families_;
|
||||
Mutex mutex_;
|
||||
};
|
||||
|
||||
BenchmarkFamilies* BenchmarkFamilies::GetInstance() {
|
||||
static BenchmarkFamilies instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
|
||||
MutexLock l(mutex_);
|
||||
size_t index = families_.size();
|
||||
families_.push_back(std::move(family));
|
||||
return index;
|
||||
}
|
||||
|
||||
bool BenchmarkFamilies::FindBenchmarks(
|
||||
const std::string& spec,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* ErrStream) {
|
||||
CHECK(ErrStream);
|
||||
auto& Err = *ErrStream;
|
||||
// Make regular expression out of command-line flag
|
||||
std::string error_msg;
|
||||
Regex re;
|
||||
if (!re.Init(spec, &error_msg)) {
|
||||
Err << "Could not compile benchmark re: " << error_msg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Special list of thread counts to use when none are specified
|
||||
const std::vector<int> one_thread = {1};
|
||||
|
||||
MutexLock l(mutex_);
|
||||
for (std::unique_ptr<Benchmark>& family : families_) {
|
||||
// Family was deleted or benchmark doesn't match
|
||||
if (!family) continue;
|
||||
|
||||
if (family->ArgsCnt() == -1) {
|
||||
family->Args({});
|
||||
}
|
||||
const std::vector<int>* thread_counts =
|
||||
(family->thread_counts_.empty()
|
||||
? &one_thread
|
||||
: &static_cast<const std::vector<int>&>(family->thread_counts_));
|
||||
const size_t family_size = family->args_.size() * thread_counts->size();
|
||||
// The benchmark will be run at least 'family_size' different inputs.
|
||||
// If 'family_size' is very large warn the user.
|
||||
if (family_size > kMaxFamilySize) {
|
||||
Err << "The number of inputs is very large. " << family->name_
|
||||
<< " will be repeated at least " << family_size << " times.\n";
|
||||
}
|
||||
// reserve in the special case the regex ".", since we know the final
|
||||
// family size.
|
||||
if (spec == ".")
|
||||
benchmarks->reserve(family_size);
|
||||
|
||||
for (auto const& args : family->args_) {
|
||||
for (int num_threads : *thread_counts) {
|
||||
|
||||
Benchmark::Instance instance;
|
||||
instance.name = family->name_;
|
||||
instance.benchmark = family.get();
|
||||
instance.report_mode = family->report_mode_;
|
||||
instance.arg = args;
|
||||
instance.time_unit = family->time_unit_;
|
||||
instance.range_multiplier = family->range_multiplier_;
|
||||
instance.min_time = family->min_time_;
|
||||
instance.repetitions = family->repetitions_;
|
||||
instance.use_real_time = family->use_real_time_;
|
||||
instance.use_manual_time = family->use_manual_time_;
|
||||
instance.complexity = family->complexity_;
|
||||
instance.complexity_lambda = family->complexity_lambda_;
|
||||
instance.threads = num_threads;
|
||||
instance.multithreaded = !(family->thread_counts_.empty());
|
||||
|
||||
// Add arguments to instance name
|
||||
for (auto const& arg : args) {
|
||||
AppendHumanReadable(arg, &instance.name);
|
||||
}
|
||||
|
||||
if (!IsZero(family->min_time_)) {
|
||||
instance.name += StringPrintF("/min_time:%0.3f", family->min_time_);
|
||||
}
|
||||
if (family->repetitions_ != 0) {
|
||||
instance.name += StringPrintF("/repeats:%d", family->repetitions_);
|
||||
}
|
||||
if (family->use_manual_time_) {
|
||||
instance.name += "/manual_time";
|
||||
} else if (family->use_real_time_) {
|
||||
instance.name += "/real_time";
|
||||
}
|
||||
|
||||
// Add the number of threads used to the name
|
||||
if (!family->thread_counts_.empty()) {
|
||||
instance.name += StringPrintF("/threads:%d", instance.threads);
|
||||
}
|
||||
|
||||
if (re.Match(instance.name)) {
|
||||
instance.last_benchmark_instance = (&args == &family->args_.back());
|
||||
benchmarks->push_back(std::move(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Benchmark* RegisterBenchmarkInternal(Benchmark* bench) {
|
||||
std::unique_ptr<Benchmark> bench_ptr(bench);
|
||||
BenchmarkFamilies* families = BenchmarkFamilies::GetInstance();
|
||||
families->AddBenchmark(std::move(bench_ptr));
|
||||
return bench;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: This function is a hack so that benchmark.cc can access
|
||||
// `BenchmarkFamilies`
|
||||
bool FindBenchmarksInternal(const std::string& re,
|
||||
std::vector<Benchmark::Instance>* benchmarks,
|
||||
std::ostream* Err)
|
||||
{
|
||||
return BenchmarkFamilies::GetInstance()->FindBenchmarks(re, benchmarks, Err);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================//
|
||||
// Benchmark
|
||||
//=============================================================================//
|
||||
|
||||
Benchmark::Benchmark(const char* name)
|
||||
: name_(name), report_mode_(RM_Unspecified),
|
||||
time_unit_(kNanosecond), range_multiplier_(kRangeMultiplier),
|
||||
min_time_(0), repetitions_(0), use_real_time_(false), use_manual_time_(false),
|
||||
complexity_(oNone)
|
||||
{
|
||||
}
|
||||
|
||||
Benchmark::~Benchmark() {
|
||||
}
|
||||
|
||||
void Benchmark::AddRange(std::vector<int>* dst, int lo, int hi, int mult) {
|
||||
CHECK_GE(lo, 0);
|
||||
CHECK_GE(hi, lo);
|
||||
CHECK_GE(mult, 2);
|
||||
|
||||
// Add "lo"
|
||||
dst->push_back(lo);
|
||||
|
||||
static const int kint32max = std::numeric_limits<int32_t>::max();
|
||||
|
||||
// Now space out the benchmarks in multiples of "mult"
|
||||
for (int32_t i = 1; i < kint32max/mult; i *= mult) {
|
||||
if (i >= hi) break;
|
||||
if (i > lo) {
|
||||
dst->push_back(i);
|
||||
}
|
||||
}
|
||||
// Add "hi" (if different from "lo")
|
||||
if (hi != lo) {
|
||||
dst->push_back(hi);
|
||||
}
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Arg(int x) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
args_.push_back({x});
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Unit(TimeUnit unit) {
|
||||
time_unit_ = unit;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Range(int start, int limit) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
std::vector<int> arglist;
|
||||
AddRange(&arglist, start, limit, range_multiplier_);
|
||||
|
||||
for (int i : arglist) {
|
||||
args_.push_back({i});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Ranges(const std::vector<std::pair<int, int>>& ranges)
|
||||
{
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
|
||||
std::vector<std::vector<int>> arglists(ranges.size());
|
||||
std::size_t total = 1;
|
||||
for (std::size_t i = 0; i < ranges.size(); i++) {
|
||||
AddRange(&arglists[i], ranges[i].first, ranges[i].second, range_multiplier_);
|
||||
total *= arglists[i].size();
|
||||
}
|
||||
|
||||
std::vector<std::size_t> ctr(arglists.size(), 0);
|
||||
|
||||
for (std::size_t i = 0; i < total; i++) {
|
||||
std::vector<int> tmp;
|
||||
tmp.reserve(arglists.size());
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
tmp.push_back(arglists[j].at(ctr[j]));
|
||||
}
|
||||
|
||||
args_.push_back(std::move(tmp));
|
||||
|
||||
for (std::size_t j = 0; j < arglists.size(); j++) {
|
||||
if (ctr[j] + 1 < arglists[j].size()) {
|
||||
++ctr[j];
|
||||
break;
|
||||
}
|
||||
ctr[j] = 0;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::DenseRange(int start, int limit, int step) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
|
||||
CHECK_GE(start, 0);
|
||||
CHECK_LE(start, limit);
|
||||
for (int arg = start; arg <= limit; arg+= step) {
|
||||
args_.push_back({arg});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Args(const std::vector<int>& args) {
|
||||
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args.size()));
|
||||
args_.push_back(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Apply(void (*custom_arguments)(Benchmark* benchmark)) {
|
||||
custom_arguments(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::RangeMultiplier(int multiplier) {
|
||||
CHECK(multiplier > 1);
|
||||
range_multiplier_ = multiplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Repetitions(int n) {
|
||||
CHECK(n > 0);
|
||||
repetitions_ = n;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ReportAggregatesOnly(bool value) {
|
||||
report_mode_ = value ? RM_ReportAggregatesOnly : RM_Default;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::MinTime(double t) {
|
||||
CHECK(t > 0.0);
|
||||
min_time_ = t;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::UseRealTime() {
|
||||
CHECK(!use_manual_time_) << "Cannot set UseRealTime and UseManualTime simultaneously.";
|
||||
use_real_time_ = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::UseManualTime() {
|
||||
CHECK(!use_real_time_) << "Cannot set UseRealTime and UseManualTime simultaneously.";
|
||||
use_manual_time_ = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Complexity(BigO complexity) {
|
||||
complexity_ = complexity;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
|
||||
complexity_lambda_ = complexity;
|
||||
complexity_ = oLambda;
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::Threads(int t) {
|
||||
CHECK_GT(t, 0);
|
||||
thread_counts_.push_back(t);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ThreadRange(int min_threads, int max_threads) {
|
||||
CHECK_GT(min_threads, 0);
|
||||
CHECK_GE(max_threads, min_threads);
|
||||
|
||||
AddRange(&thread_counts_, min_threads, max_threads, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark *Benchmark::DenseThreadRange(int min_threads, int max_threads,
|
||||
int stride) {
|
||||
CHECK_GT(min_threads, 0);
|
||||
CHECK_GE(max_threads, min_threads);
|
||||
CHECK_GE(stride, 1);
|
||||
|
||||
for (auto i = min_threads; i < max_threads; i += stride) {
|
||||
thread_counts_.push_back(i);
|
||||
}
|
||||
thread_counts_.push_back(max_threads);
|
||||
return this;
|
||||
}
|
||||
|
||||
Benchmark* Benchmark::ThreadPerCpu() {
|
||||
static int num_cpus = NumCPUs();
|
||||
thread_counts_.push_back(num_cpus);
|
||||
return this;
|
||||
}
|
||||
|
||||
void Benchmark::SetName(const char* name) {
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
int Benchmark::ArgsCnt() const
|
||||
{ return args_.empty() ? -1 : static_cast<int>(args_.front().size()); }
|
||||
|
||||
|
||||
//=============================================================================//
|
||||
// FunctionBenchmark
|
||||
//=============================================================================//
|
||||
|
||||
void FunctionBenchmark::Run(State& st) {
|
||||
func_(st);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
70
src/re.h
70
src/re.h
@ -26,13 +26,16 @@
|
||||
#endif
|
||||
#include <string>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// A wrapper around the POSIX regular expression API that provides automatic
|
||||
// cleanup
|
||||
class Regex {
|
||||
public:
|
||||
Regex();
|
||||
Regex() : init_(false) {}
|
||||
|
||||
~Regex();
|
||||
|
||||
// Compile a regular expression matcher from spec. Returns true on success.
|
||||
@ -43,7 +46,7 @@ class Regex {
|
||||
|
||||
// Returns whether str matches the compiled regular expression.
|
||||
bool Match(const std::string& str);
|
||||
private:
|
||||
private:
|
||||
bool init_;
|
||||
// Underlying regular expression object
|
||||
#if defined(HAVE_STD_REGEX)
|
||||
@ -55,6 +58,69 @@ class Regex {
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#if defined(HAVE_STD_REGEX)
|
||||
|
||||
inline bool Regex::Init(const std::string& spec, std::string* error) {
|
||||
try {
|
||||
re_ = std::regex(spec, std::regex_constants::extended);
|
||||
|
||||
init_ = true;
|
||||
} catch (const std::regex_error& e) {
|
||||
if (error) {
|
||||
*error = e.what();
|
||||
}
|
||||
}
|
||||
return init_;
|
||||
}
|
||||
|
||||
inline Regex::~Regex() { }
|
||||
|
||||
inline bool Regex::Match(const std::string& str) {
|
||||
if (!init_) {
|
||||
return false;
|
||||
}
|
||||
return std::regex_search(str, re_);
|
||||
}
|
||||
|
||||
#else
|
||||
inline bool Regex::Init(const std::string& spec, std::string* error) {
|
||||
int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
if (error) {
|
||||
size_t needed = regerror(ec, &re_, nullptr, 0);
|
||||
char* errbuf = new char[needed];
|
||||
regerror(ec, &re_, errbuf, needed);
|
||||
|
||||
// regerror returns the number of bytes necessary to null terminate
|
||||
// the string, so we move that when assigning to error.
|
||||
CHECK_NE(needed, 0);
|
||||
error->assign(errbuf, needed - 1);
|
||||
|
||||
delete[] errbuf;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
init_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Regex::~Regex() {
|
||||
if (init_) {
|
||||
regfree(&re_);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Regex::Match(const std::string& str) {
|
||||
if (!init_) {
|
||||
return false;
|
||||
}
|
||||
return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_RE_H_
|
||||
|
@ -1,59 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "check.h"
|
||||
#include "re.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
Regex::Regex() : init_(false) { }
|
||||
|
||||
bool Regex::Init(const std::string& spec, std::string* error) {
|
||||
int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
if (error) {
|
||||
size_t needed = regerror(ec, &re_, nullptr, 0);
|
||||
char* errbuf = new char[needed];
|
||||
regerror(ec, &re_, errbuf, needed);
|
||||
|
||||
// regerror returns the number of bytes necessary to null terminate
|
||||
// the string, so we move that when assigning to error.
|
||||
CHECK_NE(needed, 0);
|
||||
error->assign(errbuf, needed - 1);
|
||||
|
||||
delete[] errbuf;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
init_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Regex::~Regex() {
|
||||
if (init_) {
|
||||
regfree(&re_);
|
||||
}
|
||||
}
|
||||
|
||||
bool Regex::Match(const std::string& str) {
|
||||
if (!init_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return regexec(&re_, str.c_str(), 0, nullptr, 0) == 0;
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "re.h"
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
Regex::Regex() : init_(false) { }
|
||||
|
||||
bool Regex::Init(const std::string& spec, std::string* error) {
|
||||
try {
|
||||
re_ = std::regex(spec, std::regex_constants::extended);
|
||||
|
||||
init_ = true;
|
||||
} catch (const std::regex_error& e) {
|
||||
if (error) {
|
||||
*error = e.what();
|
||||
}
|
||||
}
|
||||
return init_;
|
||||
}
|
||||
|
||||
Regex::~Regex() { }
|
||||
|
||||
bool Regex::Match(const std::string& str) {
|
||||
if (!init_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::regex_search(str, re_);
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
@ -54,7 +54,6 @@ namespace benchmark {
|
||||
|
||||
// Suppress unused warnings on helper functions.
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
@ -72,9 +71,6 @@ double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) {
|
||||
1e-7;
|
||||
}
|
||||
#else
|
||||
double MakeTime(struct timespec const& ts) {
|
||||
return ts.tv_sec + (static_cast<double>(ts.tv_nsec) * 1e-9);
|
||||
}
|
||||
double MakeTime(struct rusage ru) {
|
||||
return (static_cast<double>(ru.ru_utime.tv_sec) +
|
||||
static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 +
|
||||
@ -90,6 +86,11 @@ double MakeTime(thread_basic_info_data_t const& info) {
|
||||
static_cast<double>(info.user_time.microseconds) * 1e-6);
|
||||
}
|
||||
#endif
|
||||
#if defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
double MakeTime(struct timespec const& ts) {
|
||||
return ts.tv_sec + (static_cast<double>(ts.tv_nsec) * 1e-9);
|
||||
}
|
||||
#endif
|
||||
|
||||
BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) {
|
||||
std::cerr << "ERROR: " << msg << std::endl;
|
||||
@ -98,12 +99,14 @@ BENCHMARK_NORETURN static void DiagnoseAndExit(const char* msg) {
|
||||
|
||||
} // end namespace
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
double ProcessCPUUsage() {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
#if defined(CLOCK_PROCESS_CPUTIME_ID)
|
||||
struct timespec spec;
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
|
||||
return MakeTime(spec);
|
||||
DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed");
|
||||
#elif defined(BENCHMARK_OS_WINDOWS)
|
||||
HANDLE proc = GetCurrentProcess();
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
@ -112,11 +115,6 @@ double ProcessCPUUsage() {
|
||||
if (GetProcessTimes(proc, &creation_time, &exit_time, &kernel_time, &user_time))
|
||||
return MakeTime(kernel_time, user_time);
|
||||
DiagnoseAndExit("GetProccessTimes() failed");
|
||||
#elif defined(CLOCK_PROCESS_CPUTIME_ID)
|
||||
struct timespec spec;
|
||||
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
|
||||
return MakeTime(spec);
|
||||
DiagnoseAndExit("clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ...) failed");
|
||||
#else
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_SELF, &ru) == 0)
|
||||
@ -126,7 +124,12 @@ double ProcessCPUUsage() {
|
||||
}
|
||||
|
||||
double ThreadCPUUsage() {
|
||||
#if defined(BENCHMARK_OS_WINDOWS)
|
||||
#if defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0)
|
||||
return MakeTime(ts);
|
||||
DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed");
|
||||
#elif defined(BENCHMARK_OS_WINDOWS)
|
||||
HANDLE this_thread = GetCurrentThread();
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
@ -135,11 +138,6 @@ double ThreadCPUUsage() {
|
||||
GetThreadTimes(this_thread, &creation_time, &exit_time, &kernel_time,
|
||||
&user_time);
|
||||
return MakeTime(kernel_time, user_time);
|
||||
#elif defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0)
|
||||
return MakeTime(ts);
|
||||
DiagnoseAndExit("clock_gettime(CLOCK_THREAD_CPUTIME_ID, ...) failed");
|
||||
#elif defined(BENCHMARK_OS_MACOSX)
|
||||
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
||||
thread_basic_info_data_t info;
|
||||
|
Loading…
Reference in New Issue
Block a user