summaryrefslogtreecommitdiffstats
path: root/lib/libcxx/utils/google-benchmark/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libcxx/utils/google-benchmark/src')
-rw-r--r--lib/libcxx/utils/google-benchmark/src/CMakeLists.txt79
-rw-r--r--lib/libcxx/utils/google-benchmark/src/benchmark.cc264
-rw-r--r--lib/libcxx/utils/google-benchmark/src/benchmark_api_internal.h12
-rw-r--r--lib/libcxx/utils/google-benchmark/src/benchmark_main.cc17
-rw-r--r--lib/libcxx/utils/google-benchmark/src/benchmark_register.cc113
-rw-r--r--lib/libcxx/utils/google-benchmark/src/benchmark_register.h33
-rw-r--r--lib/libcxx/utils/google-benchmark/src/check.h11
-rw-r--r--lib/libcxx/utils/google-benchmark/src/colorprint.cc4
-rw-r--r--lib/libcxx/utils/google-benchmark/src/commandlineflags.cc8
-rw-r--r--lib/libcxx/utils/google-benchmark/src/complexity.cc131
-rw-r--r--lib/libcxx/utils/google-benchmark/src/complexity.h10
-rw-r--r--lib/libcxx/utils/google-benchmark/src/console_reporter.cc55
-rw-r--r--lib/libcxx/utils/google-benchmark/src/counter.cc29
-rw-r--r--lib/libcxx/utils/google-benchmark/src/counter.h10
-rw-r--r--lib/libcxx/utils/google-benchmark/src/csv_reporter.cc29
-rw-r--r--lib/libcxx/utils/google-benchmark/src/cycleclock.h9
-rw-r--r--lib/libcxx/utils/google-benchmark/src/internal_macros.h79
-rw-r--r--lib/libcxx/utils/google-benchmark/src/json_reporter.cc83
-rw-r--r--lib/libcxx/utils/google-benchmark/src/log.h7
-rw-r--r--lib/libcxx/utils/google-benchmark/src/re.h44
-rw-r--r--lib/libcxx/utils/google-benchmark/src/reporter.cc37
-rw-r--r--lib/libcxx/utils/google-benchmark/src/statistics.cc177
-rw-r--r--lib/libcxx/utils/google-benchmark/src/statistics.h37
-rw-r--r--lib/libcxx/utils/google-benchmark/src/string_util.cc107
-rw-r--r--lib/libcxx/utils/google-benchmark/src/string_util.h30
-rw-r--r--lib/libcxx/utils/google-benchmark/src/sysinfo.cc724
-rw-r--r--lib/libcxx/utils/google-benchmark/src/thread_manager.h66
-rw-r--r--lib/libcxx/utils/google-benchmark/src/thread_timer.h69
-rw-r--r--lib/libcxx/utils/google-benchmark/src/timers.cc15
29 files changed, 1540 insertions, 749 deletions
diff --git a/lib/libcxx/utils/google-benchmark/src/CMakeLists.txt b/lib/libcxx/utils/google-benchmark/src/CMakeLists.txt
index 7707773930c..977474f43f2 100644
--- a/lib/libcxx/utils/google-benchmark/src/CMakeLists.txt
+++ b/lib/libcxx/utils/google-benchmark/src/CMakeLists.txt
@@ -11,6 +11,10 @@ file(GLOB
*.cc
${PROJECT_SOURCE_DIR}/include/benchmark/*.h
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
+file(GLOB BENCHMARK_MAIN "benchmark_main.cc")
+foreach(item ${BENCHMARK_MAIN})
+ list(REMOVE_ITEM SOURCE_FILES "${item}")
+endforeach()
add_library(benchmark ${SOURCE_FILES})
set_target_properties(benchmark PROPERTIES
@@ -18,6 +22,9 @@ set_target_properties(benchmark PROPERTIES
VERSION ${GENERIC_LIB_VERSION}
SOVERSION ${GENERIC_LIB_SOVERSION}
)
+target_include_directories(benchmark PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+ )
# Link threads.
target_link_libraries(benchmark ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
@@ -31,45 +38,71 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
target_link_libraries(benchmark Shlwapi)
endif()
+# We need extra libraries on Solaris
+if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
+ target_link_libraries(benchmark kstat)
+endif()
+
+# Benchmark main library
+add_library(benchmark_main "benchmark_main.cc")
+set_target_properties(benchmark_main PROPERTIES
+ OUTPUT_NAME "benchmark_main"
+ VERSION ${GENERIC_LIB_VERSION}
+ SOVERSION ${GENERIC_LIB_SOVERSION}
+)
+target_include_directories(benchmark PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+ )
+target_link_libraries(benchmark_main benchmark)
+
set(include_install_dir "include")
set(lib_install_dir "lib/")
set(bin_install_dir "bin/")
set(config_install_dir "lib/cmake/${PROJECT_NAME}")
+set(pkgconfig_install_dir "lib/pkgconfig")
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
+set(pkg_config "${generated_dir}/${PROJECT_NAME}.pc")
set(targets_export_name "${PROJECT_NAME}Targets")
set(namespace "${PROJECT_NAME}::")
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
- "${version_config}" VERSION ${GIT_VERSION} COMPATIBILITY SameMajorVersion
+ "${version_config}" VERSION ${GENERIC_LIB_VERSION} COMPATIBILITY SameMajorVersion
)
configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY)
+configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY)
-# Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
-install(
- TARGETS benchmark
- EXPORT ${targets_export_name}
- ARCHIVE DESTINATION ${lib_install_dir}
- LIBRARY DESTINATION ${lib_install_dir}
- RUNTIME DESTINATION ${bin_install_dir}
- INCLUDES DESTINATION ${include_install_dir})
-
-install(
- DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark"
- DESTINATION ${include_install_dir}
- FILES_MATCHING PATTERN "*.*h")
-
-install(
- FILES "${project_config}" "${version_config}"
- DESTINATION "${config_install_dir}")
-
-install(
- EXPORT "${targets_export_name}"
- NAMESPACE "${namespace}"
- DESTINATION "${config_install_dir}")
+if (BENCHMARK_ENABLE_INSTALL)
+ # Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
+ install(
+ TARGETS benchmark benchmark_main
+ EXPORT ${targets_export_name}
+ ARCHIVE DESTINATION ${lib_install_dir}
+ LIBRARY DESTINATION ${lib_install_dir}
+ RUNTIME DESTINATION ${bin_install_dir}
+ INCLUDES DESTINATION ${include_install_dir})
+
+ install(
+ DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark"
+ DESTINATION ${include_install_dir}
+ FILES_MATCHING PATTERN "*.*h")
+
+ install(
+ FILES "${project_config}" "${version_config}"
+ DESTINATION "${config_install_dir}")
+
+ install(
+ FILES "${pkg_config}"
+ DESTINATION "${pkgconfig_install_dir}")
+
+ install(
+ EXPORT "${targets_export_name}"
+ NAMESPACE "${namespace}"
+ DESTINATION "${config_install_dir}")
+endif()
diff --git a/lib/libcxx/utils/google-benchmark/src/benchmark.cc b/lib/libcxx/utils/google-benchmark/src/benchmark.cc
index 00ffa07ff56..b14bc629143 100644
--- a/lib/libcxx/utils/google-benchmark/src/benchmark.cc
+++ b/lib/libcxx/utils/google-benchmark/src/benchmark.cc
@@ -17,7 +17,9 @@
#include "internal_macros.h"
#ifndef BENCHMARK_OS_WINDOWS
+#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
+#endif
#include <sys/time.h>
#include <unistd.h>
#endif
@@ -27,10 +29,10 @@
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
-#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
+#include <string>
#include <thread>
#include "check.h"
@@ -38,13 +40,14 @@
#include "commandlineflags.h"
#include "complexity.h"
#include "counter.h"
+#include "internal_macros.h"
#include "log.h"
#include "mutex.h"
#include "re.h"
-#include "stat.h"
+#include "statistics.h"
#include "string_util.h"
-#include "sysinfo.h"
-#include "timers.h"
+#include "thread_manager.h"
+#include "thread_timer.h"
DEFINE_bool(benchmark_list_tests, false,
"Print a list of benchmarks. This option overrides all other "
@@ -82,7 +85,7 @@ DEFINE_string(benchmark_out_format, "json",
"The format to use for file output. Valid values are "
"'console', 'json', or 'csv'.");
-DEFINE_string(benchmark_out, "", "The file to write additonal output to");
+DEFINE_string(benchmark_out, "", "The file to write additional output to");
DEFINE_string(benchmark_color, "auto",
"Whether to use colors in the output. Valid values: "
@@ -91,134 +94,28 @@ DEFINE_string(benchmark_color, "auto",
"environment variable is set to a terminal type that supports "
"colors.");
+DEFINE_bool(benchmark_counters_tabular, false,
+ "Whether to use tabular format when printing user counters to "
+ "the console. Valid values: 'true'/'yes'/1, 'false'/'no'/0."
+ "Defaults to false.");
+
DEFINE_int32(v, 0, "The level of verbose logging to output");
namespace benchmark {
-namespace internal {
-
-void UseCharPointer(char const volatile*) {}
-
-} // end namespace internal
namespace {
-
static const size_t kMaxIterations = 1000000000;
-
} // end namespace
namespace internal {
-class ThreadManager {
- public:
- ThreadManager(int num_threads)
- : alive_threads_(num_threads), start_stop_barrier_(num_threads) {}
-
- Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) {
- return benchmark_mutex_;
- }
-
- bool StartStopBarrier() EXCLUDES(end_cond_mutex_) {
- return start_stop_barrier_.wait();
- }
-
- void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) {
- start_stop_barrier_.removeThread();
- if (--alive_threads_ == 0) {
- MutexLock lock(end_cond_mutex_);
- end_condition_.notify_all();
- }
- }
-
- void WaitForAllThreads() EXCLUDES(end_cond_mutex_) {
- MutexLock lock(end_cond_mutex_);
- end_condition_.wait(lock.native_handle(),
- [this]() { return alive_threads_ == 0; });
- }
-
- public:
- struct Result {
- double real_time_used = 0;
- double cpu_time_used = 0;
- double manual_time_used = 0;
- int64_t bytes_processed = 0;
- int64_t items_processed = 0;
- int complexity_n = 0;
- std::string report_label_;
- std::string error_message_;
- bool has_error_ = false;
- UserCounters counters;
- };
- GUARDED_BY(GetBenchmarkMutex()) Result results;
-
- private:
- mutable Mutex benchmark_mutex_;
- std::atomic<int> alive_threads_;
- Barrier start_stop_barrier_;
- Mutex end_cond_mutex_;
- Condition end_condition_;
-};
-
-// Timer management class
-class ThreadTimer {
- public:
- ThreadTimer() = default;
-
- // Called by each thread
- void StartTimer() {
- running_ = true;
- start_real_time_ = ChronoClockNow();
- start_cpu_time_ = ThreadCPUUsage();
- }
-
- // Called by each thread
- void StopTimer() {
- CHECK(running_);
- running_ = false;
- real_time_used_ += ChronoClockNow() - start_real_time_;
- cpu_time_used_ += ThreadCPUUsage() - start_cpu_time_;
- }
-
- // Called by each thread
- void SetIterationTime(double seconds) { manual_time_used_ += seconds; }
-
- bool running() const { return running_; }
-
- // REQUIRES: timer is not running
- double real_time_used() {
- CHECK(!running_);
- return real_time_used_;
- }
-
- // REQUIRES: timer is not running
- double cpu_time_used() {
- CHECK(!running_);
- return cpu_time_used_;
- }
-
- // REQUIRES: timer is not running
- double manual_time_used() {
- CHECK(!running_);
- return manual_time_used_;
- }
-
- private:
- bool running_ = false; // Is the timer running
- double start_real_time_ = 0; // If running_
- double start_cpu_time_ = 0; // If running_
-
- // Accumulated time so far (does not contain current slice if running_)
- double real_time_used_ = 0;
- double cpu_time_used_ = 0;
- // Manually set iteration time. User sets this with SetIterationTime(seconds).
- double manual_time_used_ = 0;
-};
+void UseCharPointer(char const volatile*) {}
namespace {
BenchmarkReporter::Run CreateRunReport(
const benchmark::internal::Benchmark::Instance& b,
- const internal::ThreadManager::Result& results, size_t iters,
- double seconds) {
+ const internal::ThreadManager::Result& results, double seconds) {
// Create report about this benchmark run.
BenchmarkReporter::Run report;
@@ -226,8 +123,8 @@ BenchmarkReporter::Run CreateRunReport(
report.error_occurred = results.has_error_;
report.error_message = results.error_message_;
report.report_label = results.report_label_;
- // Report the total iterations across all threads.
- report.iterations = static_cast<int64_t>(iters) * b.threads;
+ // This is the total iterations across all threads.
+ report.iterations = results.iterations;
report.time_unit = b.time_unit;
if (!report.error_occurred) {
@@ -251,7 +148,9 @@ BenchmarkReporter::Run CreateRunReport(
report.complexity_n = results.complexity_n;
report.complexity = b.complexity;
report.complexity_lambda = b.complexity_lambda;
+ report.statistics = b.statistics;
report.counters = results.counters;
+ internal::Finish(&report.counters, results.iterations, seconds, b.threads);
}
return report;
}
@@ -264,11 +163,12 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b,
internal::ThreadTimer timer;
State st(iters, b->arg, thread_id, b->threads, &timer, manager);
b->benchmark->Run(st);
- CHECK(st.iterations() == st.max_iterations)
+ CHECK(st.iterations() >= st.max_iterations)
<< "Benchmark returned before State::KeepRunning() returned false!";
{
MutexLock l(manager->GetBenchmarkMutex());
internal::ThreadManager::Result& results = manager->results;
+ results.iterations += st.iterations();
results.cpu_time_used += timer.cpu_time_used();
results.real_time_used += timer.real_time_used();
results.manual_time_used += timer.manual_time_used();
@@ -333,21 +233,23 @@ std::vector<BenchmarkReporter::Run> RunBenchmark(
const double min_time =
!IsZero(b.min_time) ? b.min_time : FLAGS_benchmark_min_time;
+ // clang-format off
+ // turn off clang-format since it mangles prettiness here
// Determine if this run should be reported; Either it has
// run for a sufficient amount of time or because an error was reported.
const bool should_report = repetition_num > 0
- || has_explicit_iteration_count // An exact iteration count was requested
+ || has_explicit_iteration_count // An exact iteration count was requested
|| results.has_error_
- || iters >= kMaxIterations
- || seconds >= min_time // the elapsed time is large enough
+ || iters >= kMaxIterations // No chance to try again, we hit the limit.
+ || seconds >= min_time // the elapsed time is large enough
// CPU time is specified but the elapsed real time greatly exceeds the
// minimum time. Note that user provided timers are except from this
// sanity check.
|| ((results.real_time_used >= 5 * min_time) && !b.use_manual_time);
+ // clang-format on
if (should_report) {
- BenchmarkReporter::Run report =
- CreateRunReport(b, results, iters, seconds);
+ BenchmarkReporter::Run report = CreateRunReport(b, results, seconds);
if (!report.error_occurred && b.complexity != oNone)
complexity_reports->push_back(report);
reports.push_back(report);
@@ -390,25 +292,50 @@ std::vector<BenchmarkReporter::Run> RunBenchmark(
} // namespace
} // namespace internal
-State::State(size_t max_iters, const std::vector<int>& ranges, int thread_i,
+State::State(size_t max_iters, const std::vector<int64_t>& ranges, int thread_i,
int n_threads, internal::ThreadTimer* timer,
internal::ThreadManager* manager)
- : started_(false),
+ : total_iterations_(0),
+ batch_leftover_(0),
+ max_iterations(max_iters),
+ started_(false),
finished_(false),
- total_iterations_(0),
+ error_occurred_(false),
range_(ranges),
bytes_processed_(0),
items_processed_(0),
complexity_n_(0),
- error_occurred_(false),
counters(),
thread_index(thread_i),
threads(n_threads),
- max_iterations(max_iters),
timer_(timer),
manager_(manager) {
CHECK(max_iterations != 0) << "At least one iteration must be run";
CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
+
+ // Note: The use of offsetof below is technically undefined until C++17
+ // because State is not a standard layout type. However, all compilers
+ // currently provide well-defined behavior as an extension (which is
+ // demonstrated since constexpr evaluation must diagnose all undefined
+ // behavior). However, GCC and Clang also warn about this use of offsetof,
+ // which must be suppressed.
+#if defined(__INTEL_COMPILER)
+#pragma warning push
+#pragma warning(disable:1875)
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-offsetof"
+#endif
+ // Offset tests to ensure commonly accessed data is on the first cache line.
+ const int cache_line_size = 64;
+ static_assert(offsetof(State, error_occurred_) <=
+ (cache_line_size - sizeof(error_occurred_)),
+ "");
+#if defined(__INTEL_COMPILER)
+#pragma warning pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
}
void State::PauseTiming() {
@@ -432,7 +359,7 @@ void State::SkipWithError(const char* msg) {
manager_->results.has_error_ = true;
}
}
- total_iterations_ = max_iterations;
+ total_iterations_ = 0;
if (timer_->running()) timer_->StopTimer();
}
@@ -448,6 +375,7 @@ void State::SetLabel(const char* label) {
void State::StartKeepRunning() {
CHECK(!started_ && !finished_);
started_ = true;
+ total_iterations_ = error_occurred_ ? 0 : max_iterations;
manager_->StartStopBarrier();
if (!error_occurred_) ResumeTiming();
}
@@ -457,8 +385,8 @@ void State::FinishKeepRunning() {
if (!error_occurred_) {
PauseTiming();
}
- // Total iterations now is one greater than max iterations. Fix this.
- total_iterations_ = max_iterations;
+ // Total iterations has now wrapped around past 0. Fix this.
+ total_iterations_ = 0;
finished_ = true;
manager_->StartStopBarrier();
}
@@ -467,30 +395,30 @@ namespace internal {
namespace {
void RunBenchmarks(const std::vector<Benchmark::Instance>& benchmarks,
- BenchmarkReporter* console_reporter,
- BenchmarkReporter* file_reporter) {
+ BenchmarkReporter* console_reporter,
+ BenchmarkReporter* file_reporter) {
// Note the file_reporter can be null.
CHECK(console_reporter != nullptr);
// Determine the width of the name field using a minimum width of 10.
bool has_repetitions = FLAGS_benchmark_repetitions > 1;
size_t name_field_width = 10;
+ size_t stat_field_width = 0;
for (const Benchmark::Instance& benchmark : benchmarks) {
name_field_width =
std::max<size_t>(name_field_width, benchmark.name.size());
has_repetitions |= benchmark.repetitions > 1;
+
+ for (const auto& Stat : *benchmark.statistics)
+ stat_field_width = std::max<size_t>(stat_field_width, Stat.name_.size());
}
- if (has_repetitions) name_field_width += std::strlen("_stddev");
+ if (has_repetitions) name_field_width += 1 + stat_field_width;
// Print header here
BenchmarkReporter::Context context;
- context.num_cpus = NumCPUs();
- context.mhz_per_cpu = CyclesPerSecond() / 1000000.0f;
-
- context.cpu_scaling_enabled = CpuScalingEnabled();
context.name_field_width = name_field_width;
- // Keep track of runing times of all instances of current benchmark
+ // Keep track of running times of all instances of current benchmark
std::vector<BenchmarkReporter::Run> complexity_reports;
// We flush streams after invoking reporter methods that write to them. This
@@ -521,10 +449,10 @@ void RunBenchmarks(const std::vector<Benchmark::Instance>& benchmarks,
}
std::unique_ptr<BenchmarkReporter> CreateReporter(
- std::string const& name, ConsoleReporter::OutputOptions allow_color) {
+ std::string const& name, ConsoleReporter::OutputOptions output_opts) {
typedef std::unique_ptr<BenchmarkReporter> PtrType;
if (name == "console") {
- return PtrType(new ConsoleReporter(allow_color));
+ return PtrType(new ConsoleReporter(output_opts));
} else if (name == "json") {
return PtrType(new JSONReporter);
} else if (name == "csv") {
@@ -536,6 +464,30 @@ std::unique_ptr<BenchmarkReporter> CreateReporter(
}
} // end namespace
+
+bool IsZero(double n) {
+ return std::abs(n) < std::numeric_limits<double>::epsilon();
+}
+
+ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) {
+ int output_opts = ConsoleReporter::OO_Defaults;
+ if ((FLAGS_benchmark_color == "auto" && IsColorTerminal()) ||
+ IsTruthyFlagValue(FLAGS_benchmark_color)) {
+ output_opts |= ConsoleReporter::OO_Color;
+ } else {
+ output_opts &= ~ConsoleReporter::OO_Color;
+ }
+ if (force_no_color) {
+ output_opts &= ~ConsoleReporter::OO_Color;
+ }
+ if (FLAGS_benchmark_counters_tabular) {
+ output_opts |= ConsoleReporter::OO_Tabular;
+ } else {
+ output_opts &= ~ConsoleReporter::OO_Tabular;
+ }
+ return static_cast<ConsoleReporter::OutputOptions>(output_opts);
+}
+
} // end namespace internal
size_t RunSpecifiedBenchmarks() {
@@ -557,29 +509,21 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter,
std::unique_ptr<BenchmarkReporter> default_console_reporter;
std::unique_ptr<BenchmarkReporter> default_file_reporter;
if (!console_reporter) {
- auto output_opts = ConsoleReporter::OO_None;
- if (FLAGS_benchmark_color == "auto")
- output_opts = IsColorTerminal() ? ConsoleReporter::OO_Color
- : ConsoleReporter::OO_None;
- else
- output_opts = IsTruthyFlagValue(FLAGS_benchmark_color)
- ? ConsoleReporter::OO_Color
- : ConsoleReporter::OO_None;
- default_console_reporter =
- internal::CreateReporter(FLAGS_benchmark_format, output_opts);
+ default_console_reporter = internal::CreateReporter(
+ FLAGS_benchmark_format, internal::GetOutputOptions());
console_reporter = default_console_reporter.get();
}
auto& Out = console_reporter->GetOutputStream();
auto& Err = console_reporter->GetErrorStream();
std::string const& fname = FLAGS_benchmark_out;
- if (fname == "" && file_reporter) {
+ if (fname.empty() && file_reporter) {
Err << "A custom file reporter was provided but "
"--benchmark_out=<file> was not specified."
<< std::endl;
std::exit(1);
}
- if (fname != "") {
+ if (!fname.empty()) {
output_file.open(fname);
if (!output_file.is_open()) {
Err << "invalid file name: '" << fname << std::endl;
@@ -625,12 +569,15 @@ void PrintUsageAndExit() {
" [--benchmark_out=<filename>]\n"
" [--benchmark_out_format=<json|console|csv>]\n"
" [--benchmark_color={auto|true|false}]\n"
+ " [--benchmark_counters_tabular={true|false}]\n"
" [--v=<verbosity>]\n");
exit(0);
}
void ParseCommandLineFlags(int* argc, char** argv) {
using namespace benchmark;
+ BenchmarkReporter::Context::executable_name =
+ (argc && *argc > 0) ? argv[0] : "unknown";
for (int i = 1; i < *argc; ++i) {
if (ParseBoolFlag(argv[i], "benchmark_list_tests",
&FLAGS_benchmark_list_tests) ||
@@ -649,6 +596,8 @@ void ParseCommandLineFlags(int* argc, char** argv) {
// "color_print" is the deprecated name for "benchmark_color".
// TODO: Remove this.
ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) ||
+ ParseBoolFlag(argv[i], "benchmark_counters_tabular",
+ &FLAGS_benchmark_counters_tabular) ||
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1];
@@ -682,7 +631,8 @@ void Initialize(int* argc, char** argv) {
bool ReportUnrecognizedArguments(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
- fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0], argv[i]);
+ fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0],
+ argv[i]);
}
return argc > 1;
}
diff --git a/lib/libcxx/utils/google-benchmark/src/benchmark_api_internal.h b/lib/libcxx/utils/google-benchmark/src/benchmark_api_internal.h
index 828ed12165f..dd7a3ffe8cb 100644
--- a/lib/libcxx/utils/google-benchmark/src/benchmark_api_internal.h
+++ b/lib/libcxx/utils/google-benchmark/src/benchmark_api_internal.h
@@ -1,7 +1,7 @@
#ifndef BENCHMARK_API_INTERNAL_H
#define BENCHMARK_API_INTERNAL_H
-#include "benchmark/benchmark_api.h"
+#include "benchmark/benchmark.h"
#include <cmath>
#include <iosfwd>
@@ -17,7 +17,7 @@ struct Benchmark::Instance {
std::string name;
Benchmark* benchmark;
ReportMode report_mode;
- std::vector<int> arg;
+ std::vector<int64_t> arg;
TimeUnit time_unit;
int range_multiplier;
bool use_real_time;
@@ -25,6 +25,7 @@ struct Benchmark::Instance {
BigO complexity;
BigOFunc* complexity_lambda;
UserCounters counters;
+ const std::vector<Statistics>* statistics;
bool last_benchmark_instance;
int repetitions;
double min_time;
@@ -36,13 +37,10 @@ bool FindBenchmarksInternal(const std::string& re,
std::vector<Benchmark::Instance>* benchmarks,
std::ostream* Err);
-namespace {
+bool IsZero(double n);
-bool IsZero(double n) {
- return std::abs(n) < std::numeric_limits<double>::epsilon();
-}
+ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color = false);
-} // end namespace
} // end namespace internal
} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/benchmark_main.cc b/lib/libcxx/utils/google-benchmark/src/benchmark_main.cc
new file mode 100644
index 00000000000..b3b24783149
--- /dev/null
+++ b/lib/libcxx/utils/google-benchmark/src/benchmark_main.cc
@@ -0,0 +1,17 @@
+// Copyright 2018 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"
+
+BENCHMARK_MAIN();
diff --git a/lib/libcxx/utils/google-benchmark/src/benchmark_register.cc b/lib/libcxx/utils/google-benchmark/src/benchmark_register.cc
index fe373204189..26a89721c78 100644
--- a/lib/libcxx/utils/google-benchmark/src/benchmark_register.cc
+++ b/lib/libcxx/utils/google-benchmark/src/benchmark_register.cc
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/benchmark.h"
-#include "benchmark_api_internal.h"
-#include "internal_macros.h"
+#include "benchmark_register.h"
#ifndef BENCHMARK_OS_WINDOWS
+#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
+#endif
#include <sys/time.h>
#include <unistd.h>
#endif
@@ -31,17 +31,20 @@
#include <fstream>
#include <iostream>
#include <memory>
+#include <sstream>
#include <thread>
+#include "benchmark/benchmark.h"
+#include "benchmark_api_internal.h"
#include "check.h"
#include "commandlineflags.h"
#include "complexity.h"
+#include "internal_macros.h"
#include "log.h"
#include "mutex.h"
#include "re.h"
-#include "stat.h"
+#include "statistics.h"
#include "string_util.h"
-#include "sysinfo.h"
#include "timers.h"
namespace benchmark {
@@ -69,9 +72,12 @@ class BenchmarkFamilies {
// Registers a benchmark family and returns the index assigned to it.
size_t AddBenchmark(std::unique_ptr<Benchmark> family);
+ // Clear all registered benchmark families.
+ void ClearBenchmarks();
+
// Extract the list of benchmark instances that match the specified
// regular expression.
- bool FindBenchmarks(const std::string& re,
+ bool FindBenchmarks(std::string re,
std::vector<Benchmark::Instance>* benchmarks,
std::ostream* Err);
@@ -94,14 +100,25 @@ size_t BenchmarkFamilies::AddBenchmark(std::unique_ptr<Benchmark> family) {
return index;
}
+void BenchmarkFamilies::ClearBenchmarks() {
+ MutexLock l(mutex_);
+ families_.clear();
+ families_.shrink_to_fit();
+}
+
bool BenchmarkFamilies::FindBenchmarks(
- const std::string& spec, std::vector<Benchmark::Instance>* benchmarks,
+ 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;
+ bool isNegativeFilter = false;
+ if (spec[0] == '-') {
+ spec.replace(0, 1, "");
+ isNegativeFilter = true;
+ }
if (!re.Init(spec, &error_msg)) {
Err << "Could not compile benchmark re: " << error_msg << std::endl;
return false;
@@ -149,6 +166,7 @@ bool BenchmarkFamilies::FindBenchmarks(
instance.use_manual_time = family->use_manual_time_;
instance.complexity = family->complexity_;
instance.complexity_lambda = family->complexity_lambda_;
+ instance.statistics = &family->statistics_;
instance.threads = num_threads;
// Add arguments to instance name
@@ -160,20 +178,20 @@ bool BenchmarkFamilies::FindBenchmarks(
const auto& arg_name = family->arg_names_[arg_i];
if (!arg_name.empty()) {
instance.name +=
- StringPrintF("%s:", family->arg_names_[arg_i].c_str());
+ StrFormat("%s:", family->arg_names_[arg_i].c_str());
}
}
- instance.name += std::to_string(arg);
+ instance.name += StrFormat("%d", arg);
++arg_i;
}
if (!IsZero(family->min_time_))
- instance.name += StringPrintF("/min_time:%0.3f", family->min_time_);
+ instance.name += StrFormat("/min_time:%0.3f", family->min_time_);
if (family->iterations_ != 0)
- instance.name += StringPrintF("/iterations:%d", family->iterations_);
+ instance.name += StrFormat("/iterations:%d", family->iterations_);
if (family->repetitions_ != 0)
- instance.name += StringPrintF("/repeats:%d", family->repetitions_);
+ instance.name += StrFormat("/repeats:%d", family->repetitions_);
if (family->use_manual_time_) {
instance.name += "/manual_time";
@@ -183,10 +201,11 @@ bool BenchmarkFamilies::FindBenchmarks(
// Add the number of threads used to the name
if (!family->thread_counts_.empty()) {
- instance.name += StringPrintF("/threads:%d", instance.threads);
+ instance.name += StrFormat("/threads:%d", instance.threads);
}
- if (re.Match(instance.name)) {
+ if ((re.Match(instance.name) && !isNegativeFilter) ||
+ (!re.Match(instance.name) && isNegativeFilter)) {
instance.last_benchmark_instance = (&args == &family->args_.back());
benchmarks->push_back(std::move(instance));
}
@@ -226,34 +245,15 @@ Benchmark::Benchmark(const char* name)
use_real_time_(false),
use_manual_time_(false),
complexity_(oNone),
- complexity_lambda_(nullptr) {}
+ complexity_lambda_(nullptr) {
+ ComputeStatistics("mean", StatisticsMean);
+ ComputeStatistics("median", StatisticsMedian);
+ ComputeStatistics("stddev", StatisticsStdDev);
+}
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) {
+Benchmark* Benchmark::Arg(int64_t x) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
args_.push_back({x});
return this;
@@ -264,20 +264,21 @@ Benchmark* Benchmark::Unit(TimeUnit unit) {
return this;
}
-Benchmark* Benchmark::Range(int start, int limit) {
+Benchmark* Benchmark::Range(int64_t start, int64_t limit) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
- std::vector<int> arglist;
+ std::vector<int64_t> arglist;
AddRange(&arglist, start, limit, range_multiplier_);
- for (int i : arglist) {
+ for (int64_t i : arglist) {
args_.push_back({i});
}
return this;
}
-Benchmark* Benchmark::Ranges(const std::vector<std::pair<int, int>>& ranges) {
+Benchmark* Benchmark::Ranges(
+ const std::vector<std::pair<int64_t, int64_t>>& ranges) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(ranges.size()));
- std::vector<std::vector<int>> arglists(ranges.size());
+ std::vector<std::vector<int64_t>> 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,
@@ -288,7 +289,7 @@ Benchmark* Benchmark::Ranges(const std::vector<std::pair<int, int>>& ranges) {
std::vector<std::size_t> ctr(arglists.size(), 0);
for (std::size_t i = 0; i < total; i++) {
- std::vector<int> tmp;
+ std::vector<int64_t> tmp;
tmp.reserve(arglists.size());
for (std::size_t j = 0; j < arglists.size(); j++) {
@@ -320,17 +321,17 @@ Benchmark* Benchmark::ArgNames(const std::vector<std::string>& names) {
return this;
}
-Benchmark* Benchmark::DenseRange(int start, int limit, int step) {
+Benchmark* Benchmark::DenseRange(int64_t start, int64_t limit, int step) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == 1);
CHECK_GE(start, 0);
CHECK_LE(start, limit);
- for (int arg = start; arg <= limit; arg += step) {
+ for (int64_t arg = start; arg <= limit; arg += step) {
args_.push_back({arg});
}
return this;
}
-Benchmark* Benchmark::Args(const std::vector<int>& args) {
+Benchmark* Benchmark::Args(const std::vector<int64_t>& args) {
CHECK(ArgsCnt() == -1 || ArgsCnt() == static_cast<int>(args.size()));
args_.push_back(args);
return this;
@@ -347,7 +348,6 @@ Benchmark* Benchmark::RangeMultiplier(int multiplier) {
return this;
}
-
Benchmark* Benchmark::MinTime(double t) {
CHECK(t > 0.0);
CHECK(iterations_ == 0);
@@ -355,7 +355,6 @@ Benchmark* Benchmark::MinTime(double t) {
return this;
}
-
Benchmark* Benchmark::Iterations(size_t n) {
CHECK(n > 0);
CHECK(IsZero(min_time_));
@@ -399,6 +398,12 @@ Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
return this;
}
+Benchmark* Benchmark::ComputeStatistics(std::string name,
+ StatisticsFunc* statistics) {
+ statistics_.emplace_back(name, statistics);
+ return this;
+}
+
Benchmark* Benchmark::Threads(int t) {
CHECK_GT(t, 0);
thread_counts_.push_back(t);
@@ -427,8 +432,7 @@ Benchmark* Benchmark::DenseThreadRange(int min_threads, int max_threads,
}
Benchmark* Benchmark::ThreadPerCpu() {
- static int num_cpus = NumCPUs();
- thread_counts_.push_back(num_cpus);
+ thread_counts_.push_back(CPUInfo::Get().num_cpus);
return this;
}
@@ -449,4 +453,9 @@ int Benchmark::ArgsCnt() const {
void FunctionBenchmark::Run(State& st) { func_(st); }
} // end namespace internal
+
+void ClearRegisteredBenchmarks() {
+ internal::BenchmarkFamilies::GetInstance()->ClearBenchmarks();
+}
+
} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/benchmark_register.h b/lib/libcxx/utils/google-benchmark/src/benchmark_register.h
new file mode 100644
index 00000000000..0705e219f2f
--- /dev/null
+++ b/lib/libcxx/utils/google-benchmark/src/benchmark_register.h
@@ -0,0 +1,33 @@
+#ifndef BENCHMARK_REGISTER_H
+#define BENCHMARK_REGISTER_H
+
+#include <vector>
+
+#include "check.h"
+
+template <typename T>
+void AddRange(std::vector<T>* dst, T lo, T hi, int mult) {
+ CHECK_GE(lo, 0);
+ CHECK_GE(hi, lo);
+ CHECK_GE(mult, 2);
+
+ // Add "lo"
+ dst->push_back(lo);
+
+ static const T kmax = std::numeric_limits<T>::max();
+
+ // Now space out the benchmarks in multiples of "mult"
+ for (T i = 1; i < kmax / 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);
+ }
+}
+
+#endif // BENCHMARK_REGISTER_H
diff --git a/lib/libcxx/utils/google-benchmark/src/check.h b/lib/libcxx/utils/google-benchmark/src/check.h
index 6f1fe0cf860..f5f8253f804 100644
--- a/lib/libcxx/utils/google-benchmark/src/check.h
+++ b/lib/libcxx/utils/google-benchmark/src/check.h
@@ -1,6 +1,7 @@
#ifndef CHECK_H_
#define CHECK_H_
+#include <cmath>
#include <cstdlib>
#include <ostream>
@@ -61,6 +62,8 @@ class CheckHandler {
#define CHECK(b) ::benchmark::internal::GetNullLogInstance()
#endif
+// clang-format off
+// preserve whitespacing between operators for alignment
#define CHECK_EQ(a, b) CHECK((a) == (b))
#define CHECK_NE(a, b) CHECK((a) != (b))
#define CHECK_GE(a, b) CHECK((a) >= (b))
@@ -68,4 +71,12 @@ class CheckHandler {
#define CHECK_GT(a, b) CHECK((a) > (b))
#define CHECK_LT(a, b) CHECK((a) < (b))
+#define CHECK_FLOAT_EQ(a, b, eps) CHECK(std::fabs((a) - (b)) < (eps))
+#define CHECK_FLOAT_NE(a, b, eps) CHECK(std::fabs((a) - (b)) >= (eps))
+#define CHECK_FLOAT_GE(a, b, eps) CHECK((a) - (b) > -(eps))
+#define CHECK_FLOAT_LE(a, b, eps) CHECK((b) - (a) > -(eps))
+#define CHECK_FLOAT_GT(a, b, eps) CHECK((a) - (b) > (eps))
+#define CHECK_FLOAT_LT(a, b, eps) CHECK((b) - (a) > (eps))
+//clang-format on
+
#endif // CHECK_H_
diff --git a/lib/libcxx/utils/google-benchmark/src/colorprint.cc b/lib/libcxx/utils/google-benchmark/src/colorprint.cc
index 513376b14b1..2dec4a8b28b 100644
--- a/lib/libcxx/utils/google-benchmark/src/colorprint.cc
+++ b/lib/libcxx/utils/google-benchmark/src/colorprint.cc
@@ -89,7 +89,7 @@ std::string FormatString(const char* msg, va_list args) {
std::size_t size = 256;
char local_buff[256];
- auto ret = std::vsnprintf(local_buff, size, msg, args_cp);
+ auto ret = vsnprintf(local_buff, size, msg, args_cp);
va_end(args_cp);
@@ -104,7 +104,7 @@ std::string FormatString(const char* msg, va_list args) {
// we did not provide a long enough buffer on our first attempt.
size = (size_t)ret + 1; // + 1 for the null byte
std::unique_ptr<char[]> buff(new char[size]);
- ret = std::vsnprintf(buff.get(), size, msg, args);
+ ret = vsnprintf(buff.get(), size, msg, args);
CHECK(ret > 0 && ((size_t)ret) < size);
return buff.get();
}
diff --git a/lib/libcxx/utils/google-benchmark/src/commandlineflags.cc b/lib/libcxx/utils/google-benchmark/src/commandlineflags.cc
index 72534e022a8..734e88bbec6 100644
--- a/lib/libcxx/utils/google-benchmark/src/commandlineflags.cc
+++ b/lib/libcxx/utils/google-benchmark/src/commandlineflags.cc
@@ -45,7 +45,7 @@ bool ParseInt32(const std::string& src_text, const char* str, int32_t* value) {
// LONG_MAX or LONG_MIN when the input overflows.)
result != long_value
// The parsed value overflows as an Int32.
- ) {
+ ) {
std::cerr << src_text << " is expected to be a 32-bit integer, "
<< "but actually has value \"" << str << "\", "
<< "which overflows.\n";
@@ -209,9 +209,9 @@ bool IsFlag(const char* str, const char* flag) {
return (ParseFlagValue(str, flag, true) != nullptr);
}
-bool IsTruthyFlagValue(const std::string& str) {
- if (str.empty()) return true;
- char ch = str[0];
+bool IsTruthyFlagValue(const std::string& value) {
+ if (value.empty()) return true;
+ char ch = value[0];
return isalnum(ch) &&
!(ch == '0' || ch == 'f' || ch == 'F' || ch == 'n' || ch == 'N');
}
diff --git a/lib/libcxx/utils/google-benchmark/src/complexity.cc b/lib/libcxx/utils/google-benchmark/src/complexity.cc
index 02adbef6292..aafd538df21 100644
--- a/lib/libcxx/utils/google-benchmark/src/complexity.cc
+++ b/lib/libcxx/utils/google-benchmark/src/complexity.cc
@@ -15,32 +15,34 @@
// Source project : https://github.com/ismaelJimenez/cpp.leastsq
// Adapted to be used with google benchmark
-#include "benchmark/benchmark_api.h"
+#include "benchmark/benchmark.h"
#include <algorithm>
#include <cmath>
#include "check.h"
#include "complexity.h"
-#include "stat.h"
namespace benchmark {
// Internal function to calculate the different scalability forms
BigOFunc* FittingCurve(BigO complexity) {
+ static const double kLog2E = 1.44269504088896340736;
switch (complexity) {
case oN:
- return [](int n) -> double { return n; };
+ return [](int64_t n) -> double { return static_cast<double>(n); };
case oNSquared:
- return [](int n) -> double { return std::pow(n, 2); };
+ return [](int64_t n) -> double { return std::pow(n, 2); };
case oNCubed:
- return [](int n) -> double { return std::pow(n, 3); };
+ return [](int64_t n) -> double { return std::pow(n, 3); };
case oLogN:
- return [](int n) { return std::log2(n); };
+ /* Note: can't use log2 because Android's GNU STL lacks it */
+ return [](int64_t n) { return kLog2E * log(static_cast<double>(n)); };
case oNLogN:
- return [](int n) { return n * std::log2(n); };
+ /* Note: can't use log2 because Android's GNU STL lacks it */
+ return [](int64_t n) { return kLog2E * n * log(static_cast<double>(n)); };
case o1:
default:
- return [](int) { return 1.0; };
+ return [](int64_t) { return 1.0; };
}
}
@@ -66,15 +68,15 @@ std::string GetBigOString(BigO complexity) {
// Find the coefficient for the high-order term in the running time, by
// minimizing the sum of squares of relative error, for the fitting curve
-// given by the lambda expresion.
+// given by the lambda expression.
// - n : Vector containing the size of the benchmark tests.
// - time : Vector containing the times for the benchmark tests.
-// - fitting_curve : lambda expresion (e.g. [](int n) {return n; };).
+// - fitting_curve : lambda expression (e.g. [](int64_t n) {return n; };).
// For a deeper explanation on the algorithm logic, look the README file at
// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit
-LeastSq MinimalLeastSq(const std::vector<int>& n,
+LeastSq MinimalLeastSq(const std::vector<int64_t>& n,
const std::vector<double>& time,
BigOFunc* fitting_curve) {
double sigma_gn = 0.0;
@@ -118,7 +120,7 @@ LeastSq MinimalLeastSq(const std::vector<int>& n,
// - complexity : If different than oAuto, the fitting curve will stick to
// this one. If it is oAuto, it will be calculated the best
// fitting curve.
-LeastSq MinimalLeastSq(const std::vector<int>& n,
+LeastSq MinimalLeastSq(const std::vector<int64_t>& n,
const std::vector<double>& time, const BigO complexity) {
CHECK_EQ(n.size(), time.size());
CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two
@@ -150,109 +152,6 @@ LeastSq MinimalLeastSq(const std::vector<int>& n,
return best_fit;
}
-std::vector<BenchmarkReporter::Run> ComputeStats(
- const std::vector<BenchmarkReporter::Run>& reports) {
- typedef BenchmarkReporter::Run Run;
- std::vector<Run> results;
-
- auto error_count =
- std::count_if(reports.begin(), reports.end(),
- [](Run const& run) { return run.error_occurred; });
-
- if (reports.size() - error_count < 2) {
- // We don't report aggregated data if there was a single run.
- return results;
- }
- // Accumulators.
- Stat1_d real_accumulated_time_stat;
- Stat1_d cpu_accumulated_time_stat;
- Stat1_d bytes_per_second_stat;
- Stat1_d items_per_second_stat;
- // All repetitions should be run with the same number of iterations so we
- // can take this information from the first benchmark.
- int64_t const run_iterations = reports.front().iterations;
- // create stats for user counters
- struct CounterStat {
- Counter c;
- Stat1_d s;
- };
- std::map< std::string, CounterStat > counter_stats;
- for(Run const& r : reports) {
- for(auto const& cnt : r.counters) {
- auto it = counter_stats.find(cnt.first);
- if(it == counter_stats.end()) {
- counter_stats.insert({cnt.first, {cnt.second, Stat1_d{}}});
- } else {
- CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags);
- }
- }
- }
-
- // Populate the accumulators.
- for (Run const& run : reports) {
- CHECK_EQ(reports[0].benchmark_name, run.benchmark_name);
- CHECK_EQ(run_iterations, run.iterations);
- if (run.error_occurred) continue;
- real_accumulated_time_stat +=
- Stat1_d(run.real_accumulated_time / run.iterations, run.iterations);
- cpu_accumulated_time_stat +=
- Stat1_d(run.cpu_accumulated_time / run.iterations, run.iterations);
- items_per_second_stat += Stat1_d(run.items_per_second, run.iterations);
- bytes_per_second_stat += Stat1_d(run.bytes_per_second, run.iterations);
- // user counters
- for(auto const& cnt : run.counters) {
- auto it = counter_stats.find(cnt.first);
- CHECK_NE(it, counter_stats.end());
- it->second.s += Stat1_d(cnt.second, run.iterations);
- }
- }
-
- // Get the data from the accumulator to BenchmarkReporter::Run's.
- Run mean_data;
- mean_data.benchmark_name = reports[0].benchmark_name + "_mean";
- mean_data.iterations = run_iterations;
- mean_data.real_accumulated_time =
- real_accumulated_time_stat.Mean() * run_iterations;
- mean_data.cpu_accumulated_time =
- cpu_accumulated_time_stat.Mean() * run_iterations;
- mean_data.bytes_per_second = bytes_per_second_stat.Mean();
- mean_data.items_per_second = items_per_second_stat.Mean();
- mean_data.time_unit = reports[0].time_unit;
- // user counters
- for(auto const& kv : counter_stats) {
- auto c = Counter(kv.second.s.Mean(), counter_stats[kv.first].c.flags);
- mean_data.counters[kv.first] = c;
- }
-
- // Only add label to mean/stddev if it is same for all runs
- mean_data.report_label = reports[0].report_label;
- for (std::size_t i = 1; i < reports.size(); i++) {
- if (reports[i].report_label != reports[0].report_label) {
- mean_data.report_label = "";
- break;
- }
- }
-
- Run stddev_data;
- stddev_data.benchmark_name = reports[0].benchmark_name + "_stddev";
- stddev_data.report_label = mean_data.report_label;
- stddev_data.iterations = 0;
- stddev_data.real_accumulated_time = real_accumulated_time_stat.StdDev();
- stddev_data.cpu_accumulated_time = cpu_accumulated_time_stat.StdDev();
- stddev_data.bytes_per_second = bytes_per_second_stat.StdDev();
- stddev_data.items_per_second = items_per_second_stat.StdDev();
- stddev_data.time_unit = reports[0].time_unit;
- // user counters
- for(auto const& kv : counter_stats) {
- auto c = Counter(kv.second.s.StdDev(), counter_stats[kv.first].c.flags);
- stddev_data.counters[kv.first] = c;
- }
-
- results.push_back(mean_data);
- results.push_back(stddev_data);
- return results;
-}
-
std::vector<BenchmarkReporter::Run> ComputeBigO(
const std::vector<BenchmarkReporter::Run>& reports) {
typedef BenchmarkReporter::Run Run;
@@ -261,7 +160,7 @@ std::vector<BenchmarkReporter::Run> ComputeBigO(
if (reports.size() < 2) return results;
// Accumulators.
- std::vector<int> n;
+ std::vector<int64_t> n;
std::vector<double> real_time;
std::vector<double> cpu_time;
diff --git a/lib/libcxx/utils/google-benchmark/src/complexity.h b/lib/libcxx/utils/google-benchmark/src/complexity.h
index 23cd9bbc8c7..df29b48d29b 100644
--- a/lib/libcxx/utils/google-benchmark/src/complexity.h
+++ b/lib/libcxx/utils/google-benchmark/src/complexity.h
@@ -21,17 +21,10 @@
#include <string>
#include <vector>
-#include "benchmark/benchmark_api.h"
-#include "benchmark/reporter.h"
+#include "benchmark/benchmark.h"
namespace benchmark {
-// Return a vector containing the mean and standard devation information for
-// the specified list of reports. If 'reports' contains less than two
-// non-errored runs an empty vector is returned
-std::vector<BenchmarkReporter::Run> ComputeStats(
- const std::vector<BenchmarkReporter::Run>& reports);
-
// Return a vector containing the bigO and RMS information for the specified
// list of reports. If 'reports.size() < 2' an empty vector is returned.
std::vector<BenchmarkReporter::Run> ComputeBigO(
@@ -58,4 +51,5 @@ struct LeastSq {
std::string GetBigOString(BigO complexity);
} // end namespace benchmark
+
#endif // COMPLEXITY_H_
diff --git a/lib/libcxx/utils/google-benchmark/src/console_reporter.cc b/lib/libcxx/utils/google-benchmark/src/console_reporter.cc
index 3f3de02945a..48920ca7829 100644
--- a/lib/libcxx/utils/google-benchmark/src/console_reporter.cc
+++ b/lib/libcxx/utils/google-benchmark/src/console_reporter.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/reporter.h"
+#include "benchmark/benchmark.h"
#include "complexity.h"
#include "counter.h"
@@ -36,15 +36,16 @@ namespace benchmark {
bool ConsoleReporter::ReportContext(const Context& context) {
name_field_width_ = context.name_field_width;
printed_header_ = false;
+ prev_counters_.clear();
PrintBasicContext(&GetErrorStream(), context);
#ifdef BENCHMARK_OS_WINDOWS
- if (color_output_ && &std::cout != &GetOutputStream()) {
+ if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) {
GetErrorStream()
<< "Color printing is only supported for stdout on windows."
" Disabling color printing\n";
- color_output_ = false;
+ output_options_ = static_cast< OutputOptions >(output_options_ & ~OO_Color);
}
#endif
@@ -52,25 +53,39 @@ bool ConsoleReporter::ReportContext(const Context& context) {
}
void ConsoleReporter::PrintHeader(const Run& run) {
- std::string str =
- FormatString("%-*s %13s %13s %10s\n", static_cast<int>(name_field_width_),
- "Benchmark", "Time", "CPU", "Iterations");
+ std::string str = FormatString("%-*s %13s %13s %10s", static_cast<int>(name_field_width_),
+ "Benchmark", "Time", "CPU", "Iterations");
if(!run.counters.empty()) {
- str += " UserCounters...";
+ if(output_options_ & OO_Tabular) {
+ for(auto const& c : run.counters) {
+ str += FormatString(" %10s", c.first.c_str());
+ }
+ } else {
+ str += " UserCounters...";
+ }
}
+ str += "\n";
std::string line = std::string(str.length(), '-');
GetOutputStream() << line << "\n" << str << line << "\n";
}
void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
for (const auto& run : reports) {
- // print the header if none was printed yet
- if (!printed_header_) {
+ // print the header:
+ // --- if none was printed yet
+ bool print_header = !printed_header_;
+ // --- or if the format is tabular and this run
+ // has different fields from the prev header
+ print_header |= (output_options_ & OO_Tabular) &&
+ (!internal::SameNames(run.counters, prev_counters_));
+ if (print_header) {
printed_header_ = true;
+ prev_counters_ = run.counters;
PrintHeader(run);
}
// As an alternative to printing the headers like this, we could sort
- // the benchmarks by header and then print like that.
+ // the benchmarks by header and then print. But this would require
+ // waiting for the full results before printing, or printing twice.
PrintRunData(run);
}
}
@@ -86,8 +101,8 @@ static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt,
void ConsoleReporter::PrintRunData(const Run& result) {
typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...);
auto& Out = GetOutputStream();
- PrinterFn* printer =
- color_output_ ? (PrinterFn*)ColorPrintf : IgnoreColorPrint;
+ PrinterFn* printer = (output_options_ & OO_Color) ?
+ (PrinterFn*)ColorPrintf : IgnoreColorPrint;
auto name_color =
(result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN;
printer(Out, name_color, "%-*s ", name_field_width_,
@@ -133,8 +148,20 @@ void ConsoleReporter::PrintRunData(const Run& result) {
}
for (auto& c : result.counters) {
- auto const& s = HumanReadableNumber(c.second.value);
- printer(Out, COLOR_DEFAULT, " %s=%s", c.first.c_str(), s.c_str());
+ const std::size_t cNameLen = std::max(std::string::size_type(10),
+ c.first.length());
+ auto const& s = HumanReadableNumber(c.second.value, 1000);
+ if (output_options_ & OO_Tabular) {
+ if (c.second.flags & Counter::kIsRate) {
+ printer(Out, COLOR_DEFAULT, " %*s/s", cNameLen - 2, s.c_str());
+ } else {
+ printer(Out, COLOR_DEFAULT, " %*s", cNameLen, s.c_str());
+ }
+ } else {
+ const char* unit = (c.second.flags & Counter::kIsRate) ? "/s" : "";
+ printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(),
+ unit);
+ }
}
if (!rate.empty()) {
diff --git a/lib/libcxx/utils/google-benchmark/src/counter.cc b/lib/libcxx/utils/google-benchmark/src/counter.cc
index 307863d3c4d..cb604e060b6 100644
--- a/lib/libcxx/utils/google-benchmark/src/counter.cc
+++ b/lib/libcxx/utils/google-benchmark/src/counter.cc
@@ -17,7 +17,8 @@
namespace benchmark {
namespace internal {
-double Finish(Counter const& c, double cpu_time, double num_threads) {
+double Finish(Counter const& c, int64_t iterations, double cpu_time,
+ double num_threads) {
double v = c.value;
if (c.flags & Counter::kIsRate) {
v /= cpu_time;
@@ -25,25 +26,31 @@ double Finish(Counter const& c, double cpu_time, double num_threads) {
if (c.flags & Counter::kAvgThreads) {
v /= num_threads;
}
+ if (c.flags & Counter::kIsIterationInvariant) {
+ v *= iterations;
+ }
+ if (c.flags & Counter::kAvgIterations) {
+ v /= iterations;
+ }
return v;
}
-void Finish(UserCounters *l, double cpu_time, double num_threads) {
- for (auto &c : *l) {
- c.second = Finish(c.second, cpu_time, num_threads);
+void Finish(UserCounters* l, int64_t iterations, double cpu_time, double num_threads) {
+ for (auto& c : *l) {
+ c.second.value = Finish(c.second, iterations, cpu_time, num_threads);
}
}
-void Increment(UserCounters *l, UserCounters const& r) {
+void Increment(UserCounters* l, UserCounters const& r) {
// add counters present in both or just in *l
- for (auto &c : *l) {
+ for (auto& c : *l) {
auto it = r.find(c.first);
if (it != r.end()) {
- c.second = c.second + it->second;
+ c.second.value = c.second + it->second;
}
}
// add counters present in r, but not in *l
- for (auto const &tc : r) {
+ for (auto const& tc : r) {
auto it = l->find(tc.first);
if (it == l->end()) {
(*l)[tc.first] = tc.second;
@@ -57,12 +64,12 @@ bool SameNames(UserCounters const& l, UserCounters const& r) {
return false;
}
for (auto const& c : l) {
- if ( r.find(c.first) == r.end()) {
+ if (r.find(c.first) == r.end()) {
return false;
}
}
return true;
}
-} // end namespace internal
-} // end namespace benchmark
+} // end namespace internal
+} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/counter.h b/lib/libcxx/utils/google-benchmark/src/counter.h
index bbb92d9a298..d884e50aa12 100644
--- a/lib/libcxx/utils/google-benchmark/src/counter.h
+++ b/lib/libcxx/utils/google-benchmark/src/counter.h
@@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/benchmark_api.h"
+#include "benchmark/benchmark.h"
namespace benchmark {
// these counter-related functions are hidden to reduce API surface.
namespace internal {
-void Finish(UserCounters *l, double time, double num_threads);
-void Increment(UserCounters *l, UserCounters const& r);
+void Finish(UserCounters* l, int64_t iterations, double time, double num_threads);
+void Increment(UserCounters* l, UserCounters const& r);
bool SameNames(UserCounters const& l, UserCounters const& r);
-} // end namespace internal
+} // end namespace internal
-} //end namespace benchmark
+} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/csv_reporter.cc b/lib/libcxx/utils/google-benchmark/src/csv_reporter.cc
index 6779815b3c3..4a641909d80 100644
--- a/lib/libcxx/utils/google-benchmark/src/csv_reporter.cc
+++ b/lib/libcxx/utils/google-benchmark/src/csv_reporter.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/reporter.h"
+#include "benchmark/benchmark.h"
#include "complexity.h"
#include <algorithm>
@@ -22,9 +22,9 @@
#include <tuple>
#include <vector>
+#include "check.h"
#include "string_util.h"
#include "timers.h"
-#include "check.h"
// File format reference: http://edoceo.com/utilitas/csv-file-format.
@@ -35,14 +35,14 @@ std::vector<std::string> elements = {
"name", "iterations", "real_time", "cpu_time",
"time_unit", "bytes_per_second", "items_per_second", "label",
"error_occurred", "error_message"};
-}
+} // namespace
bool CSVReporter::ReportContext(const Context& context) {
PrintBasicContext(&GetErrorStream(), context);
return true;
}
-void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
+void CSVReporter::ReportRuns(const std::vector<Run>& reports) {
std::ostream& Out = GetOutputStream();
if (!printed_header_) {
@@ -58,7 +58,8 @@ void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
Out << *B++;
if (B != elements.end()) Out << ",";
}
- for (auto B = user_counter_names_.begin(); B != user_counter_names_.end();) {
+ for (auto B = user_counter_names_.begin();
+ B != user_counter_names_.end();) {
Out << ",\"" << *B++ << "\"";
}
Out << "\n";
@@ -69,9 +70,9 @@ void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
for (const auto& run : reports) {
for (const auto& cnt : run.counters) {
CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end())
- << "All counters must be present in each run. "
- << "Counter named \"" << cnt.first
- << "\" was not in a run after being added to the header";
+ << "All counters must be present in each run. "
+ << "Counter named \"" << cnt.first
+ << "\" was not in a run after being added to the header";
}
}
}
@@ -80,10 +81,9 @@ void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
for (const auto& run : reports) {
PrintRunData(run);
}
-
}
-void CSVReporter::PrintRunData(const Run & run) {
+void CSVReporter::PrintRunData(const Run& run) {
std::ostream& Out = GetOutputStream();
// Field with embedded double-quote characters must be doubled and the field
@@ -135,10 +135,13 @@ void CSVReporter::PrintRunData(const Run & run) {
Out << ",,"; // for error_occurred and error_message
// Print user counters
- for (const auto &ucn : user_counter_names_) {
+ for (const auto& ucn : user_counter_names_) {
auto it = run.counters.find(ucn);
- CHECK(it != run.counters.end());
- Out << "," << it->second;
+ if (it == run.counters.end()) {
+ Out << ",";
+ } else {
+ Out << "," << it->second;
+ }
}
Out << '\n';
}
diff --git a/lib/libcxx/utils/google-benchmark/src/cycleclock.h b/lib/libcxx/utils/google-benchmark/src/cycleclock.h
index e0f9b01f9d3..00d57641676 100644
--- a/lib/libcxx/utils/google-benchmark/src/cycleclock.h
+++ b/lib/libcxx/utils/google-benchmark/src/cycleclock.h
@@ -23,7 +23,7 @@
#include <cstdint>
-#include "benchmark/macros.h"
+#include "benchmark/benchmark.h"
#include "internal_macros.h"
#if defined(BENCHMARK_OS_MACOSX)
@@ -121,7 +121,7 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
// because is provides nanosecond resolution (which is noticable at
// least for PNaCl modules running on x86 Mac & Linux).
// Initialize to always return 0 if clock_gettime fails.
- struct timespec ts = { 0, 0 };
+ struct timespec ts = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
#elif defined(__aarch64__)
@@ -159,6 +159,11 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() {
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
+#elif defined(__s390__) // Covers both s390 and s390x.
+ // Return the CPU clock.
+ uint64_t tsc;
+ asm("stck %0" : "=Q"(tsc) : : "cc");
+ return tsc;
#else
// The soft failover to a generic implementation is automatic only for ARM.
// For other platforms the developer is expected to make an attempt to create
diff --git a/lib/libcxx/utils/google-benchmark/src/internal_macros.h b/lib/libcxx/utils/google-benchmark/src/internal_macros.h
index ab9dd85c102..b7e9203ff60 100644
--- a/lib/libcxx/utils/google-benchmark/src/internal_macros.h
+++ b/lib/libcxx/utils/google-benchmark/src/internal_macros.h
@@ -1,36 +1,51 @@
#ifndef BENCHMARK_INTERNAL_MACROS_H_
#define BENCHMARK_INTERNAL_MACROS_H_
-#include "benchmark/macros.h"
+#include "benchmark/benchmark.h"
+
+/* Needed to detect STL */
+#include <cstdlib>
+
+// clang-format off
#ifndef __has_feature
#define __has_feature(x) 0
#endif
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
#if defined(__clang__)
-#define COMPILER_CLANG
+ #if !defined(COMPILER_CLANG)
+ #define COMPILER_CLANG
+ #endif
#elif defined(_MSC_VER)
-#define COMPILER_MSVC
+ #if !defined(COMPILER_MSVC)
+ #define COMPILER_MSVC
+ #endif
#elif defined(__GNUC__)
-#define COMPILER_GCC
+ #if !defined(COMPILER_GCC)
+ #define COMPILER_GCC
+ #endif
#endif
#if __has_feature(cxx_attributes)
-#define BENCHMARK_NORETURN [[noreturn]]
+ #define BENCHMARK_NORETURN [[noreturn]]
#elif defined(__GNUC__)
-#define BENCHMARK_NORETURN __attribute__((noreturn))
+ #define BENCHMARK_NORETURN __attribute__((noreturn))
#elif defined(COMPILER_MSVC)
-#define BENCHMARK_NORETURN __declspec(noreturn)
+ #define BENCHMARK_NORETURN __declspec(noreturn)
#else
-#define BENCHMARK_NORETURN
+ #define BENCHMARK_NORETURN
#endif
#if defined(__CYGWIN__)
-#define BENCHMARK_OS_CYGWIN 1
+ #define BENCHMARK_OS_CYGWIN 1
#elif defined(_WIN32)
-#define BENCHMARK_OS_WINDOWS 1
+ #define BENCHMARK_OS_WINDOWS 1
#elif defined(__APPLE__)
-#include "TargetConditionals.h"
+ #define BENCHMARK_OS_APPLE 1
+ #include "TargetConditionals.h"
#if defined(TARGET_OS_MAC)
#define BENCHMARK_OS_MACOSX 1
#if defined(TARGET_OS_IPHONE)
@@ -38,18 +53,48 @@
#endif
#endif
#elif defined(__FreeBSD__)
-#define BENCHMARK_OS_FREEBSD 1
+ #define BENCHMARK_OS_FREEBSD 1
+#elif defined(__NetBSD__)
+ #define BENCHMARK_OS_NETBSD 1
+#elif defined(__OpenBSD__)
+ #define BENCHMARK_OS_OPENBSD 1
#elif defined(__linux__)
-#define BENCHMARK_OS_LINUX 1
+ #define BENCHMARK_OS_LINUX 1
#elif defined(__native_client__)
-#define BENCHMARK_OS_NACL 1
-#elif defined(EMSCRIPTEN)
-#define BENCHMARK_OS_EMSCRIPTEN 1
+ #define BENCHMARK_OS_NACL 1
+#elif defined(__EMSCRIPTEN__)
+ #define BENCHMARK_OS_EMSCRIPTEN 1
+#elif defined(__rtems__)
+ #define BENCHMARK_OS_RTEMS 1
+#elif defined(__Fuchsia__)
+#define BENCHMARK_OS_FUCHSIA 1
+#elif defined (__SVR4) && defined (__sun)
+#define BENCHMARK_OS_SOLARIS 1
+#endif
+
+#if defined(__ANDROID__) && defined(__GLIBCXX__)
+#define BENCHMARK_STL_ANDROID_GNUSTL 1
#endif
#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \
&& !defined(__EXCEPTIONS)
-#define BENCHMARK_HAS_NO_EXCEPTIONS
+ #define BENCHMARK_HAS_NO_EXCEPTIONS
#endif
+#if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
+ #define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
+#else
+ #define BENCHMARK_MAYBE_UNUSED
+#endif
+
+#if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable)
+ #define BENCHMARK_UNREACHABLE() __builtin_unreachable()
+#elif defined(COMPILER_MSVC)
+ #define BENCHMARK_UNREACHABLE() __assume(false)
+#else
+ #define BENCHMARK_UNREACHABLE() ((void)0)
+#endif
+
+// clang-format on
+
#endif // BENCHMARK_INTERNAL_MACROS_H_
diff --git a/lib/libcxx/utils/google-benchmark/src/json_reporter.cc b/lib/libcxx/utils/google-benchmark/src/json_reporter.cc
index 5a653088e5b..611605af6b5 100644
--- a/lib/libcxx/utils/google-benchmark/src/json_reporter.cc
+++ b/lib/libcxx/utils/google-benchmark/src/json_reporter.cc
@@ -12,12 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/reporter.h"
+#include "benchmark/benchmark.h"
#include "complexity.h"
#include <algorithm>
#include <cstdint>
+#include <iomanip> // for setprecision
#include <iostream>
+#include <limits>
#include <string>
#include <tuple>
#include <vector>
@@ -30,15 +32,15 @@ namespace benchmark {
namespace {
std::string FormatKV(std::string const& key, std::string const& value) {
- return StringPrintF("\"%s\": \"%s\"", key.c_str(), value.c_str());
+ return StrFormat("\"%s\": \"%s\"", key.c_str(), value.c_str());
}
std::string FormatKV(std::string const& key, const char* value) {
- return StringPrintF("\"%s\": \"%s\"", key.c_str(), value);
+ return StrFormat("\"%s\": \"%s\"", key.c_str(), value);
}
std::string FormatKV(std::string const& key, bool value) {
- return StringPrintF("\"%s\": %s", key.c_str(), value ? "true" : "false");
+ return StrFormat("\"%s\": %s", key.c_str(), value ? "true" : "false");
}
std::string FormatKV(std::string const& key, int64_t value) {
@@ -48,7 +50,14 @@ std::string FormatKV(std::string const& key, int64_t value) {
}
std::string FormatKV(std::string const& key, double value) {
- return StringPrintF("\"%s\": %.2f", key.c_str(), value);
+ std::stringstream ss;
+ ss << '"' << key << "\": ";
+
+ const auto max_digits10 = std::numeric_limits<decltype(value)>::max_digits10;
+ const auto max_fractional_digits10 = max_digits10 - 1;
+
+ ss << std::scientific << std::setprecision(max_fractional_digits10) << value;
+ return ss.str();
}
int64_t RoundDouble(double v) { return static_cast<int64_t>(v + 0.5); }
@@ -68,13 +77,41 @@ bool JSONReporter::ReportContext(const Context& context) {
std::string walltime_value = LocalDateTimeString();
out << indent << FormatKV("date", walltime_value) << ",\n";
- out << indent << FormatKV("num_cpus", static_cast<int64_t>(context.num_cpus))
+ if (Context::executable_name) {
+ out << indent << FormatKV("executable", Context::executable_name) << ",\n";
+ }
+
+ CPUInfo const& info = context.cpu_info;
+ out << indent << FormatKV("num_cpus", static_cast<int64_t>(info.num_cpus))
<< ",\n";
- out << indent << FormatKV("mhz_per_cpu", RoundDouble(context.mhz_per_cpu))
+ out << indent
+ << FormatKV("mhz_per_cpu",
+ RoundDouble(info.cycles_per_second / 1000000.0))
<< ",\n";
- out << indent << FormatKV("cpu_scaling_enabled", context.cpu_scaling_enabled)
+ out << indent << FormatKV("cpu_scaling_enabled", info.scaling_enabled)
<< ",\n";
+ out << indent << "\"caches\": [\n";
+ indent = std::string(6, ' ');
+ std::string cache_indent(8, ' ');
+ for (size_t i = 0; i < info.caches.size(); ++i) {
+ auto& CI = info.caches[i];
+ out << indent << "{\n";
+ out << cache_indent << FormatKV("type", CI.type) << ",\n";
+ out << cache_indent << FormatKV("level", static_cast<int64_t>(CI.level))
+ << ",\n";
+ out << cache_indent
+ << FormatKV("size", static_cast<int64_t>(CI.size) * 1000u) << ",\n";
+ out << cache_indent
+ << FormatKV("num_sharing", static_cast<int64_t>(CI.num_sharing))
+ << "\n";
+ out << indent << "}";
+ if (i != info.caches.size() - 1) out << ",";
+ out << "\n";
+ }
+ indent = std::string(4, ' ');
+ out << indent << "],\n";
+
#if defined(NDEBUG)
const char build_type[] = "release";
#else
@@ -124,40 +161,30 @@ void JSONReporter::PrintRunData(Run const& run) {
}
if (!run.report_big_o && !run.report_rms) {
out << indent << FormatKV("iterations", run.iterations) << ",\n";
- out << indent
- << FormatKV("real_time", RoundDouble(run.GetAdjustedRealTime()))
- << ",\n";
- out << indent
- << FormatKV("cpu_time", RoundDouble(run.GetAdjustedCPUTime()));
+ out << indent << FormatKV("real_time", run.GetAdjustedRealTime()) << ",\n";
+ out << indent << FormatKV("cpu_time", run.GetAdjustedCPUTime());
out << ",\n"
<< indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
} else if (run.report_big_o) {
- out << indent
- << FormatKV("cpu_coefficient", RoundDouble(run.GetAdjustedCPUTime()))
+ out << indent << FormatKV("cpu_coefficient", run.GetAdjustedCPUTime())
<< ",\n";
- out << indent
- << FormatKV("real_coefficient", RoundDouble(run.GetAdjustedRealTime()))
+ out << indent << FormatKV("real_coefficient", run.GetAdjustedRealTime())
<< ",\n";
out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n";
out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
} else if (run.report_rms) {
- out << indent
- << FormatKV("rms", run.GetAdjustedCPUTime());
+ out << indent << FormatKV("rms", run.GetAdjustedCPUTime());
}
if (run.bytes_per_second > 0.0) {
out << ",\n"
- << indent
- << FormatKV("bytes_per_second", RoundDouble(run.bytes_per_second));
+ << indent << FormatKV("bytes_per_second", run.bytes_per_second);
}
if (run.items_per_second > 0.0) {
out << ",\n"
- << indent
- << FormatKV("items_per_second", RoundDouble(run.items_per_second));
+ << indent << FormatKV("items_per_second", run.items_per_second);
}
- for(auto &c : run.counters) {
- out << ",\n"
- << indent
- << FormatKV(c.first, RoundDouble(c.second));
+ for (auto& c : run.counters) {
+ out << ",\n" << indent << FormatKV(c.first, c.second);
}
if (!run.report_label.empty()) {
out << ",\n" << indent << FormatKV("label", run.report_label);
@@ -165,4 +192,4 @@ void JSONReporter::PrintRunData(Run const& run) {
out << '\n';
}
-} // end namespace benchmark
+} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/log.h b/lib/libcxx/utils/google-benchmark/src/log.h
index 978cb0b4c8c..47d0c35c018 100644
--- a/lib/libcxx/utils/google-benchmark/src/log.h
+++ b/lib/libcxx/utils/google-benchmark/src/log.h
@@ -4,7 +4,7 @@
#include <iostream>
#include <ostream>
-#include "benchmark/macros.h"
+#include "benchmark/benchmark.h"
namespace benchmark {
namespace internal {
@@ -66,8 +66,9 @@ inline LogType& GetLogInstanceForLevel(int level) {
} // end namespace internal
} // end namespace benchmark
+// clang-format off
#define VLOG(x) \
(::benchmark::internal::GetLogInstanceForLevel(x) << "-- LOG(" << x << "):" \
" ")
-
-#endif \ No newline at end of file
+// clang-format on
+#endif
diff --git a/lib/libcxx/utils/google-benchmark/src/re.h b/lib/libcxx/utils/google-benchmark/src/re.h
index 01e9736505e..fbe25037b46 100644
--- a/lib/libcxx/utils/google-benchmark/src/re.h
+++ b/lib/libcxx/utils/google-benchmark/src/re.h
@@ -17,22 +17,39 @@
#include "internal_macros.h"
+// clang-format off
+
+#if !defined(HAVE_STD_REGEX) && \
+ !defined(HAVE_GNU_POSIX_REGEX) && \
+ !defined(HAVE_POSIX_REGEX)
+ // No explicit regex selection; detect based on builtin hints.
+ #if defined(BENCHMARK_OS_LINUX) || defined(BENCHMARK_OS_APPLE)
+ #define HAVE_POSIX_REGEX 1
+ #elif __cplusplus >= 199711L
+ #define HAVE_STD_REGEX 1
+ #endif
+#endif
+
// Prefer C regex libraries when compiling w/o exceptions so that we can
// correctly report errors.
-#if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && defined(HAVE_STD_REGEX) && \
+#if defined(BENCHMARK_HAS_NO_EXCEPTIONS) && \
+ defined(BENCHMARK_HAVE_STD_REGEX) && \
(defined(HAVE_GNU_POSIX_REGEX) || defined(HAVE_POSIX_REGEX))
-#undef HAVE_STD_REGEX
+ #undef HAVE_STD_REGEX
#endif
#if defined(HAVE_STD_REGEX)
-#include <regex>
+ #include <regex>
#elif defined(HAVE_GNU_POSIX_REGEX)
-#include <gnuregex.h>
+ #include <gnuregex.h>
#elif defined(HAVE_POSIX_REGEX)
-#include <regex.h>
+ #include <regex.h>
#else
#error No regular expression backend was found!
#endif
+
+// clang-format on
+
#include <string>
#include "check.h"
@@ -72,20 +89,21 @@ class Regex {
inline bool Regex::Init(const std::string& spec, std::string* error) {
#ifdef BENCHMARK_HAS_NO_EXCEPTIONS
- ((void)error); // suppress unused warning
+ ((void)error); // suppress unused warning
#else
try {
#endif
- re_ = std::regex(spec, std::regex_constants::extended);
- init_ = true;
+ re_ = std::regex(spec, std::regex_constants::extended);
+ init_ = true;
#ifndef BENCHMARK_HAS_NO_EXCEPTIONS
- } catch (const std::regex_error& e) {
- if (error) {
- *error = e.what();
- }
+}
+catch (const std::regex_error& e) {
+ if (error) {
+ *error = e.what();
}
+}
#endif
- return init_;
+return init_;
}
inline Regex::~Regex() {}
diff --git a/lib/libcxx/utils/google-benchmark/src/reporter.cc b/lib/libcxx/utils/google-benchmark/src/reporter.cc
index 64742426cd3..541661a25f0 100644
--- a/lib/libcxx/utils/google-benchmark/src/reporter.cc
+++ b/lib/libcxx/utils/google-benchmark/src/reporter.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/reporter.h"
+#include "benchmark/benchmark.h"
#include "timers.h"
#include <cstdlib>
@@ -22,7 +22,6 @@
#include <vector>
#include "check.h"
-#include "stat.h"
namespace benchmark {
@@ -31,17 +30,32 @@ BenchmarkReporter::BenchmarkReporter()
BenchmarkReporter::~BenchmarkReporter() {}
-void BenchmarkReporter::PrintBasicContext(std::ostream *out_ptr,
+void BenchmarkReporter::PrintBasicContext(std::ostream *out,
Context const &context) {
- CHECK(out_ptr) << "cannot be null";
- auto &Out = *out_ptr;
-
- Out << "Run on (" << context.num_cpus << " X " << context.mhz_per_cpu
- << " MHz CPU " << ((context.num_cpus > 1) ? "s" : "") << ")\n";
+ CHECK(out) << "cannot be null";
+ auto &Out = *out;
Out << LocalDateTimeString() << "\n";
- if (context.cpu_scaling_enabled) {
+ if (context.executable_name)
+ Out << "Running " << context.executable_name << "\n";
+
+ const CPUInfo &info = context.cpu_info;
+ Out << "Run on (" << info.num_cpus << " X "
+ << (info.cycles_per_second / 1000000.0) << " MHz CPU "
+ << ((info.num_cpus > 1) ? "s" : "") << ")\n";
+ if (info.caches.size() != 0) {
+ Out << "CPU Caches:\n";
+ for (auto &CInfo : info.caches) {
+ Out << " L" << CInfo.level << " " << CInfo.type << " "
+ << (CInfo.size / 1000) << "K";
+ if (CInfo.num_sharing != 0)
+ Out << " (x" << (info.num_cpus / CInfo.num_sharing) << ")";
+ Out << "\n";
+ }
+ }
+
+ if (info.scaling_enabled) {
Out << "***WARNING*** CPU scaling is enabled, the benchmark "
"real time measurements may be noisy and will incur extra "
"overhead.\n";
@@ -53,6 +67,11 @@ void BenchmarkReporter::PrintBasicContext(std::ostream *out_ptr,
#endif
}
+// No initializer because it's already initialized to NULL.
+const char *BenchmarkReporter::Context::executable_name;
+
+BenchmarkReporter::Context::Context() : cpu_info(CPUInfo::Get()) {}
+
double BenchmarkReporter::Run::GetAdjustedRealTime() const {
double new_time = real_accumulated_time * GetTimeUnitMultiplier(time_unit);
if (iterations != 0) new_time /= static_cast<double>(iterations);
diff --git a/lib/libcxx/utils/google-benchmark/src/statistics.cc b/lib/libcxx/utils/google-benchmark/src/statistics.cc
new file mode 100644
index 00000000000..612dda2d1a7
--- /dev/null
+++ b/lib/libcxx/utils/google-benchmark/src/statistics.cc
@@ -0,0 +1,177 @@
+// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
+// Copyright 2017 Roman Lebedev. 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 <algorithm>
+#include <cmath>
+#include <numeric>
+#include <string>
+#include <vector>
+#include "check.h"
+#include "statistics.h"
+
+namespace benchmark {
+
+auto StatisticsSum = [](const std::vector<double>& v) {
+ return std::accumulate(v.begin(), v.end(), 0.0);
+};
+
+double StatisticsMean(const std::vector<double>& v) {
+ if (v.empty()) return 0.0;
+ return StatisticsSum(v) * (1.0 / v.size());
+}
+
+double StatisticsMedian(const std::vector<double>& v) {
+ if (v.size() < 3) return StatisticsMean(v);
+ std::vector<double> copy(v);
+
+ auto center = copy.begin() + v.size() / 2;
+ std::nth_element(copy.begin(), center, copy.end());
+
+ // did we have an odd number of samples?
+ // if yes, then center is the median
+ // it no, then we are looking for the average between center and the value
+ // before
+ if (v.size() % 2 == 1) return *center;
+ auto center2 = copy.begin() + v.size() / 2 - 1;
+ std::nth_element(copy.begin(), center2, copy.end());
+ return (*center + *center2) / 2.0;
+}
+
+// Return the sum of the squares of this sample set
+auto SumSquares = [](const std::vector<double>& v) {
+ return std::inner_product(v.begin(), v.end(), v.begin(), 0.0);
+};
+
+auto Sqr = [](const double dat) { return dat * dat; };
+auto Sqrt = [](const double dat) {
+ // Avoid NaN due to imprecision in the calculations
+ if (dat < 0.0) return 0.0;
+ return std::sqrt(dat);
+};
+
+double StatisticsStdDev(const std::vector<double>& v) {
+ const auto mean = StatisticsMean(v);
+ if (v.empty()) return mean;
+
+ // Sample standard deviation is undefined for n = 1
+ if (v.size() == 1) return 0.0;
+
+ const double avg_squares = SumSquares(v) * (1.0 / v.size());
+ return Sqrt(v.size() / (v.size() - 1.0) * (avg_squares - Sqr(mean)));
+}
+
+std::vector<BenchmarkReporter::Run> ComputeStats(
+ const std::vector<BenchmarkReporter::Run>& reports) {
+ typedef BenchmarkReporter::Run Run;
+ std::vector<Run> results;
+
+ auto error_count =
+ std::count_if(reports.begin(), reports.end(),
+ [](Run const& run) { return run.error_occurred; });
+
+ if (reports.size() - error_count < 2) {
+ // We don't report aggregated data if there was a single run.
+ return results;
+ }
+
+ // Accumulators.
+ std::vector<double> real_accumulated_time_stat;
+ std::vector<double> cpu_accumulated_time_stat;
+ std::vector<double> bytes_per_second_stat;
+ std::vector<double> items_per_second_stat;
+
+ real_accumulated_time_stat.reserve(reports.size());
+ cpu_accumulated_time_stat.reserve(reports.size());
+ bytes_per_second_stat.reserve(reports.size());
+ items_per_second_stat.reserve(reports.size());
+
+ // All repetitions should be run with the same number of iterations so we
+ // can take this information from the first benchmark.
+ int64_t const run_iterations = reports.front().iterations;
+ // create stats for user counters
+ struct CounterStat {
+ Counter c;
+ std::vector<double> s;
+ };
+ std::map<std::string, CounterStat> counter_stats;
+ for (Run const& r : reports) {
+ for (auto const& cnt : r.counters) {
+ auto it = counter_stats.find(cnt.first);
+ if (it == counter_stats.end()) {
+ counter_stats.insert({cnt.first, {cnt.second, std::vector<double>{}}});
+ it = counter_stats.find(cnt.first);
+ it->second.s.reserve(reports.size());
+ } else {
+ CHECK_EQ(counter_stats[cnt.first].c.flags, cnt.second.flags);
+ }
+ }
+ }
+
+ // Populate the accumulators.
+ for (Run const& run : reports) {
+ CHECK_EQ(reports[0].benchmark_name, run.benchmark_name);
+ CHECK_EQ(run_iterations, run.iterations);
+ if (run.error_occurred) continue;
+ real_accumulated_time_stat.emplace_back(run.real_accumulated_time);
+ cpu_accumulated_time_stat.emplace_back(run.cpu_accumulated_time);
+ items_per_second_stat.emplace_back(run.items_per_second);
+ bytes_per_second_stat.emplace_back(run.bytes_per_second);
+ // user counters
+ for (auto const& cnt : run.counters) {
+ auto it = counter_stats.find(cnt.first);
+ CHECK_NE(it, counter_stats.end());
+ it->second.s.emplace_back(cnt.second);
+ }
+ }
+
+ // Only add label if it is same for all runs
+ std::string report_label = reports[0].report_label;
+ for (std::size_t i = 1; i < reports.size(); i++) {
+ if (reports[i].report_label != report_label) {
+ report_label = "";
+ break;
+ }
+ }
+
+ for (const auto& Stat : *reports[0].statistics) {
+ // Get the data from the accumulator to BenchmarkReporter::Run's.
+ Run data;
+ data.benchmark_name = reports[0].benchmark_name + "_" + Stat.name_;
+ data.report_label = report_label;
+ data.iterations = run_iterations;
+
+ data.real_accumulated_time = Stat.compute_(real_accumulated_time_stat);
+ data.cpu_accumulated_time = Stat.compute_(cpu_accumulated_time_stat);
+ data.bytes_per_second = Stat.compute_(bytes_per_second_stat);
+ data.items_per_second = Stat.compute_(items_per_second_stat);
+
+ data.time_unit = reports[0].time_unit;
+
+ // user counters
+ for (auto const& kv : counter_stats) {
+ const auto uc_stat = Stat.compute_(kv.second.s);
+ auto c = Counter(uc_stat, counter_stats[kv.first].c.flags);
+ data.counters[kv.first] = c;
+ }
+
+ results.push_back(data);
+ }
+
+ return results;
+}
+
+} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/statistics.h b/lib/libcxx/utils/google-benchmark/src/statistics.h
new file mode 100644
index 00000000000..7eccc85536a
--- /dev/null
+++ b/lib/libcxx/utils/google-benchmark/src/statistics.h
@@ -0,0 +1,37 @@
+// Copyright 2016 Ismael Jimenez Martinez. All rights reserved.
+// Copyright 2017 Roman Lebedev. 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.
+
+#ifndef STATISTICS_H_
+#define STATISTICS_H_
+
+#include <vector>
+
+#include "benchmark/benchmark.h"
+
+namespace benchmark {
+
+// Return a vector containing the mean, median and standard devation information
+// (and any user-specified info) for the specified list of reports. If 'reports'
+// contains less than two non-errored runs an empty vector is returned
+std::vector<BenchmarkReporter::Run> ComputeStats(
+ const std::vector<BenchmarkReporter::Run>& reports);
+
+double StatisticsMean(const std::vector<double>& v);
+double StatisticsMedian(const std::vector<double>& v);
+double StatisticsStdDev(const std::vector<double>& v);
+
+} // end namespace benchmark
+
+#endif // STATISTICS_H_
diff --git a/lib/libcxx/utils/google-benchmark/src/string_util.cc b/lib/libcxx/utils/google-benchmark/src/string_util.cc
index cd4e7cfde57..05ac5b4ea36 100644
--- a/lib/libcxx/utils/google-benchmark/src/string_util.cc
+++ b/lib/libcxx/utils/google-benchmark/src/string_util.cc
@@ -27,8 +27,6 @@ static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits),
static const int64_t kUnitsSize = arraysize(kBigSIUnits);
-} // end anonymous namespace
-
void ToExponentAndMantissa(double val, double thresh, int precision,
double one_k, std::string* mantissa,
int64_t* exponent) {
@@ -100,14 +98,16 @@ std::string ExponentToPrefix(int64_t exponent, bool iec) {
}
std::string ToBinaryStringFullySpecified(double value, double threshold,
- int precision) {
+ int precision, double one_k = 1024.0) {
std::string mantissa;
int64_t exponent;
- ToExponentAndMantissa(value, threshold, precision, 1024.0, &mantissa,
+ ToExponentAndMantissa(value, threshold, precision, one_k, &mantissa,
&exponent);
return mantissa + ExponentToPrefix(exponent, false);
}
+} // end namespace
+
void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
@@ -115,14 +115,14 @@ void AppendHumanReadable(int n, std::string* str) {
*str += ss.str();
}
-std::string HumanReadableNumber(double n) {
+std::string HumanReadableNumber(double n, double one_k) {
// 1.1 means that figures up to 1.1k should be shown with the next unit down;
// this softens edge effects.
// 1 means that we should show one decimal place of precision.
- return ToBinaryStringFullySpecified(n, 1.1, 1);
+ return ToBinaryStringFullySpecified(n, 1.1, 1, one_k);
}
-std::string StringPrintFImp(const char* msg, va_list args) {
+std::string StrFormatImp(const char* msg, va_list args) {
// we might need a second shot at this, so pre-emptivly make a copy
va_list args_cp;
va_copy(args_cp, args);
@@ -152,10 +152,10 @@ std::string StringPrintFImp(const char* msg, va_list args) {
return std::string(buff_ptr.get());
}
-std::string StringPrintF(const char* format, ...) {
+std::string StrFormat(const char* format, ...) {
va_list args;
va_start(args, format);
- std::string tmp = StringPrintFImp(format, args);
+ std::string tmp = StrFormatImp(format, args);
va_end(args);
return tmp;
}
@@ -169,4 +169,93 @@ void ReplaceAll(std::string* str, const std::string& from,
}
}
+#ifdef BENCHMARK_STL_ANDROID_GNUSTL
+/*
+ * GNU STL in Android NDK lacks support for some C++11 functions, including
+ * stoul, stoi, stod. We reimplement them here using C functions strtoul,
+ * strtol, strtod. Note that reimplemented functions are in benchmark::
+ * namespace, not std:: namespace.
+ */
+unsigned long stoul(const std::string& str, size_t* pos, int base) {
+ /* Record previous errno */
+ const int oldErrno = errno;
+ errno = 0;
+
+ const char* strStart = str.c_str();
+ char* strEnd = const_cast<char*>(strStart);
+ const unsigned long result = strtoul(strStart, &strEnd, base);
+
+ const int strtoulErrno = errno;
+ /* Restore previous errno */
+ errno = oldErrno;
+
+ /* Check for errors and return */
+ if (strtoulErrno == ERANGE) {
+ throw std::out_of_range(
+ "stoul failed: " + str + " is outside of range of unsigned long");
+ } else if (strEnd == strStart || strtoulErrno != 0) {
+ throw std::invalid_argument(
+ "stoul failed: " + str + " is not an integer");
+ }
+ if (pos != nullptr) {
+ *pos = static_cast<size_t>(strEnd - strStart);
+ }
+ return result;
+}
+
+int stoi(const std::string& str, size_t* pos, int base) {
+ /* Record previous errno */
+ const int oldErrno = errno;
+ errno = 0;
+
+ const char* strStart = str.c_str();
+ char* strEnd = const_cast<char*>(strStart);
+ const long result = strtol(strStart, &strEnd, base);
+
+ const int strtolErrno = errno;
+ /* Restore previous errno */
+ errno = oldErrno;
+
+ /* Check for errors and return */
+ if (strtolErrno == ERANGE || long(int(result)) != result) {
+ throw std::out_of_range(
+ "stoul failed: " + str + " is outside of range of int");
+ } else if (strEnd == strStart || strtolErrno != 0) {
+ throw std::invalid_argument(
+ "stoul failed: " + str + " is not an integer");
+ }
+ if (pos != nullptr) {
+ *pos = static_cast<size_t>(strEnd - strStart);
+ }
+ return int(result);
+}
+
+double stod(const std::string& str, size_t* pos) {
+ /* Record previous errno */
+ const int oldErrno = errno;
+ errno = 0;
+
+ const char* strStart = str.c_str();
+ char* strEnd = const_cast<char*>(strStart);
+ const double result = strtod(strStart, &strEnd);
+
+ /* Restore previous errno */
+ const int strtodErrno = errno;
+ errno = oldErrno;
+
+ /* Check for errors and return */
+ if (strtodErrno == ERANGE) {
+ throw std::out_of_range(
+ "stoul failed: " + str + " is outside of range of int");
+ } else if (strEnd == strStart || strtodErrno != 0) {
+ throw std::invalid_argument(
+ "stoul failed: " + str + " is not an integer");
+ }
+ if (pos != nullptr) {
+ *pos = static_cast<size_t>(strEnd - strStart);
+ }
+ return result;
+}
+#endif
+
} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/string_util.h b/lib/libcxx/utils/google-benchmark/src/string_util.h
index 0b190b91a16..4a5501273cf 100644
--- a/lib/libcxx/utils/google-benchmark/src/string_util.h
+++ b/lib/libcxx/utils/google-benchmark/src/string_util.h
@@ -10,31 +10,47 @@ namespace benchmark {
void AppendHumanReadable(int n, std::string* str);
-std::string HumanReadableNumber(double n);
+std::string HumanReadableNumber(double n, double one_k = 1024.0);
-std::string StringPrintF(const char* format, ...);
+std::string StrFormat(const char* format, ...);
-inline std::ostream& StringCatImp(std::ostream& out) BENCHMARK_NOEXCEPT {
+inline std::ostream& StrCatImp(std::ostream& out) BENCHMARK_NOEXCEPT {
return out;
}
template <class First, class... Rest>
-inline std::ostream& StringCatImp(std::ostream& out, First&& f,
- Rest&&... rest) {
+inline std::ostream& StrCatImp(std::ostream& out, First&& f, Rest&&... rest) {
out << std::forward<First>(f);
- return StringCatImp(out, std::forward<Rest>(rest)...);
+ return StrCatImp(out, std::forward<Rest>(rest)...);
}
template <class... Args>
inline std::string StrCat(Args&&... args) {
std::ostringstream ss;
- StringCatImp(ss, std::forward<Args>(args)...);
+ StrCatImp(ss, std::forward<Args>(args)...);
return ss.str();
}
void ReplaceAll(std::string* str, const std::string& from,
const std::string& to);
+#ifdef BENCHMARK_STL_ANDROID_GNUSTL
+/*
+ * GNU STL in Android NDK lacks support for some C++11 functions, including
+ * stoul, stoi, stod. We reimplement them here using C functions strtoul,
+ * strtol, strtod. Note that reimplemented functions are in benchmark::
+ * namespace, not std:: namespace.
+ */
+unsigned long stoul(const std::string& str, size_t* pos = nullptr,
+ int base = 10);
+int stoi(const std::string& str, size_t* pos = nullptr, int base = 10);
+double stod(const std::string& str, size_t* pos = nullptr);
+#else
+using std::stoul;
+using std::stoi;
+using std::stod;
+#endif
+
} // end namespace benchmark
#endif // BENCHMARK_STRING_UTIL_H_
diff --git a/lib/libcxx/utils/google-benchmark/src/sysinfo.cc b/lib/libcxx/utils/google-benchmark/src/sysinfo.cc
index 7feb79e65f2..73064b97ba2 100644
--- a/lib/libcxx/utils/google-benchmark/src/sysinfo.cc
+++ b/lib/libcxx/utils/google-benchmark/src/sysinfo.cc
@@ -12,34 +12,47 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "sysinfo.h"
#include "internal_macros.h"
#ifdef BENCHMARK_OS_WINDOWS
#include <Shlwapi.h>
+#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
#include <VersionHelpers.h>
#include <Windows.h>
#else
#include <fcntl.h>
+#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
+#endif
#include <sys/time.h>
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
#include <unistd.h>
-#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX
+#if defined BENCHMARK_OS_FREEBSD || defined BENCHMARK_OS_MACOSX || \
+ defined BENCHMARK_OS_NETBSD || defined BENCHMARK_OS_OPENBSD
+#define BENCHMARK_HAS_SYSCTL
#include <sys/sysctl.h>
#endif
#endif
+#if defined(BENCHMARK_OS_SOLARIS)
+#include <kstat.h>
+#endif
+#include <algorithm>
+#include <array>
+#include <bitset>
#include <cerrno>
+#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <fstream>
#include <iostream>
+#include <iterator>
#include <limits>
-#include <mutex>
+#include <memory>
+#include <sstream>
-#include "arraysize.h"
#include "check.h"
#include "cycleclock.h"
#include "internal_macros.h"
@@ -49,214 +62,466 @@
namespace benchmark {
namespace {
-std::once_flag cpuinfo_init;
-double cpuinfo_cycles_per_second = 1.0;
-int cpuinfo_num_cpus = 1; // Conservative guess
-#if !defined BENCHMARK_OS_MACOSX
-const int64_t estimate_time_ms = 1000;
+void PrintImp(std::ostream& out) { out << std::endl; }
-// Helper function estimates cycles/sec by observing cycles elapsed during
-// sleep(). Using small sleep time decreases accuracy significantly.
-int64_t EstimateCyclesPerSecond() {
- const int64_t start_ticks = cycleclock::Now();
- SleepForMilliseconds(estimate_time_ms);
- return cycleclock::Now() - start_ticks;
+template <class First, class... Rest>
+void PrintImp(std::ostream& out, First&& f, Rest&&... rest) {
+ out << std::forward<First>(f);
+ PrintImp(out, std::forward<Rest>(rest)...);
}
-#endif
-#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
-// Helper function for reading an int from a file. Returns true if successful
-// and the memory location pointed to by value is set to the value read.
-bool ReadIntFromFile(const char* file, long* value) {
- bool ret = false;
- int fd = open(file, O_RDONLY);
- if (fd != -1) {
- char line[1024];
- char* err;
- memset(line, '\0', sizeof(line));
- ssize_t read_err = read(fd, line, sizeof(line) - 1);
- ((void)read_err); // prevent unused warning
- CHECK(read_err >= 0);
- const long temp_value = strtol(line, &err, 10);
- if (line[0] != '\0' && (*err == '\n' || *err == '\0')) {
- *value = temp_value;
- ret = true;
+template <class... Args>
+BENCHMARK_NORETURN void PrintErrorAndDie(Args&&... args) {
+ PrintImp(std::cerr, std::forward<Args>(args)...);
+ std::exit(EXIT_FAILURE);
+}
+
+#ifdef BENCHMARK_HAS_SYSCTL
+
+/// ValueUnion - A type used to correctly alias the byte-for-byte output of
+/// `sysctl` with the result type it's to be interpreted as.
+struct ValueUnion {
+ union DataT {
+ uint32_t uint32_value;
+ uint64_t uint64_value;
+ // For correct aliasing of union members from bytes.
+ char bytes[8];
+ };
+ using DataPtr = std::unique_ptr<DataT, decltype(&std::free)>;
+
+ // The size of the data union member + its trailing array size.
+ size_t Size;
+ DataPtr Buff;
+
+ public:
+ ValueUnion() : Size(0), Buff(nullptr, &std::free) {}
+
+ explicit ValueUnion(size_t BuffSize)
+ : Size(sizeof(DataT) + BuffSize),
+ Buff(::new (std::malloc(Size)) DataT(), &std::free) {}
+
+ ValueUnion(ValueUnion&& other) = default;
+
+ explicit operator bool() const { return bool(Buff); }
+
+ char* data() const { return Buff->bytes; }
+
+ std::string GetAsString() const { return std::string(data()); }
+
+ int64_t GetAsInteger() const {
+ if (Size == sizeof(Buff->uint32_value))
+ return static_cast<int32_t>(Buff->uint32_value);
+ else if (Size == sizeof(Buff->uint64_value))
+ return static_cast<int64_t>(Buff->uint64_value);
+ BENCHMARK_UNREACHABLE();
+ }
+
+ uint64_t GetAsUnsigned() const {
+ if (Size == sizeof(Buff->uint32_value))
+ return Buff->uint32_value;
+ else if (Size == sizeof(Buff->uint64_value))
+ return Buff->uint64_value;
+ BENCHMARK_UNREACHABLE();
+ }
+
+ template <class T, int N>
+ std::array<T, N> GetAsArray() {
+ const int ArrSize = sizeof(T) * N;
+ CHECK_LE(ArrSize, Size);
+ std::array<T, N> Arr;
+ std::memcpy(Arr.data(), data(), ArrSize);
+ return Arr;
+ }
+};
+
+ValueUnion GetSysctlImp(std::string const& Name) {
+#if defined BENCHMARK_OS_OPENBSD
+ int mib[2];
+
+ mib[0] = CTL_HW;
+ if ((Name == "hw.ncpu") || (Name == "hw.cpuspeed")){
+ ValueUnion buff(sizeof(int));
+
+ if (Name == "hw.ncpu") {
+ mib[1] = HW_NCPU;
+ } else {
+ mib[1] = HW_CPUSPEED;
+ }
+
+ if (sysctl(mib, 2, buff.data(), &buff.Size, nullptr, 0) == -1) {
+ return ValueUnion();
}
- close(fd);
+ return buff;
}
- return ret;
+ return ValueUnion();
+#else
+ size_t CurBuffSize = 0;
+ if (sysctlbyname(Name.c_str(), nullptr, &CurBuffSize, nullptr, 0) == -1)
+ return ValueUnion();
+
+ ValueUnion buff(CurBuffSize);
+ if (sysctlbyname(Name.c_str(), buff.data(), &buff.Size, nullptr, 0) == 0)
+ return buff;
+ return ValueUnion();
+#endif
+}
+
+BENCHMARK_MAYBE_UNUSED
+bool GetSysctl(std::string const& Name, std::string* Out) {
+ Out->clear();
+ auto Buff = GetSysctlImp(Name);
+ if (!Buff) return false;
+ Out->assign(Buff.data());
+ return true;
+}
+
+template <class Tp,
+ class = typename std::enable_if<std::is_integral<Tp>::value>::type>
+bool GetSysctl(std::string const& Name, Tp* Out) {
+ *Out = 0;
+ auto Buff = GetSysctlImp(Name);
+ if (!Buff) return false;
+ *Out = static_cast<Tp>(Buff.GetAsUnsigned());
+ return true;
+}
+
+template <class Tp, size_t N>
+bool GetSysctl(std::string const& Name, std::array<Tp, N>* Out) {
+ auto Buff = GetSysctlImp(Name);
+ if (!Buff) return false;
+ *Out = Buff.GetAsArray<Tp, N>();
+ return true;
}
#endif
-#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
-static std::string convertToLowerCase(std::string s) {
- for (auto& ch : s)
- ch = std::tolower(ch);
- return s;
+template <class ArgT>
+bool ReadFromFile(std::string const& fname, ArgT* arg) {
+ *arg = ArgT();
+ std::ifstream f(fname.c_str());
+ if (!f.is_open()) return false;
+ f >> *arg;
+ return f.good();
+}
+
+bool CpuScalingEnabled(int num_cpus) {
+ // We don't have a valid CPU count, so don't even bother.
+ if (num_cpus <= 0) return false;
+#ifndef BENCHMARK_OS_WINDOWS
+ // On Linux, the CPUfreq subsystem exposes CPU information as files on the
+ // local file system. If reading the exported files fails, then we may not be
+ // running on Linux, so we silently ignore all the read errors.
+ std::string res;
+ for (int cpu = 0; cpu < num_cpus; ++cpu) {
+ std::string governor_file =
+ StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor");
+ if (ReadFromFile(governor_file, &res) && res != "performance") return true;
+ }
+#endif
+ return false;
}
-static bool startsWithKey(std::string Value, std::string Key,
- bool IgnoreCase = true) {
- if (IgnoreCase) {
- Key = convertToLowerCase(std::move(Key));
- Value = convertToLowerCase(std::move(Value));
+
+int CountSetBitsInCPUMap(std::string Val) {
+ auto CountBits = [](std::string Part) {
+ using CPUMask = std::bitset<sizeof(std::uintptr_t) * CHAR_BIT>;
+ Part = "0x" + Part;
+ CPUMask Mask(benchmark::stoul(Part, nullptr, 16));
+ return static_cast<int>(Mask.count());
+ };
+ size_t Pos;
+ int total = 0;
+ while ((Pos = Val.find(',')) != std::string::npos) {
+ total += CountBits(Val.substr(0, Pos));
+ Val = Val.substr(Pos + 1);
+ }
+ if (!Val.empty()) {
+ total += CountBits(Val);
+ }
+ return total;
+}
+
+BENCHMARK_MAYBE_UNUSED
+std::vector<CPUInfo::CacheInfo> GetCacheSizesFromKVFS() {
+ std::vector<CPUInfo::CacheInfo> res;
+ std::string dir = "/sys/devices/system/cpu/cpu0/cache/";
+ int Idx = 0;
+ while (true) {
+ CPUInfo::CacheInfo info;
+ std::string FPath = StrCat(dir, "index", Idx++, "/");
+ std::ifstream f(StrCat(FPath, "size").c_str());
+ if (!f.is_open()) break;
+ std::string suffix;
+ f >> info.size;
+ if (f.fail())
+ PrintErrorAndDie("Failed while reading file '", FPath, "size'");
+ if (f.good()) {
+ f >> suffix;
+ if (f.bad())
+ PrintErrorAndDie(
+ "Invalid cache size format: failed to read size suffix");
+ else if (f && suffix != "K")
+ PrintErrorAndDie("Invalid cache size format: Expected bytes ", suffix);
+ else if (suffix == "K")
+ info.size *= 1000;
+ }
+ if (!ReadFromFile(StrCat(FPath, "type"), &info.type))
+ PrintErrorAndDie("Failed to read from file ", FPath, "type");
+ if (!ReadFromFile(StrCat(FPath, "level"), &info.level))
+ PrintErrorAndDie("Failed to read from file ", FPath, "level");
+ std::string map_str;
+ if (!ReadFromFile(StrCat(FPath, "shared_cpu_map"), &map_str))
+ PrintErrorAndDie("Failed to read from file ", FPath, "shared_cpu_map");
+ info.num_sharing = CountSetBitsInCPUMap(map_str);
+ res.push_back(info);
+ }
+
+ return res;
+}
+
+#ifdef BENCHMARK_OS_MACOSX
+std::vector<CPUInfo::CacheInfo> GetCacheSizesMacOSX() {
+ std::vector<CPUInfo::CacheInfo> res;
+ std::array<uint64_t, 4> CacheCounts{{0, 0, 0, 0}};
+ GetSysctl("hw.cacheconfig", &CacheCounts);
+
+ struct {
+ std::string name;
+ std::string type;
+ int level;
+ size_t num_sharing;
+ } Cases[] = {{"hw.l1dcachesize", "Data", 1, CacheCounts[1]},
+ {"hw.l1icachesize", "Instruction", 1, CacheCounts[1]},
+ {"hw.l2cachesize", "Unified", 2, CacheCounts[2]},
+ {"hw.l3cachesize", "Unified", 3, CacheCounts[3]}};
+ for (auto& C : Cases) {
+ int val;
+ if (!GetSysctl(C.name, &val)) continue;
+ CPUInfo::CacheInfo info;
+ info.type = C.type;
+ info.level = C.level;
+ info.size = val;
+ info.num_sharing = static_cast<int>(C.num_sharing);
+ res.push_back(std::move(info));
+ }
+ return res;
+}
+#elif defined(BENCHMARK_OS_WINDOWS)
+std::vector<CPUInfo::CacheInfo> GetCacheSizesWindows() {
+ std::vector<CPUInfo::CacheInfo> res;
+ DWORD buffer_size = 0;
+ using PInfo = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
+ using CInfo = CACHE_DESCRIPTOR;
+
+ using UPtr = std::unique_ptr<PInfo, decltype(&std::free)>;
+ GetLogicalProcessorInformation(nullptr, &buffer_size);
+ UPtr buff((PInfo*)malloc(buffer_size), &std::free);
+ if (!GetLogicalProcessorInformation(buff.get(), &buffer_size))
+ PrintErrorAndDie("Failed during call to GetLogicalProcessorInformation: ",
+ GetLastError());
+
+ PInfo* it = buff.get();
+ PInfo* end = buff.get() + (buffer_size / sizeof(PInfo));
+
+ for (; it != end; ++it) {
+ if (it->Relationship != RelationCache) continue;
+ using BitSet = std::bitset<sizeof(ULONG_PTR) * CHAR_BIT>;
+ BitSet B(it->ProcessorMask);
+ // To prevent duplicates, only consider caches where CPU 0 is specified
+ if (!B.test(0)) continue;
+ CInfo* Cache = &it->Cache;
+ CPUInfo::CacheInfo C;
+ C.num_sharing = static_cast<int>(B.count());
+ C.level = Cache->Level;
+ C.size = Cache->Size;
+ switch (Cache->Type) {
+ case CacheUnified:
+ C.type = "Unified";
+ break;
+ case CacheInstruction:
+ C.type = "Instruction";
+ break;
+ case CacheData:
+ C.type = "Data";
+ break;
+ case CacheTrace:
+ C.type = "Trace";
+ break;
+ default:
+ C.type = "Unknown";
+ break;
+ }
+ res.push_back(C);
}
- return Value.compare(0, Key.size(), Key) == 0;
+ return res;
+}
+#endif
+
+std::vector<CPUInfo::CacheInfo> GetCacheSizes() {
+#ifdef BENCHMARK_OS_MACOSX
+ return GetCacheSizesMacOSX();
+#elif defined(BENCHMARK_OS_WINDOWS)
+ return GetCacheSizesWindows();
+#else
+ return GetCacheSizesFromKVFS();
+#endif
}
+
+int GetNumCPUs() {
+#ifdef BENCHMARK_HAS_SYSCTL
+ int NumCPU = -1;
+ if (GetSysctl("hw.ncpu", &NumCPU)) return NumCPU;
+ fprintf(stderr, "Err: %s\n", strerror(errno));
+ std::exit(EXIT_FAILURE);
+#elif defined(BENCHMARK_OS_WINDOWS)
+ SYSTEM_INFO sysinfo;
+ // Use memset as opposed to = {} to avoid GCC missing initializer false
+ // positives.
+ std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO));
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwNumberOfProcessors; // number of logical
+ // processors in the current
+ // group
+#elif defined(BENCHMARK_OS_SOLARIS)
+ // Returns -1 in case of a failure.
+ int NumCPU = sysconf(_SC_NPROCESSORS_ONLN);
+ if (NumCPU < 0) {
+ fprintf(stderr,
+ "sysconf(_SC_NPROCESSORS_ONLN) failed with error: %s\n",
+ strerror(errno));
+ }
+ return NumCPU;
+#else
+ int NumCPUs = 0;
+ int MaxID = -1;
+ std::ifstream f("/proc/cpuinfo");
+ if (!f.is_open()) {
+ std::cerr << "failed to open /proc/cpuinfo\n";
+ return -1;
+ }
+ const std::string Key = "processor";
+ std::string ln;
+ while (std::getline(f, ln)) {
+ if (ln.empty()) continue;
+ size_t SplitIdx = ln.find(':');
+ std::string value;
+ if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
+ if (ln.size() >= Key.size() && ln.compare(0, Key.size(), Key) == 0) {
+ NumCPUs++;
+ if (!value.empty()) {
+ int CurID = benchmark::stoi(value);
+ MaxID = std::max(CurID, MaxID);
+ }
+ }
+ }
+ if (f.bad()) {
+ std::cerr << "Failure reading /proc/cpuinfo\n";
+ return -1;
+ }
+ if (!f.eof()) {
+ std::cerr << "Failed to read to end of /proc/cpuinfo\n";
+ return -1;
+ }
+ f.close();
+
+ if ((MaxID + 1) != NumCPUs) {
+ fprintf(stderr,
+ "CPU ID assignments in /proc/cpuinfo seem messed up."
+ " This is usually caused by a bad BIOS.\n");
+ }
+ return NumCPUs;
#endif
+ BENCHMARK_UNREACHABLE();
+}
-void InitializeSystemInfo() {
+double GetCPUCyclesPerSecond() {
#if defined BENCHMARK_OS_LINUX || defined BENCHMARK_OS_CYGWIN
- char line[1024];
- char* err;
long freq;
- bool saw_mhz = false;
-
// If the kernel is exporting the tsc frequency use that. There are issues
// where cpuinfo_max_freq cannot be relied on because the BIOS may be
// exporintg an invalid p-state (on x86) or p-states may be used to put the
// processor in a new mode (turbo mode). Essentially, those frequencies
// cannot always be relied upon. The same reasons apply to /proc/cpuinfo as
// well.
- if (!saw_mhz &&
- ReadIntFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {
+ if (ReadFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)
+ // If CPU scaling is in effect, we want to use the *maximum* frequency,
+ // not whatever CPU speed some random processor happens to be using now.
+ || ReadFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
+ &freq)) {
// The value is in kHz (as the file name suggests). For example, on a
// 2GHz warpstation, the file contains the value "2000000".
- cpuinfo_cycles_per_second = freq * 1000.0;
- saw_mhz = true;
+ return freq * 1000.0;
}
- // If CPU scaling is in effect, we want to use the *maximum* frequency,
- // not whatever CPU speed some random processor happens to be using now.
- if (!saw_mhz &&
- ReadIntFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
- &freq)) {
- // The value is in kHz. For example, on a 2GHz warpstation, the file
- // contains the value "2000000".
- cpuinfo_cycles_per_second = freq * 1000.0;
- saw_mhz = true;
- }
+ const double error_value = -1;
+ double bogo_clock = error_value;
- // Read /proc/cpuinfo for other values, and if there is no cpuinfo_max_freq.
- const char* pname = "/proc/cpuinfo";
- int fd = open(pname, O_RDONLY);
- if (fd == -1) {
- perror(pname);
- if (!saw_mhz) {
- cpuinfo_cycles_per_second =
- static_cast<double>(EstimateCyclesPerSecond());
- }
- return;
+ std::ifstream f("/proc/cpuinfo");
+ if (!f.is_open()) {
+ std::cerr << "failed to open /proc/cpuinfo\n";
+ return error_value;
}
- double bogo_clock = 1.0;
- bool saw_bogo = false;
- long max_cpu_id = 0;
- int num_cpus = 0;
- line[0] = line[1] = '\0';
- size_t chars_read = 0;
- do { // we'll exit when the last read didn't read anything
- // Move the next line to the beginning of the buffer
- const size_t oldlinelen = strlen(line);
- if (sizeof(line) == oldlinelen + 1) // oldlinelen took up entire line
- line[0] = '\0';
- else // still other lines left to save
- memmove(line, line + oldlinelen + 1, sizeof(line) - (oldlinelen + 1));
- // Terminate the new line, reading more if we can't find the newline
- char* newline = strchr(line, '\n');
- if (newline == nullptr) {
- const size_t linelen = strlen(line);
- const size_t bytes_to_read = sizeof(line) - 1 - linelen;
- CHECK(bytes_to_read > 0); // because the memmove recovered >=1 bytes
- chars_read = read(fd, line + linelen, bytes_to_read);
- line[linelen + chars_read] = '\0';
- newline = strchr(line, '\n');
- }
- if (newline != nullptr) *newline = '\0';
+ auto startsWithKey = [](std::string const& Value, std::string const& Key) {
+ if (Key.size() > Value.size()) return false;
+ auto Cmp = [&](char X, char Y) {
+ return std::tolower(X) == std::tolower(Y);
+ };
+ return std::equal(Key.begin(), Key.end(), Value.begin(), Cmp);
+ };
+ std::string ln;
+ while (std::getline(f, ln)) {
+ if (ln.empty()) continue;
+ size_t SplitIdx = ln.find(':');
+ std::string value;
+ if (SplitIdx != std::string::npos) value = ln.substr(SplitIdx + 1);
// When parsing the "cpu MHz" and "bogomips" (fallback) entries, we only
- // accept postive values. Some environments (virtual machines) report zero,
+ // accept positive values. Some environments (virtual machines) report zero,
// which would cause infinite looping in WallTime_Init.
- if (!saw_mhz && startsWithKey(line, "cpu MHz")) {
- const char* freqstr = strchr(line, ':');
- if (freqstr) {
- cpuinfo_cycles_per_second = strtod(freqstr + 1, &err) * 1000000.0;
- if (freqstr[1] != '\0' && *err == '\0' && cpuinfo_cycles_per_second > 0)
- saw_mhz = true;
+ if (startsWithKey(ln, "cpu MHz")) {
+ if (!value.empty()) {
+ double cycles_per_second = benchmark::stod(value) * 1000000.0;
+ if (cycles_per_second > 0) return cycles_per_second;
}
- } else if (startsWithKey(line, "bogomips")) {
- const char* freqstr = strchr(line, ':');
- if (freqstr) {
- bogo_clock = strtod(freqstr + 1, &err) * 1000000.0;
- if (freqstr[1] != '\0' && *err == '\0' && bogo_clock > 0)
- saw_bogo = true;
- }
- } else if (startsWithKey(line, "processor", /*IgnoreCase*/false)) {
- // The above comparison is case-sensitive because ARM kernels often
- // include a "Processor" line that tells you about the CPU, distinct
- // from the usual "processor" lines that give you CPU ids. No current
- // Linux architecture is using "Processor" for CPU ids.
- num_cpus++; // count up every time we see an "processor :" entry
- const char* id_str = strchr(line, ':');
- if (id_str) {
- const long cpu_id = strtol(id_str + 1, &err, 10);
- if (id_str[1] != '\0' && *err == '\0' && max_cpu_id < cpu_id)
- max_cpu_id = cpu_id;
+ } else if (startsWithKey(ln, "bogomips")) {
+ if (!value.empty()) {
+ bogo_clock = benchmark::stod(value) * 1000000.0;
+ if (bogo_clock < 0.0) bogo_clock = error_value;
}
}
- } while (chars_read > 0);
- close(fd);
-
- if (!saw_mhz) {
- if (saw_bogo) {
- // If we didn't find anything better, we'll use bogomips, but
- // we're not happy about it.
- cpuinfo_cycles_per_second = bogo_clock;
- } else {
- // If we don't even have bogomips, we'll use the slow estimation.
- cpuinfo_cycles_per_second =
- static_cast<double>(EstimateCyclesPerSecond());
- }
}
- if (num_cpus == 0) {
- fprintf(stderr, "Failed to read num. CPUs correctly from /proc/cpuinfo\n");
- } else {
- if ((max_cpu_id + 1) != num_cpus) {
- fprintf(stderr,
- "CPU ID assignments in /proc/cpuinfo seem messed up."
- " This is usually caused by a bad BIOS.\n");
- }
- cpuinfo_num_cpus = num_cpus;
+ if (f.bad()) {
+ std::cerr << "Failure reading /proc/cpuinfo\n";
+ return error_value;
}
+ if (!f.eof()) {
+ std::cerr << "Failed to read to end of /proc/cpuinfo\n";
+ return error_value;
+ }
+ f.close();
+ // If we found the bogomips clock, but nothing better, we'll use it (but
+ // we're not happy about it); otherwise, fallback to the rough estimation
+ // below.
+ if (bogo_clock >= 0.0) return bogo_clock;
-#elif defined BENCHMARK_OS_FREEBSD
-// For this sysctl to work, the machine must be configured without
-// SMP, APIC, or APM support. hz should be 64-bit in freebsd 7.0
-// and later. Before that, it's a 32-bit quantity (and gives the
-// wrong answer on machines faster than 2^32 Hz). See
-// http://lists.freebsd.org/pipermail/freebsd-i386/2004-November/001846.html
-// But also compare FreeBSD 7.0:
-// http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG70#L223
-// 231 error = sysctl_handle_quad(oidp, &freq, 0, req);
-// To FreeBSD 6.3 (it's the same in 6-STABLE):
-// http://fxr.watson.org/fxr/source/i386/i386/tsc.c?v=RELENG6#L131
-// 139 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
-#if __FreeBSD__ >= 7
- uint64_t hz = 0;
+#elif defined BENCHMARK_HAS_SYSCTL
+ constexpr auto* FreqStr =
+#if defined(BENCHMARK_OS_FREEBSD) || defined(BENCHMARK_OS_NETBSD)
+ "machdep.tsc_freq";
+#elif defined BENCHMARK_OS_OPENBSD
+ "hw.cpuspeed";
#else
- unsigned int hz = 0;
+ "hw.cpufrequency";
#endif
- size_t sz = sizeof(hz);
- const char* sysctl_path = "machdep.tsc_freq";
- if (sysctlbyname(sysctl_path, &hz, &sz, nullptr, 0) != 0) {
- fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n",
- sysctl_path, strerror(errno));
- cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond());
- } else {
- cpuinfo_cycles_per_second = hz;
- }
-// TODO: also figure out cpuinfo_num_cpus
+ unsigned long long hz = 0;
+#if defined BENCHMARK_OS_OPENBSD
+ if (GetSysctl(FreqStr, &hz)) return hz * 1000000;
+#else
+ if (GetSysctl(FreqStr, &hz)) return hz;
+#endif
+ fprintf(stderr, "Unable to determine clock rate from sysctl: %s: %s\n",
+ FreqStr, strerror(errno));
#elif defined BENCHMARK_OS_WINDOWS
// In NT, read MHz from the registry. If we fail to do so or we're in win9x
@@ -267,89 +532,56 @@ void InitializeSystemInfo() {
SHGetValueA(HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
"~MHz", nullptr, &data, &data_size)))
- cpuinfo_cycles_per_second =
- static_cast<double>((int64_t)data * (int64_t)(1000 * 1000)); // was mhz
- else
- cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond());
-
- SYSTEM_INFO sysinfo;
- // Use memset as opposed to = {} to avoid GCC missing initializer false
- // positives.
- std::memset(&sysinfo, 0, sizeof(SYSTEM_INFO));
- GetSystemInfo(&sysinfo);
- cpuinfo_num_cpus = sysinfo.dwNumberOfProcessors; // number of logical
- // processors in the current
- // group
-
-#elif defined BENCHMARK_OS_MACOSX
- int32_t num_cpus = 0;
- size_t size = sizeof(num_cpus);
- if (::sysctlbyname("hw.ncpu", &num_cpus, &size, nullptr, 0) == 0 &&
- (size == sizeof(num_cpus))) {
- cpuinfo_num_cpus = num_cpus;
- } else {
- fprintf(stderr, "%s\n", strerror(errno));
- std::exit(EXIT_FAILURE);
+ return static_cast<double>((int64_t)data *
+ (int64_t)(1000 * 1000)); // was mhz
+#elif defined (BENCHMARK_OS_SOLARIS)
+ kstat_ctl_t *kc = kstat_open();
+ if (!kc) {
+ std::cerr << "failed to open /dev/kstat\n";
+ return -1;
}
- int64_t cpu_freq = 0;
- size = sizeof(cpu_freq);
- if (::sysctlbyname("hw.cpufrequency", &cpu_freq, &size, nullptr, 0) == 0 &&
- (size == sizeof(cpu_freq))) {
- cpuinfo_cycles_per_second = cpu_freq;
- } else {
- #if defined BENCHMARK_OS_IOS
- fprintf(stderr, "CPU frequency cannot be detected. \n");
- cpuinfo_cycles_per_second = 0;
- #else
- fprintf(stderr, "%s\n", strerror(errno));
- std::exit(EXIT_FAILURE);
- #endif
+ kstat_t *ksp = kstat_lookup(kc, (char*)"cpu_info", -1, (char*)"cpu_info0");
+ if (!ksp) {
+ std::cerr << "failed to lookup in /dev/kstat\n";
+ return -1;
}
-#else
- // Generic cycles per second counter
- cpuinfo_cycles_per_second = static_cast<double>(EstimateCyclesPerSecond());
+ if (kstat_read(kc, ksp, NULL) < 0) {
+ std::cerr << "failed to read from /dev/kstat\n";
+ return -1;
+ }
+ kstat_named_t *knp =
+ (kstat_named_t*)kstat_data_lookup(ksp, (char*)"current_clock_Hz");
+ if (!knp) {
+ std::cerr << "failed to lookup data in /dev/kstat\n";
+ return -1;
+ }
+ if (knp->data_type != KSTAT_DATA_UINT64) {
+ std::cerr << "current_clock_Hz is of unexpected data type: "
+ << knp->data_type << "\n";
+ return -1;
+ }
+ double clock_hz = knp->value.ui64;
+ kstat_close(kc);
+ return clock_hz;
#endif
+ // If we've fallen through, attempt to roughly estimate the CPU clock rate.
+ const int estimate_time_ms = 1000;
+ const auto start_ticks = cycleclock::Now();
+ SleepForMilliseconds(estimate_time_ms);
+ return static_cast<double>(cycleclock::Now() - start_ticks);
}
} // end namespace
-double CyclesPerSecond(void) {
- std::call_once(cpuinfo_init, InitializeSystemInfo);
- return cpuinfo_cycles_per_second;
-}
-
-int NumCPUs(void) {
- std::call_once(cpuinfo_init, InitializeSystemInfo);
- return cpuinfo_num_cpus;
+const CPUInfo& CPUInfo::Get() {
+ static const CPUInfo* info = new CPUInfo();
+ return *info;
}
-// The ""'s catch people who don't pass in a literal for "str"
-#define strliterallen(str) (sizeof("" str "") - 1)
-
-// Must use a string literal for prefix.
-#define memprefix(str, len, prefix) \
- ((((len) >= strliterallen(prefix)) && \
- std::memcmp(str, prefix, strliterallen(prefix)) == 0) \
- ? str + strliterallen(prefix) \
- : nullptr)
-
-bool CpuScalingEnabled() {
-#ifndef BENCHMARK_OS_WINDOWS
- // On Linux, the CPUfreq subsystem exposes CPU information as files on the
- // local file system. If reading the exported files fails, then we may not be
- // running on Linux, so we silently ignore all the read errors.
- for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) {
- std::string governor_file =
- StrCat("/sys/devices/system/cpu/cpu", cpu, "/cpufreq/scaling_governor");
- FILE* file = fopen(governor_file.c_str(), "r");
- if (!file) break;
- char buff[16];
- size_t bytes_read = fread(buff, 1, sizeof(buff), file);
- fclose(file);
- if (memprefix(buff, bytes_read, "performance") == nullptr) return true;
- }
-#endif
- return false;
-}
+CPUInfo::CPUInfo()
+ : num_cpus(GetNumCPUs()),
+ cycles_per_second(GetCPUCyclesPerSecond()),
+ caches(GetCacheSizes()),
+ scaling_enabled(CpuScalingEnabled(num_cpus)) {}
} // end namespace benchmark
diff --git a/lib/libcxx/utils/google-benchmark/src/thread_manager.h b/lib/libcxx/utils/google-benchmark/src/thread_manager.h
new file mode 100644
index 00000000000..82b4d72b62f
--- /dev/null
+++ b/lib/libcxx/utils/google-benchmark/src/thread_manager.h
@@ -0,0 +1,66 @@
+#ifndef BENCHMARK_THREAD_MANAGER_H
+#define BENCHMARK_THREAD_MANAGER_H
+
+#include <atomic>
+
+#include "benchmark/benchmark.h"
+#include "mutex.h"
+
+namespace benchmark {
+namespace internal {
+
+class ThreadManager {
+ public:
+ ThreadManager(int num_threads)
+ : alive_threads_(num_threads), start_stop_barrier_(num_threads) {}
+
+ Mutex& GetBenchmarkMutex() const RETURN_CAPABILITY(benchmark_mutex_) {
+ return benchmark_mutex_;
+ }
+
+ bool StartStopBarrier() EXCLUDES(end_cond_mutex_) {
+ return start_stop_barrier_.wait();
+ }
+
+ void NotifyThreadComplete() EXCLUDES(end_cond_mutex_) {
+ start_stop_barrier_.removeThread();
+ if (--alive_threads_ == 0) {
+ MutexLock lock(end_cond_mutex_);
+ end_condition_.notify_all();
+ }
+ }
+
+ void WaitForAllThreads() EXCLUDES(end_cond_mutex_) {
+ MutexLock lock(end_cond_mutex_);
+ end_condition_.wait(lock.native_handle(),
+ [this]() { return alive_threads_ == 0; });
+ }
+
+ public:
+ struct Result {
+ int64_t iterations = 0;
+ double real_time_used = 0;
+ double cpu_time_used = 0;
+ double manual_time_used = 0;
+ int64_t bytes_processed = 0;
+ int64_t items_processed = 0;
+ int64_t complexity_n = 0;
+ std::string report_label_;
+ std::string error_message_;
+ bool has_error_ = false;
+ UserCounters counters;
+ };
+ GUARDED_BY(GetBenchmarkMutex()) Result results;
+
+ private:
+ mutable Mutex benchmark_mutex_;
+ std::atomic<int> alive_threads_;
+ Barrier start_stop_barrier_;
+ Mutex end_cond_mutex_;
+ Condition end_condition_;
+};
+
+} // namespace internal
+} // namespace benchmark
+
+#endif // BENCHMARK_THREAD_MANAGER_H
diff --git a/lib/libcxx/utils/google-benchmark/src/thread_timer.h b/lib/libcxx/utils/google-benchmark/src/thread_timer.h
new file mode 100644
index 00000000000..eaf108e017d
--- /dev/null
+++ b/lib/libcxx/utils/google-benchmark/src/thread_timer.h
@@ -0,0 +1,69 @@
+#ifndef BENCHMARK_THREAD_TIMER_H
+#define BENCHMARK_THREAD_TIMER_H
+
+#include "check.h"
+#include "timers.h"
+
+namespace benchmark {
+namespace internal {
+
+class ThreadTimer {
+ public:
+ ThreadTimer() = default;
+
+ // Called by each thread
+ void StartTimer() {
+ running_ = true;
+ start_real_time_ = ChronoClockNow();
+ start_cpu_time_ = ThreadCPUUsage();
+ }
+
+ // Called by each thread
+ void StopTimer() {
+ CHECK(running_);
+ running_ = false;
+ real_time_used_ += ChronoClockNow() - start_real_time_;
+ // Floating point error can result in the subtraction producing a negative
+ // time. Guard against that.
+ cpu_time_used_ += std::max<double>(ThreadCPUUsage() - start_cpu_time_, 0);
+ }
+
+ // Called by each thread
+ void SetIterationTime(double seconds) { manual_time_used_ += seconds; }
+
+ bool running() const { return running_; }
+
+ // REQUIRES: timer is not running
+ double real_time_used() {
+ CHECK(!running_);
+ return real_time_used_;
+ }
+
+ // REQUIRES: timer is not running
+ double cpu_time_used() {
+ CHECK(!running_);
+ return cpu_time_used_;
+ }
+
+ // REQUIRES: timer is not running
+ double manual_time_used() {
+ CHECK(!running_);
+ return manual_time_used_;
+ }
+
+ private:
+ bool running_ = false; // Is the timer running
+ double start_real_time_ = 0; // If running_
+ double start_cpu_time_ = 0; // If running_
+
+ // Accumulated time so far (does not contain current slice if running_)
+ double real_time_used_ = 0;
+ double cpu_time_used_ = 0;
+ // Manually set iteration time. User sets this with SetIterationTime(seconds).
+ double manual_time_used_ = 0;
+};
+
+} // namespace internal
+} // namespace benchmark
+
+#endif // BENCHMARK_THREAD_TIMER_H
diff --git a/lib/libcxx/utils/google-benchmark/src/timers.cc b/lib/libcxx/utils/google-benchmark/src/timers.cc
index 8d56e8adf8d..2010e2450b4 100644
--- a/lib/libcxx/utils/google-benchmark/src/timers.cc
+++ b/lib/libcxx/utils/google-benchmark/src/timers.cc
@@ -17,11 +17,14 @@
#ifdef BENCHMARK_OS_WINDOWS
#include <Shlwapi.h>
+#undef StrCat // Don't let StrCat in string_util.h be renamed to lstrcatA
#include <VersionHelpers.h>
#include <Windows.h>
#else
#include <fcntl.h>
+#ifndef BENCHMARK_OS_FUCHSIA
#include <sys/resource.h>
+#endif
#include <sys/time.h>
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
#include <unistd.h>
@@ -74,7 +77,7 @@ double MakeTime(FILETIME const& kernel_time, FILETIME const& user_time) {
static_cast<double>(user.QuadPart)) *
1e-7;
}
-#else
+#elif !defined(BENCHMARK_OS_FUCHSIA)
double MakeTime(struct rusage const& ru) {
return (static_cast<double>(ru.ru_utime.tv_sec) +
static_cast<double>(ru.ru_utime.tv_usec) * 1e-6 +
@@ -158,6 +161,14 @@ double ThreadCPUUsage() {
#elif defined(BENCHMARK_OS_EMSCRIPTEN)
// Emscripten doesn't support traditional threads
return ProcessCPUUsage();
+#elif defined(BENCHMARK_OS_RTEMS)
+ // RTEMS doesn't support CLOCK_THREAD_CPUTIME_ID. See
+ // https://github.com/RTEMS/rtems/blob/master/cpukit/posix/src/clockgettime.c
+ return ProcessCPUUsage();
+#elif defined(BENCHMARK_OS_SOLARIS)
+ struct rusage ru;
+ if (getrusage(RUSAGE_LWP, &ru) == 0) return MakeTime(ru);
+ DiagnoseAndExit("getrusage(RUSAGE_LWP, ...) failed");
#elif defined(CLOCK_THREAD_CPUTIME_ID)
struct timespec ts;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0) return MakeTime(ts);
@@ -182,7 +193,6 @@ std::string DateTimeString(bool local) {
std::strftime(storage, sizeof(storage), "%x %X", ::localtime(&now));
#else
std::tm timeinfo;
- std::memset(&timeinfo, 0, sizeof(std::tm));
::localtime_r(&now, &timeinfo);
written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
#endif
@@ -191,7 +201,6 @@ std::string DateTimeString(bool local) {
written = std::strftime(storage, sizeof(storage), "%x %X", ::gmtime(&now));
#else
std::tm timeinfo;
- std::memset(&timeinfo, 0, sizeof(std::tm));
::gmtime_r(&now, &timeinfo);
written = std::strftime(storage, sizeof(storage), "%F %T", &timeinfo);
#endif