diff options
Diffstat (limited to 'benchmarks')
-rw-r--r-- | benchmarks/Android.mk | 59 | ||||
-rw-r--r-- | benchmarks/Benchmark.cpp | 154 | ||||
-rw-r--r-- | benchmarks/benchmark/Benchmark.h | 154 | ||||
-rw-r--r-- | benchmarks/benchmark_main.cpp | 266 | ||||
-rw-r--r-- | benchmarks/include/benchmark.h | 65 | ||||
-rw-r--r-- | benchmarks/main.cpp | 61 | ||||
-rw-r--r-- | benchmarks/math_benchmark.cpp | 121 | ||||
-rw-r--r-- | benchmarks/property_benchmark.cpp | 316 | ||||
-rw-r--r-- | benchmarks/pthread_benchmark.cpp | 74 | ||||
-rw-r--r-- | benchmarks/semaphore_benchmark.cpp | 114 | ||||
-rw-r--r-- | benchmarks/stdio_benchmark.cpp | 50 | ||||
-rw-r--r-- | benchmarks/string_benchmark.cpp | 35 | ||||
-rw-r--r-- | benchmarks/time_benchmark.cpp | 25 | ||||
-rw-r--r-- | benchmarks/unistd_benchmark.cpp | 20 | ||||
-rw-r--r-- | benchmarks/utils.cpp | 81 | ||||
-rw-r--r-- | benchmarks/utils.h | 26 |
16 files changed, 806 insertions, 815 deletions
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk index c3eb6d3..ae0541f 100644 --- a/benchmarks/Android.mk +++ b/benchmarks/Android.mk @@ -20,12 +20,29 @@ LOCAL_PATH := $(call my-dir) # Benchmarks library, usable by projects outside this directory. # ----------------------------------------------------------------------------- +benchmark_cflags := \ + -O2 \ + -fno-builtin \ + -Wall \ + -Wextra \ + -Werror \ + -Wunused \ + +benchmark_cppflags := \ + -std=gnu++11 \ + +benchmarklib_src_files := \ + Benchmark.cpp \ + utils.cpp \ + main.cpp \ + include $(CLEAR_VARS) LOCAL_MODULE := libbenchmark -LOCAL_CFLAGS += -O2 -Wall -Wextra -Werror -LOCAL_SRC_FILES := benchmark_main.cpp -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_CFLAGS := $(benchmark_cflags) +LOCAL_CPPFLAGS := $(benchmark_cppflags) +LOCAL_SRC_FILES := $(benchmarklib_src_files) +LOCAL_C_INCLUDES := $(benchmark_c_includes) +LOCAL_STATIC_LIBRARIES := libutils include $(BUILD_STATIC_LIBRARY) # Only supported on linux systems. @@ -33,11 +50,12 @@ ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) LOCAL_MODULE := libbenchmark -LOCAL_CFLAGS += -O2 -Wall -Wextra -Werror -LOCAL_SRC_FILES := benchmark_main.cpp -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include -LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_CFLAGS := $(benchmark_cflags) +LOCAL_CPPFLAGS := $(benchmark_cppflags) +LOCAL_SRC_FILES := $(benchmarklib_src_files) +LOCAL_C_INCLUDES := $(benchmark_c_includes) LOCAL_MULTILIB := both +LOCAL_STATIC_LIBRARIES := libutils include $(BUILD_HOST_STATIC_LIBRARY) endif @@ -45,16 +63,9 @@ endif # ----------------------------------------------------------------------------- # Benchmarks. # ----------------------------------------------------------------------------- - -benchmark_c_flags = \ - -O2 \ - -Wall -Wextra -Wunused \ - -Werror \ - -fno-builtin \ - -std=gnu++11 \ - -benchmark_src_files = \ +benchmark_src_files := \ math_benchmark.cpp \ + property_benchmark.cpp \ pthread_benchmark.cpp \ semaphore_benchmark.cpp \ stdio_benchmark.cpp \ @@ -70,9 +81,10 @@ LOCAL_MODULE := bionic-benchmarks LOCAL_MODULE_STEM_32 := bionic-benchmarks32 LOCAL_MODULE_STEM_64 := bionic-benchmarks64 LOCAL_MULTILIB := both -LOCAL_CFLAGS += $(benchmark_c_flags) -LOCAL_SRC_FILES := $(benchmark_src_files) property_benchmark.cpp -LOCAL_STATIC_LIBRARIES += libbenchmark +LOCAL_CFLAGS := $(benchmark_cflags) +LOCAL_CPPFLAGS := $(benchmark_cppflags) +LOCAL_SRC_FILES := $(benchmark_src_files) +LOCAL_STATIC_LIBRARIES := libbenchmark libutils include $(BUILD_EXECUTABLE) # We don't build a static benchmark executable because it's not usually @@ -90,10 +102,11 @@ LOCAL_MODULE := bionic-benchmarks-glibc LOCAL_MODULE_STEM_32 := bionic-benchmarks-glibc32 LOCAL_MODULE_STEM_64 := bionic-benchmarks-glibc64 LOCAL_MULTILIB := both -LOCAL_CFLAGS += $(benchmark_c_flags) -LOCAL_LDFLAGS += -lrt +LOCAL_CFLAGS := $(benchmark_cflags) +LOCAL_CPPFLAGS := $(benchmark_cppflags) +LOCAL_LDFLAGS := -lrt LOCAL_SRC_FILES := $(benchmark_src_files) -LOCAL_STATIC_LIBRARIES += libbenchmark +LOCAL_STATIC_LIBRARIES := libbenchmark libutils include $(BUILD_HOST_EXECUTABLE) endif diff --git a/benchmarks/Benchmark.cpp b/benchmarks/Benchmark.cpp new file mode 100644 index 0000000..0eb779a --- /dev/null +++ b/benchmarks/Benchmark.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 <inttypes.h> +#include <regex.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> + +#include <string> +#include <vector> + +#include <utils/stringprintf.h> + +#include <benchmark/Benchmark.h> + +#include "utils.h" + +namespace testing { + +static uint64_t NanoTime() { + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &t); + return static_cast<uint64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec; +} + +std::vector<Benchmark*>& Benchmark::List() { + static std::vector<Benchmark*> list; + return list; +} + +size_t Benchmark::MaxNameColumnWidth() { + size_t max = 20; + for (auto& benchmark : List()) { + max = std::max(max, benchmark->NameColumnWidth()); + } + return max; +} + +bool Benchmark::RunAll(std::vector<regex_t*>& regs) { + bool ran_benchmark = false; + for (auto& benchmark : List()) { + if (benchmark->ShouldRun(regs)) { + if (!ran_benchmark) { + printf("%-*s %10s %10s\n", MaxNameColumnWidth(), "", "iterations", "ns/op"); + ran_benchmark = true; + } + benchmark->RunAll(); + } + } + return ran_benchmark; +} + +bool Benchmark::ShouldRun(std::vector<regex_t*>& regs) { + if (regs.empty()) { + return true; + } + + for (const auto& re : regs) { + if (regexec(re, Name().c_str(), 0, NULL, 0) != REG_NOMATCH) { + return true; + } + } + return false; +} + +void Benchmark::StopBenchmarkTiming() { + if (start_time_ns_ != 0) { + total_time_ns_ += NanoTime() - start_time_ns_; + } + start_time_ns_ = 0; +} + +void Benchmark::StartBenchmarkTiming() { + if (start_time_ns_ == 0) { + start_time_ns_ = NanoTime(); + } +} + +std::string BenchmarkWithoutArg::GetNameStr(void*) { + return Name(); +} + +template <> +std::string BenchmarkWithArg<int>::GetNameStr(int arg) { + return Name() + "/" + PrettyInt(arg, 2); +} + +template <> +std::string BenchmarkWithArg<double>::GetNameStr(double arg) { + return Name() + "/" + android::StringPrintf("%0.6f", arg); +} + +template<typename T> +void BenchmarkT<T>::RunWithArg(T arg) { + int new_iterations = 1; + int iterations; + while (new_iterations < 1e8) { + bytes_processed_ = 0; + total_time_ns_ = 0; + start_time_ns_ = 0; + + iterations = new_iterations; + RunIterations(iterations, arg); + if (total_time_ns_ >= 1e9) { + break; + } + + if (total_time_ns_/iterations == 0) { + new_iterations = 1e9; + } else { + new_iterations = 1e9/ (total_time_ns_/iterations); + } + new_iterations = std::max(iterations + 1, + std::min(new_iterations + new_iterations/2, 100*iterations)); + + new_iterations = Round(new_iterations); + } + + printf("%-*s %10s %10" PRId64, MaxNameColumnWidth(), GetNameStr(arg).c_str(), + PrettyInt(iterations, 10).c_str(), total_time_ns_/iterations); + + if (total_time_ns_ > 0 && bytes_processed_ > 0) { + double gib_processed = static_cast<double>(bytes_processed_)/1e9; + double seconds = static_cast<double>(total_time_ns_)/1e9; + printf(" %8.3f GiB/s", gib_processed/seconds); + } + printf("\n"); + fflush(stdout); +} + +template class BenchmarkT<int>; +template class BenchmarkT<double>; +template class BenchmarkT<void*>; + +template class BenchmarkWithArg<int>; +template class BenchmarkWithArg<double>; + +} // namespace testing diff --git a/benchmarks/benchmark/Benchmark.h b/benchmarks/benchmark/Benchmark.h new file mode 100644 index 0000000..7c208e6 --- /dev/null +++ b/benchmarks/benchmark/Benchmark.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 BENCHMARKS_BENCHMARK_H_ +#define BENCHMARKS_BENCHMARK_H_ + +#include <regex.h> +#include <stdint.h> + +#include <string> +#include <vector> + +namespace testing { + +class Benchmark { +public: + Benchmark() { + List().push_back(this); + } + virtual ~Benchmark() {} + + virtual std::string Name() = 0; + + virtual void RunAll() = 0; + + bool ShouldRun(std::vector<regex_t*>&); + + void SetBenchmarkBytesProcessed(uint64_t bytes) { bytes_processed_ += bytes; } + void StopBenchmarkTiming(); + void StartBenchmarkTiming(); + + // Run all of the benchmarks that have registered. + static bool RunAll(std::vector<regex_t*>&); + + static std::vector<Benchmark*>& List(); + + static size_t MaxNameColumnWidth(); + +protected: + virtual size_t NameColumnWidth() = 0; + + uint64_t bytes_processed_; + uint64_t total_time_ns_; + uint64_t start_time_ns_; +}; + +template <typename T> +class BenchmarkT : public Benchmark { +public: + BenchmarkT() {} + virtual ~BenchmarkT() {} + +protected: + void RunWithArg(T arg); + virtual void RunIterations(int, T) = 0; + virtual std::string GetNameStr(T) = 0; +}; + +class BenchmarkWithoutArg : public BenchmarkT<void*> { +public: + BenchmarkWithoutArg() {} + virtual ~BenchmarkWithoutArg() {} + +protected: + virtual void RunAll() override { + RunWithArg(nullptr); + } + + virtual void RunIterations(int iters, void*) override { + Run(iters); + } + + virtual void Run(int) = 0; + + virtual size_t NameColumnWidth() override { + return Name().size(); + } + + virtual std::string GetNameStr(void *) override; +}; + +template<typename T> +class BenchmarkWithArg : public BenchmarkT<T> { +public: + BenchmarkWithArg() {} + virtual ~BenchmarkWithArg() {} + + BenchmarkWithArg* Arg(T arg) { + args_.push_back(arg); + return this; + } + +protected: + virtual size_t NameColumnWidth() override { + size_t max = 0; + for (const auto arg : args_) { + max = std::max(max, GetNameStr(arg).size()); + } + return max; + } + + std::string GetNameStr(T arg) override; + + virtual void RunAll() override { + for (T arg : args_) { + BenchmarkT<T>::RunWithArg(arg); + } + } + + virtual void RunIterations(int iters, T arg) override { + Run(iters, arg); + } + + virtual void Run(int iters, T arg) = 0; + +private: + std::vector<T> args_; +}; + +} // namespace testing + +#define BENCHMARK_START(f, super_class) \ + class f : public super_class { \ + public: \ + f() {} \ + virtual ~f() {} \ + virtual std::string Name() override { return #f; } \ + +#define BENCHMARK_NO_ARG(f) \ + BENCHMARK_START(f, ::testing::BenchmarkWithoutArg) \ + virtual void Run(int) override; \ + }; \ + static ::testing::Benchmark* __benchmark_##f = new f() + +#define BENCHMARK_WITH_ARG(f, arg_type) \ + BENCHMARK_START(f, ::testing::BenchmarkWithArg<arg_type>) \ + virtual void Run(int, arg_type) override; \ + }; \ + static ::testing::BenchmarkWithArg<arg_type>* __benchmark_##f = (new f()) + +#endif // BENCHMARKS_BENCHMARK_H_ diff --git a/benchmarks/benchmark_main.cpp b/benchmarks/benchmark_main.cpp deleted file mode 100644 index fae09be..0000000 --- a/benchmarks/benchmark_main.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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.h> - -#include <regex.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -#include <string> -#include <vector> - -#include <inttypes.h> - -static int64_t g_bytes_processed; -static int64_t g_benchmark_total_time_ns; -static int64_t g_benchmark_start_time_ns; -static int g_name_column_width = 20; - -typedef std::vector<::testing::Benchmark*> BenchmarkList; - -static BenchmarkList& Benchmarks() { - static BenchmarkList benchmarks; - return benchmarks; -} - -// Similar to the code in art, but supporting both binary and decimal prefixes. -static std::string PrettyInt(uint64_t count, size_t base) { - if (base != 2 && base != 10) abort(); - - // The byte thresholds at which we display amounts. A count is displayed - // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1]. - static const uint64_t kUnitThresholds2[] = { - 1024*1024*1024 /* Gi */, 2*1024*1024 /* Mi */, 3*1024 /* Ki */, 0, - }; - static const uint64_t kUnitThresholds10[] = { - 1000*1000*1000 /* G */, 2*1000*1000 /* M */, 3*1000 /* k */, 0, - }; - static const uint64_t kAmountPerUnit2[] = { 1024*1024*1024, 1024*1024, 1024, 1 }; - static const uint64_t kAmountPerUnit10[] = { 1000*1000*1000, 1000*1000, 1000, 1 }; - static const char* const kUnitStrings2[] = { "Gi", "Mi", "Ki", "" }; - static const char* const kUnitStrings10[] = { "G", "M", "k", "" }; - - // Which set are we using? - const uint64_t* kUnitThresholds = ((base == 2) ? kUnitThresholds2 : kUnitThresholds10); - const uint64_t* kAmountPerUnit = ((base == 2) ? kAmountPerUnit2 : kAmountPerUnit10); - const char* const* kUnitStrings = ((base == 2) ? kUnitStrings2 : kUnitStrings10); - - size_t i = 0; - for (; kUnitThresholds[i] != 0; ++i) { - if (count >= kUnitThresholds[i]) { - break; - } - } - char* s = NULL; - asprintf(&s, "%" PRId64 "%s", count / kAmountPerUnit[i], kUnitStrings[i]); - std::string result(s); - free(s); - return result; -} - -static int Round(int n) { - int base = 1; - while (base*10 < n) { - base *= 10; - } - if (n < 2*base) { - return 2*base; - } - if (n < 5*base) { - return 5*base; - } - return 10*base; -} - -static int64_t NanoTime() { - struct timespec t; - t.tv_sec = t.tv_nsec = 0; - clock_gettime(CLOCK_MONOTONIC, &t); - return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec; -} - -namespace testing { - -Benchmark* Benchmark::Arg(int arg) { - args_.push_back(arg); - return this; -} - -const char* Benchmark::Name() { - return name_; -} - -bool Benchmark::ShouldRun(int argc, char* argv[]) { - if (argc == 1) { - return true; // With no arguments, we run all benchmarks. - } - // Otherwise, we interpret each argument as a regular expression and - // see if any of our benchmarks match. - for (int i = 1; i < argc; i++) { - regex_t re; - if (regcomp(&re, argv[i], 0) != 0) { - fprintf(stderr, "couldn't compile \"%s\" as a regular expression!\n", argv[i]); - exit(EXIT_FAILURE); - } - int match = regexec(&re, name_, 0, NULL, 0); - regfree(&re); - if (match != REG_NOMATCH) { - return true; - } - } - return false; -} - -void Benchmark::Register(const char* name, void (*fn)(int), void (*fn_range)(int, int)) { - name_ = name; - fn_ = fn; - fn_range_ = fn_range; - - if (fn_ == NULL && fn_range_ == NULL) { - fprintf(stderr, "%s: missing function\n", name_); - exit(EXIT_FAILURE); - } - - Benchmarks().push_back(this); -} - -void Benchmark::Run() { - if (fn_ != NULL) { - RunWithArg(0); - } else { - if (args_.empty()) { - fprintf(stderr, "%s: no args!\n", name_); - exit(EXIT_FAILURE); - } - for (size_t i = 0; i < args_.size(); ++i) { - RunWithArg(args_[i]); - } - } -} - -void Benchmark::RunRepeatedlyWithArg(int iterations, int arg) { - g_bytes_processed = 0; - g_benchmark_total_time_ns = 0; - g_benchmark_start_time_ns = NanoTime(); - if (fn_ != NULL) { - fn_(iterations); - } else { - fn_range_(iterations, arg); - } - if (g_benchmark_start_time_ns != 0) { - g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns; - } -} - -void Benchmark::RunWithArg(int arg) { - // Run once in case it's expensive. - int iterations = 1; - int64_t realStartTime = NanoTime(); - RunRepeatedlyWithArg(iterations, arg); - int64_t realTotalTime = NanoTime() - realStartTime; - while (realTotalTime < 1e9 && iterations < 1e8) { - int last = iterations; - if (realTotalTime/iterations == 0) { - iterations = 1e9; - } else { - iterations = 1e9 / (realTotalTime/iterations); - } - iterations = std::max(last + 1, std::min(iterations + iterations/2, 100*last)); - iterations = Round(iterations); - realStartTime = NanoTime(); - RunRepeatedlyWithArg(iterations, arg); - realTotalTime = NanoTime() - realStartTime; - } - - char throughput[100]; - throughput[0] = '\0'; - - if (g_benchmark_total_time_ns > 0 && g_bytes_processed > 0) { - double gib_processed = static_cast<double>(g_bytes_processed)/1e9; - double seconds = static_cast<double>(g_benchmark_total_time_ns)/1e9; - snprintf(throughput, sizeof(throughput), " %8.3f GiB/s", gib_processed/seconds); - } - - char full_name[100]; - if (fn_range_ != NULL) { - snprintf(full_name, sizeof(full_name), "%s/%s", name_, PrettyInt(arg, 2).c_str()); - } else { - snprintf(full_name, sizeof(full_name), "%s", name_); - } - - printf("%-*s %10s %10" PRId64 "%s\n", - g_name_column_width, full_name, - PrettyInt(iterations, 10).c_str(), - g_benchmark_total_time_ns/iterations, - throughput); - fflush(stdout); -} - -} // namespace testing - -void SetBenchmarkBytesProcessed(int64_t x) { - g_bytes_processed = x; -} - -void StopBenchmarkTiming() { - if (g_benchmark_start_time_ns != 0) { - g_benchmark_total_time_ns += NanoTime() - g_benchmark_start_time_ns; - } - g_benchmark_start_time_ns = 0; -} - -void StartBenchmarkTiming() { - if (g_benchmark_start_time_ns == 0) { - g_benchmark_start_time_ns = NanoTime(); - } -} - -int main(int argc, char* argv[]) { - if (Benchmarks().empty()) { - fprintf(stderr, "No benchmarks registered!\n"); - exit(EXIT_FAILURE); - } - - for (auto& b : Benchmarks()) { - int name_width = static_cast<int>(strlen(b->Name())); - g_name_column_width = std::max(g_name_column_width, name_width); - } - - bool need_header = true; - for (auto& b : Benchmarks()) { - if (b->ShouldRun(argc, argv)) { - if (need_header) { - printf("%-*s %10s %10s\n", g_name_column_width, "", "iterations", "ns/op"); - fflush(stdout); - need_header = false; - } - b->Run(); - } - } - - if (need_header) { - fprintf(stderr, "No matching benchmarks!\n"); - fprintf(stderr, "Available benchmarks:\n"); - for (auto& b : Benchmarks()) { - fprintf(stderr, " %s\n", b->Name()); - } - exit(EXIT_FAILURE); - } - - return 0; -} diff --git a/benchmarks/include/benchmark.h b/benchmarks/include/benchmark.h deleted file mode 100644 index 7e134a0..0000000 --- a/benchmarks/include/benchmark.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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 BENCHMARKS_BENCHMARK_H_ -#define BENCHMARKS_BENCHMARK_H_ - -#include <stdint.h> -#include <vector> - -namespace testing { - -class Benchmark { - public: - Benchmark(const char* name, void (*fn)(int)) { - Register(name, fn, NULL); - } - - Benchmark(const char* name, void (*fn_range)(int, int)) { - Register(name, NULL, fn_range); - } - - Benchmark* Arg(int x); - - const char* Name(); - - bool ShouldRun(int argc, char* argv[]); - void Run(); - - private: - const char* name_; - - void (*fn_)(int); - void (*fn_range_)(int, int); - - std::vector<int> args_; - - void Register(const char* name, void (*fn)(int), void (*fn_range)(int, int)); - void RunRepeatedlyWithArg(int iterations, int arg); - void RunWithArg(int arg); -}; - -} // namespace testing - -void SetBenchmarkBytesProcessed(int64_t); -void StopBenchmarkTiming(); -void StartBenchmarkTiming(); - -#define BENCHMARK(f) \ - static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \ - (new ::testing::Benchmark(#f, f)) - -#endif diff --git a/benchmarks/main.cpp b/benchmarks/main.cpp new file mode 100644 index 0000000..b6984fc --- /dev/null +++ b/benchmarks/main.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 <regex.h> +#include <stdio.h> +#include <stdlib.h> + +#include <vector> + +#include <benchmark/Benchmark.h> + +int main(int argc, char* argv[]) { + if (::testing::Benchmark::List().empty()) { + fprintf(stderr, "No benchmarks registered!\n"); + exit(EXIT_FAILURE); + } + + std::vector<regex_t*> regs; + for (int i = 1; i < argc; i++) { + regex_t* re = new regex_t; + int errcode = regcomp(re, argv[i], 0); + if (errcode != 0) { + size_t errbuf_size = regerror(errcode, re, NULL, 0); + if (errbuf_size > 0) { + char* errbuf = new char[errbuf_size]; + regerror(errcode, re, errbuf, errbuf_size); + fprintf(stderr, "Couldn't compile \"%s\" as a regular expression: %s\n", + argv[i], errbuf); + } else { + fprintf(stderr, "Unknown compile error for \"%s\" as a regular expression!\n", argv[i]); + } + exit(EXIT_FAILURE); + } + regs.push_back(re); + } + + if (!::testing::Benchmark::RunAll(regs)) { + fprintf(stderr, "No matching benchmarks!\n"); + fprintf(stderr, "Available benchmarks:\n"); + for (const auto& benchmark : ::testing::Benchmark::List()) { + fprintf(stderr, " %s\n", benchmark->Name().c_str()); + } + exit(EXIT_FAILURE); + } + + return 0; +} diff --git a/benchmarks/math_benchmark.cpp b/benchmarks/math_benchmark.cpp index 8d6dd10..4de28d1 100644 --- a/benchmarks/math_benchmark.cpp +++ b/benchmarks/math_benchmark.cpp @@ -14,16 +14,20 @@ * limitations under the License. */ -#include "benchmark.h" - #include <fenv.h> #include <math.h> +#include <benchmark/Benchmark.h> + +#define AT_COMMON_VALS \ + Arg(1234.0)->Arg(nan(""))->Arg(HUGE_VAL)->Arg(0.0) + // Avoid optimization. volatile double d; volatile double v; -static void BM_math_sqrt(int iters) { +BENCHMARK_NO_ARG(BM_math_sqrt); +void BM_math_sqrt::Run(int iters) { StartBenchmarkTiming(); d = 0.0; @@ -34,9 +38,9 @@ static void BM_math_sqrt(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_math_sqrt); -static void BM_math_log10(int iters) { +BENCHMARK_NO_ARG(BM_math_log10); +void BM_math_log10::Run(int iters) { StartBenchmarkTiming(); d = 0.0; @@ -47,9 +51,9 @@ static void BM_math_log10(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_math_log10); -static void BM_math_logb(int iters) { +BENCHMARK_NO_ARG(BM_math_logb); +void BM_math_logb::Run(int iters) { StartBenchmarkTiming(); d = 0.0; @@ -60,61 +64,22 @@ static void BM_math_logb(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_math_logb); - -static void BM_math_isinf_NORMAL(int iters) { - StartBenchmarkTiming(); - - d = 0.0; - v = 1234.0; // FP_NORMAL - for (int i = 0; i < iters; ++i) { - d += (isinf)(v); - } - - StopBenchmarkTiming(); -} -BENCHMARK(BM_math_isinf_NORMAL); - -static void BM_math_isinf_NAN(int iters) { - StartBenchmarkTiming(); - - d = 0.0; - v = nan(""); // FP_NAN - for (int i = 0; i < iters; ++i) { - d += (isinf)(v); - } - - StopBenchmarkTiming(); -} -BENCHMARK(BM_math_isinf_NAN); -static void BM_math_isinf_INFINITE(int iters) { +BENCHMARK_WITH_ARG(BM_math_isinf, double)->AT_COMMON_VALS; +void BM_math_isinf::Run(int iters, double value) { StartBenchmarkTiming(); d = 0.0; - v = HUGE_VAL; // FP_INFINITE + v = value; for (int i = 0; i < iters; ++i) { d += (isinf)(v); } StopBenchmarkTiming(); } -BENCHMARK(BM_math_isinf_INFINITE); -static void BM_math_isinf_ZERO(int iters) { - StartBenchmarkTiming(); - - d = 0.0; - v = 0.0; // FP_ZERO - for (int i = 0; i < iters; ++i) { - d += (isinf)(v); - } - - StopBenchmarkTiming(); -} -BENCHMARK(BM_math_isinf_ZERO); - -static void BM_math_sin_fast(int iters) { +BENCHMARK_NO_ARG(BM_math_sin_fast); +void BM_math_sin_fast::Run(int iters) { StartBenchmarkTiming(); d = 1.0; @@ -124,9 +89,9 @@ static void BM_math_sin_fast(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_math_sin_fast); -static void BM_math_sin_feupdateenv(int iters) { +BENCHMARK_NO_ARG(BM_math_sin_feupdateenv); +void BM_math_sin_feupdateenv::Run(int iters) { StartBenchmarkTiming(); d = 1.0; @@ -140,9 +105,9 @@ static void BM_math_sin_feupdateenv(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_math_sin_feupdateenv); -static void BM_math_sin_fesetenv(int iters) { +BENCHMARK_NO_ARG(BM_math_sin_fesetenv); +void BM_math_sin_fesetenv::Run(int iters) { StartBenchmarkTiming(); d = 1.0; @@ -156,56 +121,16 @@ static void BM_math_sin_fesetenv(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_math_sin_fesetenv); - -static void BM_math_fpclassify_NORMAL(int iters) { - StartBenchmarkTiming(); - - d = 0.0; - v = 1234.0; // FP_NORMAL - for (int i = 0; i < iters; ++i) { - d += fpclassify(v); - } - - StopBenchmarkTiming(); -} -BENCHMARK(BM_math_fpclassify_NORMAL); - -static void BM_math_fpclassify_NAN(int iters) { - StartBenchmarkTiming(); - - d = 0.0; - v = nan(""); // FP_NAN - for (int i = 0; i < iters; ++i) { - d += fpclassify(v); - } - - StopBenchmarkTiming(); -} -BENCHMARK(BM_math_fpclassify_NAN); - -static void BM_math_fpclassify_INFINITE(int iters) { - StartBenchmarkTiming(); - - d = 0.0; - v = HUGE_VAL; // FP_INFINITE - for (int i = 0; i < iters; ++i) { - d += fpclassify(v); - } - - StopBenchmarkTiming(); -} -BENCHMARK(BM_math_fpclassify_INFINITE); -static void BM_math_fpclassify_ZERO(int iters) { +BENCHMARK_WITH_ARG(BM_math_fpclassify, double)->AT_COMMON_VALS; +void BM_math_fpclassify::Run(int iters, double value) { StartBenchmarkTiming(); d = 0.0; - v = 0.0; // FP_ZERO + v = value; for (int i = 0; i < iters; ++i) { d += fpclassify(v); } StopBenchmarkTiming(); } -BENCHMARK(BM_math_fpclassify_ZERO); diff --git a/benchmarks/property_benchmark.cpp b/benchmarks/property_benchmark.cpp index 0802b4c..944cd68 100644 --- a/benchmarks/property_benchmark.cpp +++ b/benchmarks/property_benchmark.cpp @@ -14,19 +14,21 @@ * limitations under the License. */ -#include "benchmark.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <string> + +#if defined(__BIONIC__) + #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> -#include <vector> -#include <string> +#include <benchmark/Benchmark.h> -extern void *__system_property_area__; +extern void* __system_property_area__; // Do not exceed 512, that is about the largest number of properties // that can be created with the current property area size. @@ -34,200 +36,198 @@ extern void *__system_property_area__; Arg(1)->Arg(4)->Arg(16)->Arg(64)->Arg(128)->Arg(256)->Arg(512) struct LocalPropertyTestState { - LocalPropertyTestState(int nprops) : nprops(nprops), valid(false) { - static const char prop_name_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; + LocalPropertyTestState(int nprops) : nprops(nprops), valid(false) { + static const char prop_name_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; - const char* android_data = getenv("ANDROID_DATA"); - if (android_data == NULL) { - printf("ANDROID_DATA environment variable not set\n"); - return; - } - char dir_template[PATH_MAX]; - snprintf(dir_template, sizeof(dir_template), "%s/local/tmp/prop-XXXXXX", android_data); - char *dirname = mkdtemp(dir_template); - if (!dirname) { - printf("making temp file for test state failed (is %s/local/tmp writable?): %s\n", - android_data, strerror(errno)); - return; - } + const char* android_data = getenv("ANDROID_DATA"); + if (android_data == NULL) { + printf("ANDROID_DATA environment variable not set\n"); + return; + } + char dir_template[PATH_MAX]; + snprintf(dir_template, sizeof(dir_template), "%s/local/tmp/prop-XXXXXX", android_data); + char* dirname = mkdtemp(dir_template); + if (!dirname) { + printf("making temp file for test state failed (is %s/local/tmp writable?): %s\n", + android_data, strerror(errno)); + return; + } - old_pa = __system_property_area__; - __system_property_area__ = NULL; - - pa_dirname = dirname; - pa_filename = pa_dirname + "/__properties__"; - - __system_property_set_filename(pa_filename.c_str()); - __system_property_area_init(); - - names = new char* [nprops]; - name_lens = new int[nprops]; - values = new char* [nprops]; - value_lens = new int[nprops]; - - srandom(nprops); - - for (int i = 0; i < nprops; i++) { - // Make sure the name has at least 10 characters to make - // it very unlikely to generate the same random name. - name_lens[i] = (random() % (PROP_NAME_MAX - 10)) + 10; - names[i] = new char[PROP_NAME_MAX + 1]; - size_t prop_name_len = sizeof(prop_name_chars) - 1; - for (int j = 0; j < name_lens[i]; j++) { - if (j == 0 || names[i][j-1] == '.' || j == name_lens[i] - 1) { - // Certain values are not allowed: - // - Don't start name with '.' - // - Don't allow '.' to appear twice in a row - // - Don't allow the name to end with '.' - // This assumes that '.' is the last character in the - // array so that decrementing the length by one removes - // the value from the possible values. - prop_name_len--; - } - names[i][j] = prop_name_chars[random() % prop_name_len]; - } - names[i][name_lens[i]] = 0; - - // Make sure the value contains at least 1 character. - value_lens[i] = (random() % (PROP_VALUE_MAX - 1)) + 1; - values[i] = new char[PROP_VALUE_MAX]; - for (int j = 0; j < value_lens[i]; j++) { - values[i][j] = prop_name_chars[random() % (sizeof(prop_name_chars) - 1)]; - } - - if (__system_property_add(names[i], name_lens[i], values[i], value_lens[i]) < 0) { - printf("Failed to add a property, terminating...\n"); - printf("%s = %.*s\n", names[i], value_lens[i], values[i]); - exit(1); - } + old_pa = __system_property_area__; + __system_property_area__ = NULL; + + pa_dirname = dirname; + pa_filename = pa_dirname + "/__properties__"; + + __system_property_set_filename(pa_filename.c_str()); + __system_property_area_init(); + + names = new char* [nprops]; + name_lens = new int[nprops]; + values = new char* [nprops]; + value_lens = new int[nprops]; + + srandom(nprops); + + for (int i = 0; i < nprops; i++) { + // Make sure the name has at least 10 characters to make + // it very unlikely to generate the same random name. + name_lens[i] = (random() % (PROP_NAME_MAX - 10)) + 10; + names[i] = new char[PROP_NAME_MAX + 1]; + size_t prop_name_len = sizeof(prop_name_chars) - 1; + for (int j = 0; j < name_lens[i]; j++) { + if (j == 0 || names[i][j-1] == '.' || j == name_lens[i] - 1) { + // Certain values are not allowed: + // - Don't start name with '.' + // - Don't allow '.' to appear twice in a row + // - Don't allow the name to end with '.' + // This assumes that '.' is the last character in the + // array so that decrementing the length by one removes + // the value from the possible values. + prop_name_len--; } - - valid = true; + names[i][j] = prop_name_chars[random() % prop_name_len]; + } + names[i][name_lens[i]] = 0; + + // Make sure the value contains at least 1 character. + value_lens[i] = (random() % (PROP_VALUE_MAX - 1)) + 1; + values[i] = new char[PROP_VALUE_MAX]; + for (int j = 0; j < value_lens[i]; j++) { + values[i][j] = prop_name_chars[random() % (sizeof(prop_name_chars) - 1)]; + } + + if (__system_property_add(names[i], name_lens[i], values[i], value_lens[i]) < 0) { + printf("Failed to add a property, terminating...\n"); + printf("%s = %.*s\n", names[i], value_lens[i], values[i]); + exit(1); + } } - ~LocalPropertyTestState() { - if (!valid) - return; + valid = true; + } - __system_property_area__ = old_pa; + ~LocalPropertyTestState() { + if (!valid) + return; - __system_property_set_filename(PROP_FILENAME); - unlink(pa_filename.c_str()); - rmdir(pa_dirname.c_str()); + __system_property_area__ = old_pa; - for (int i = 0; i < nprops; i++) { - delete names[i]; - delete values[i]; - } - delete[] names; - delete[] name_lens; - delete[] values; - delete[] value_lens; + __system_property_set_filename(PROP_FILENAME); + unlink(pa_filename.c_str()); + rmdir(pa_dirname.c_str()); + + for (int i = 0; i < nprops; i++) { + delete names[i]; + delete values[i]; } + delete[] names; + delete[] name_lens; + delete[] values; + delete[] value_lens; + } public: - const int nprops; - char **names; - int *name_lens; - char **values; - int *value_lens; - bool valid; + const int nprops; + char** names; + int* name_lens; + char** values; + int* value_lens; + bool valid; private: - std::string pa_dirname; - std::string pa_filename; - void *old_pa; + std::string pa_dirname; + std::string pa_filename; + void* old_pa; }; -static void BM_property_get(int iters, int nprops) -{ - StopBenchmarkTiming(); +BENCHMARK_WITH_ARG(BM_property_get, int)->TEST_NUM_PROPS; +void BM_property_get::Run(int iters, int nprops) { + StopBenchmarkTiming(); - LocalPropertyTestState pa(nprops); - char value[PROP_VALUE_MAX]; + LocalPropertyTestState pa(nprops); + char value[PROP_VALUE_MAX]; - if (!pa.valid) - return; + if (!pa.valid) + return; - srandom(iters * nprops); + srandom(iters * nprops); - StartBenchmarkTiming(); + StartBenchmarkTiming(); - for (int i = 0; i < iters; i++) { - __system_property_get(pa.names[random() % nprops], value); - } - StopBenchmarkTiming(); + for (int i = 0; i < iters; i++) { + __system_property_get(pa.names[random() % nprops], value); + } + StopBenchmarkTiming(); } -BENCHMARK(BM_property_get)->TEST_NUM_PROPS; -static void BM_property_find(int iters, int nprops) -{ - StopBenchmarkTiming(); +BENCHMARK_WITH_ARG(BM_property_find, int)->TEST_NUM_PROPS; +void BM_property_find::Run(int iters, int nprops) { + StopBenchmarkTiming(); - LocalPropertyTestState pa(nprops); + LocalPropertyTestState pa(nprops); - if (!pa.valid) - return; + if (!pa.valid) + return; - srandom(iters * nprops); + srandom(iters * nprops); - StartBenchmarkTiming(); + StartBenchmarkTiming(); - for (int i = 0; i < iters; i++) { - __system_property_find(pa.names[random() % nprops]); - } - StopBenchmarkTiming(); + for (int i = 0; i < iters; i++) { + __system_property_find(pa.names[random() % nprops]); + } + StopBenchmarkTiming(); } -BENCHMARK(BM_property_find)->TEST_NUM_PROPS; -static void BM_property_read(int iters, int nprops) -{ - StopBenchmarkTiming(); +BENCHMARK_WITH_ARG(BM_property_read, int)->TEST_NUM_PROPS; +void BM_property_read::Run(int iters, int nprops) { + StopBenchmarkTiming(); - LocalPropertyTestState pa(nprops); + LocalPropertyTestState pa(nprops); - if (!pa.valid) - return; + if (!pa.valid) + return; - srandom(iters * nprops); - const prop_info** pinfo = new const prop_info*[iters]; - char propvalue[PROP_VALUE_MAX]; + srandom(iters * nprops); + const prop_info** pinfo = new const prop_info*[iters]; + char propvalue[PROP_VALUE_MAX]; - for (int i = 0; i < iters; i++) { - pinfo[i] = __system_property_find(pa.names[random() % nprops]); - } + for (int i = 0; i < iters; i++) { + pinfo[i] = __system_property_find(pa.names[random() % nprops]); + } - StartBenchmarkTiming(); - for (int i = 0; i < iters; i++) { - __system_property_read(pinfo[i], 0, propvalue); - } - StopBenchmarkTiming(); + StartBenchmarkTiming(); + for (int i = 0; i < iters; i++) { + __system_property_read(pinfo[i], 0, propvalue); + } + StopBenchmarkTiming(); - delete[] pinfo; + delete[] pinfo; } -BENCHMARK(BM_property_read)->TEST_NUM_PROPS; -static void BM_property_serial(int iters, int nprops) -{ - StopBenchmarkTiming(); +BENCHMARK_WITH_ARG(BM_property_serial, int)->TEST_NUM_PROPS; +void BM_property_serial::Run(int iters, int nprops) { + StopBenchmarkTiming(); - LocalPropertyTestState pa(nprops); + LocalPropertyTestState pa(nprops); - if (!pa.valid) - return; + if (!pa.valid) + return; - srandom(iters * nprops); - const prop_info** pinfo = new const prop_info*[iters]; + srandom(iters * nprops); + const prop_info** pinfo = new const prop_info*[iters]; - for (int i = 0; i < iters; i++) { - pinfo[i] = __system_property_find(pa.names[random() % nprops]); - } + for (int i = 0; i < iters; i++) { + pinfo[i] = __system_property_find(pa.names[random() % nprops]); + } - StartBenchmarkTiming(); - for (int i = 0; i < iters; i++) { - __system_property_serial(pinfo[i]); - } - StopBenchmarkTiming(); + StartBenchmarkTiming(); + for (int i = 0; i < iters; i++) { + __system_property_serial(pinfo[i]); + } + StopBenchmarkTiming(); - delete[] pinfo; + delete[] pinfo; } -BENCHMARK(BM_property_serial)->TEST_NUM_PROPS; + +#endif // __BIONIC__ diff --git a/benchmarks/pthread_benchmark.cpp b/benchmarks/pthread_benchmark.cpp index 42023e0..2f6572d 100644 --- a/benchmarks/pthread_benchmark.cpp +++ b/benchmarks/pthread_benchmark.cpp @@ -14,14 +14,15 @@ * limitations under the License. */ -#include "benchmark.h" - #include <pthread.h> +#include <benchmark/Benchmark.h> + // Stop GCC optimizing out our pure function. /* Must not be static! */ pthread_t (*pthread_self_fp)() = pthread_self; -static void BM_pthread_self(int iters) { +BENCHMARK_NO_ARG(BM_pthread_self); +void BM_pthread_self::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { @@ -30,9 +31,9 @@ static void BM_pthread_self(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_pthread_self); -static void BM_pthread_getspecific(int iters) { +BENCHMARK_NO_ARG(BM_pthread_getspecific); +void BM_pthread_getspecific::Run(int iters) { StopBenchmarkTiming(); pthread_key_t key; pthread_key_create(&key, NULL); @@ -45,9 +46,9 @@ static void BM_pthread_getspecific(int iters) { StopBenchmarkTiming(); pthread_key_delete(key); } -BENCHMARK(BM_pthread_getspecific); -static void BM_pthread_setspecific(int iters) { +BENCHMARK_NO_ARG(BM_pthread_setspecific); +void BM_pthread_setspecific::Run(int iters) { StopBenchmarkTiming(); pthread_key_t key; pthread_key_create(&key, NULL); @@ -60,12 +61,12 @@ static void BM_pthread_setspecific(int iters) { StopBenchmarkTiming(); pthread_key_delete(key); } -BENCHMARK(BM_pthread_setspecific); static void DummyPthreadOnceInitFunction() { } -static void BM_pthread_once(int iters) { +BENCHMARK_NO_ARG(BM_pthread_once); +void BM_pthread_once::Run(int iters) { StopBenchmarkTiming(); pthread_once_t once = PTHREAD_ONCE_INIT; pthread_once(&once, DummyPthreadOnceInitFunction); @@ -77,9 +78,9 @@ static void BM_pthread_once(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_pthread_once); -static void BM_pthread_mutex_lock(int iters) { +BENCHMARK_NO_ARG(BM_pthread_mutex_lock); +void BM_pthread_mutex_lock::Run(int iters) { StopBenchmarkTiming(); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; StartBenchmarkTiming(); @@ -91,9 +92,9 @@ static void BM_pthread_mutex_lock(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_pthread_mutex_lock); -static void BM_pthread_mutex_lock_ERRORCHECK(int iters) { +BENCHMARK_NO_ARG(BM_pthread_mutex_lock_ERRORCHECK); +void BM_pthread_mutex_lock_ERRORCHECK::Run(int iters) { StopBenchmarkTiming(); pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; StartBenchmarkTiming(); @@ -105,9 +106,9 @@ static void BM_pthread_mutex_lock_ERRORCHECK(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_pthread_mutex_lock_ERRORCHECK); -static void BM_pthread_mutex_lock_RECURSIVE(int iters) { +BENCHMARK_NO_ARG(BM_pthread_mutex_lock_RECURSIVE); +void BM_pthread_mutex_lock_RECURSIVE::Run(int iters) { StopBenchmarkTiming(); pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; StartBenchmarkTiming(); @@ -119,9 +120,9 @@ static void BM_pthread_mutex_lock_RECURSIVE(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_pthread_mutex_lock_RECURSIVE); -static void BM_pthread_rw_lock_read(int iters) { +BENCHMARK_NO_ARG(BM_pthread_rw_lock_read); +void BM_pthread_rw_lock_read::Run(int iters) { StopBenchmarkTiming(); pthread_rwlock_t lock; pthread_rwlock_init(&lock, NULL); @@ -135,9 +136,9 @@ static void BM_pthread_rw_lock_read(int iters) { StopBenchmarkTiming(); pthread_rwlock_destroy(&lock); } -BENCHMARK(BM_pthread_rw_lock_read); -static void BM_pthread_rw_lock_write(int iters) { +BENCHMARK_NO_ARG(BM_pthread_rw_lock_write); +void BM_pthread_rw_lock_write::Run(int iters) { StopBenchmarkTiming(); pthread_rwlock_t lock; pthread_rwlock_init(&lock, NULL); @@ -151,13 +152,13 @@ static void BM_pthread_rw_lock_write(int iters) { StopBenchmarkTiming(); pthread_rwlock_destroy(&lock); } -BENCHMARK(BM_pthread_rw_lock_write); static void* IdleThread(void*) { return NULL; } -static void BM_pthread_create(int iters) { +BENCHMARK_NO_ARG(BM_pthread_create); +void BM_pthread_create::Run(int iters) { StopBenchmarkTiming(); pthread_t thread; @@ -168,43 +169,45 @@ static void BM_pthread_create(int iters) { pthread_join(thread, NULL); } } -BENCHMARK(BM_pthread_create); -static void* RunThread(void*) { - StopBenchmarkTiming(); +static void* RunThread(void* arg) { + ::testing::Benchmark* benchmark = reinterpret_cast<::testing::Benchmark*>(arg); + benchmark->StopBenchmarkTiming(); return NULL; } -static void BM_pthread_create_and_run(int iters) { +BENCHMARK_NO_ARG(BM_pthread_create_and_run); +void BM_pthread_create_and_run::Run(int iters) { StopBenchmarkTiming(); pthread_t thread; for (int i = 0; i < iters; ++i) { StartBenchmarkTiming(); - pthread_create(&thread, NULL, RunThread, NULL); + pthread_create(&thread, NULL, RunThread, this); pthread_join(thread, NULL); } } -BENCHMARK(BM_pthread_create_and_run); -static void* ExitThread(void*) { - StartBenchmarkTiming(); +static void* ExitThread(void* arg) { + ::testing::Benchmark* benchmark = reinterpret_cast<::testing::Benchmark*>(arg); + benchmark->StartBenchmarkTiming(); pthread_exit(NULL); } -static void BM_pthread_exit_and_join(int iters) { +BENCHMARK_NO_ARG(BM_pthread_exit_and_join); +void BM_pthread_exit_and_join::Run(int iters) { StopBenchmarkTiming(); pthread_t thread; for (int i = 0; i < iters; ++i) { - pthread_create(&thread, NULL, ExitThread, NULL); + pthread_create(&thread, NULL, ExitThread, this); pthread_join(thread, NULL); StopBenchmarkTiming(); } } -BENCHMARK(BM_pthread_exit_and_join); -static void BM_pthread_key_create(int iters) { +BENCHMARK_NO_ARG(BM_pthread_key_create); +void BM_pthread_key_create::Run(int iters) { StopBenchmarkTiming(); pthread_key_t key; @@ -215,9 +218,9 @@ static void BM_pthread_key_create(int iters) { pthread_key_delete(key); } } -BENCHMARK(BM_pthread_key_create); -static void BM_pthread_key_delete(int iters) { +BENCHMARK_NO_ARG(BM_pthread_key_delete); +void BM_pthread_key_delete::Run(int iters) { StopBenchmarkTiming(); pthread_key_t key; @@ -228,4 +231,3 @@ static void BM_pthread_key_delete(int iters) { StopBenchmarkTiming(); } } -BENCHMARK(BM_pthread_key_delete); diff --git a/benchmarks/semaphore_benchmark.cpp b/benchmarks/semaphore_benchmark.cpp index 974b046..8dd5684 100644 --- a/benchmarks/semaphore_benchmark.cpp +++ b/benchmarks/semaphore_benchmark.cpp @@ -14,14 +14,15 @@ * limitations under the License. */ -#include "benchmark.h" - #include <pthread.h> #include <semaphore.h> #include <stdatomic.h> #include <stdio.h> -static void BM_semaphore_sem_getvalue(int iters) { +#include <benchmark/Benchmark.h> + +BENCHMARK_NO_ARG(BM_semaphore_sem_getvalue); +void BM_semaphore_sem_getvalue::Run(int iters) { StopBenchmarkTiming(); sem_t semaphore; sem_init(&semaphore, 1, 1); @@ -34,9 +35,9 @@ static void BM_semaphore_sem_getvalue(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_semaphore_sem_getvalue); -static void BM_semaphore_sem_wait_sem_post(int iters) { +BENCHMARK_NO_ARG(BM_semaphore_sem_wait_sem_post); +void BM_semaphore_sem_wait_sem_post::Run(int iters) { StopBenchmarkTiming(); sem_t semaphore; sem_init(&semaphore, 1, 1); @@ -49,7 +50,6 @@ static void BM_semaphore_sem_wait_sem_post(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_semaphore_sem_wait_sem_post); /* * This test reports the overhead of the underlying futex wake syscall on @@ -87,7 +87,8 @@ static void *BM_semaphore_sem_post_start_thread(void *obj) { return NULL; } -static void BM_semaphore_sem_post(int iters) { +BENCHMARK_NO_ARG(BM_semaphore_sem_post); +void BM_semaphore_sem_post::Run(int iters) { StopBenchmarkTiming(); sem_t semaphore; @@ -100,9 +101,6 @@ static void BM_semaphore_sem_post(int iters) { pthread_attr_setschedparam(&attr, ¶m); pthread_attr_setschedpolicy(&attr, SCHED_OTHER); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -#ifdef PTHREAD_SET_INHERIT_SCHED - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); -#endif pthread_t pthread; pthread_create(&pthread, &attr, BM_semaphore_sem_post_start_thread, &semaphore); pthread_attr_destroy(&attr); @@ -143,99 +141,3 @@ static void BM_semaphore_sem_post(int iters) { sched_yield(); } while (!BM_semaphore_sem_post_running); } -BENCHMARK(BM_semaphore_sem_post); - -/* - * This test reports the overhead of sem_post to sem_wake. A circle of - * num_semaphore - 1 threads are run on a set of semaphores to measure the - * activity. One can calculate the sem_wake overhead alone by: - * - * BM_semaphore_sem_post_sem_wait - BM_semaphore_sem_post - BM_time_clock_gettime - * - * Differences will result if there are more threads than active processors, - * there will be delay induced when scheduling the processes. This cost is - * measured by trying different values of num_semaphore. The governor selected - * will have a major impact on the results for a large number of threads. - * - * To reduce the chances for threads racing ahead and not triggering the - * futex, for example the background threads finish their job before the - * sem_wait is hit in the main thread, the background threads will run at - * batch priority and the main thread at fifo priority. This should generally - * guarantee the main thread completes its task of priming itself with the - * sem_wait before the other threads can start. In practice without the - * sched mechanics here, this works on Android configured kernels, this is - * insurance for wacky(tm) sched configurations. - */ -static void *BM_semaphore_sem_post_sem_wait_start_thread(void *obj) { - sem_t *semaphore = reinterpret_cast<sem_t *>(obj); - - while ((BM_semaphore_sem_post_running > 0) && !sem_wait(semaphore)) { - sem_post(semaphore + 1); - } - --BM_semaphore_sem_post_running; - return NULL; -} - -static void BM_semaphore_sem_post_sem_wait_num(int iters, int num_semaphore) { - StopBenchmarkTiming(); - - sem_t semaphore[num_semaphore]; - - for (int i = 0; i < num_semaphore; ++i) { - sem_init(semaphore + i, 0, 0); - } - - pthread_attr_t attr; - pthread_attr_init(&attr); - BM_semaphore_sem_post_running = 1; - struct sched_param param = { 0, }; - pthread_attr_setschedparam(&attr, ¶m); - pthread_attr_setschedpolicy(&attr, SCHED_BATCH); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -#ifdef PTHREAD_SET_INHERIT_SCHED - pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); -#endif - for (int i = 0; i < (num_semaphore - 1); ++i) { - pthread_t pthread; - pthread_create(&pthread, &attr, BM_semaphore_sem_post_sem_wait_start_thread, semaphore + i); - } - pthread_attr_destroy(&attr); - sched_yield(); - - param.sched_priority = 1; - sched_setscheduler((pid_t)0, SCHED_FIFO, ¶m); - - StartBenchmarkTiming(); - - for (int i = 0; i < iters; i += num_semaphore) { - sem_post(semaphore); - sem_wait(semaphore + num_semaphore - 1); - } - - StopBenchmarkTiming(); - - param.sched_priority = 0; - sched_setscheduler((pid_t)0, SCHED_OTHER, ¶m); - - if (BM_semaphore_sem_post_running > 0) { - BM_semaphore_sem_post_running = 0; - } - for (int i = 0; - (i < (10 * num_semaphore)) && (BM_semaphore_sem_post_running > (1 - num_semaphore)); - ++i) { - for (int j = 0; j < (num_semaphore - 1); ++j) { - sem_post(semaphore + j); - } - sched_yield(); - } -} - -static void BM_semaphore_sem_post_sem_wait_low(int iters) { - BM_semaphore_sem_post_sem_wait_num(iters, 2); -} -BENCHMARK(BM_semaphore_sem_post_sem_wait_low); - -static void BM_semaphore_sem_post_sem_wait_high(int iters) { - BM_semaphore_sem_post_sem_wait_num(iters, 100); -} -BENCHMARK(BM_semaphore_sem_post_sem_wait_high); diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp index 5658a50..342e561 100644 --- a/benchmarks/stdio_benchmark.cpp +++ b/benchmarks/stdio_benchmark.cpp @@ -14,11 +14,11 @@ * limitations under the License. */ -#include "benchmark.h" - #include <stdio.h> #include <stdio_ext.h> +#include <benchmark/Benchmark.h> + #define KB 1024 #define MB 1024*KB @@ -27,12 +27,12 @@ Arg(1*KB)->Arg(4*KB)->Arg(8*KB)->Arg(16*KB)->Arg(64*KB) template <typename Fn> -static void ReadWriteTest(int iters, int chunk_size, Fn f, bool buffered) { - StopBenchmarkTiming(); +void ReadWriteTest(::testing::Benchmark* benchmark, int iters, int chunk_size, Fn f, bool buffered) { + benchmark->StopBenchmarkTiming(); FILE* fp = fopen("/dev/zero", "rw"); __fsetlocking(fp, FSETLOCKING_BYCALLER); char* buf = new char[chunk_size]; - StartBenchmarkTiming(); + benchmark->StartBenchmarkTiming(); if (!buffered) { setvbuf(fp, 0, _IONBF, 0); @@ -42,31 +42,31 @@ static void ReadWriteTest(int iters, int chunk_size, Fn f, bool buffered) { f(buf, chunk_size, 1, fp); } - StopBenchmarkTiming(); - SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size)); + benchmark->StopBenchmarkTiming(); + benchmark->SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(chunk_size)); delete[] buf; fclose(fp); } -static void BM_stdio_fread(int iters, int chunk_size) { - ReadWriteTest(iters, chunk_size, fread, true); +BENCHMARK_WITH_ARG(BM_stdio_fread, int)->AT_COMMON_SIZES; +void BM_stdio_fread::Run(int iters, int chunk_size) { + ReadWriteTest(this, iters, chunk_size, fread, true); } -BENCHMARK(BM_stdio_fread)->AT_COMMON_SIZES; -static void BM_stdio_fwrite(int iters, int chunk_size) { - ReadWriteTest(iters, chunk_size, fwrite, true); +BENCHMARK_WITH_ARG(BM_stdio_fwrite, int)->AT_COMMON_SIZES; +void BM_stdio_fwrite::Run(int iters, int chunk_size) { + ReadWriteTest(this, iters, chunk_size, fwrite, true); } -BENCHMARK(BM_stdio_fwrite)->AT_COMMON_SIZES; -static void BM_stdio_fread_unbuffered(int iters, int chunk_size) { - ReadWriteTest(iters, chunk_size, fread, false); +BENCHMARK_WITH_ARG(BM_stdio_fread_unbuffered, int)->AT_COMMON_SIZES; +void BM_stdio_fread_unbuffered::Run(int iters, int chunk_size) { + ReadWriteTest(this, iters, chunk_size, fread, false); } -BENCHMARK(BM_stdio_fread_unbuffered)->AT_COMMON_SIZES; -static void BM_stdio_fwrite_unbuffered(int iters, int chunk_size) { - ReadWriteTest(iters, chunk_size, fwrite, false); +BENCHMARK_WITH_ARG(BM_stdio_fwrite_unbuffered, int)->AT_COMMON_SIZES; +void BM_stdio_fwrite_unbuffered::Run(int iters, int chunk_size) { + ReadWriteTest(this, iters, chunk_size, fwrite, false); } -BENCHMARK(BM_stdio_fwrite_unbuffered)->AT_COMMON_SIZES; static void FopenFgetsFclose(int iters, bool no_locking) { char buf[1024]; @@ -78,12 +78,16 @@ static void FopenFgetsFclose(int iters, bool no_locking) { } } -static void BM_stdio_fopen_fgets_fclose_locking(int iters) { +BENCHMARK_NO_ARG(BM_stdio_fopen_fgets_fclose_locking); +void BM_stdio_fopen_fgets_fclose_locking::Run(int iters) { + StartBenchmarkTiming(); FopenFgetsFclose(iters, false); + StopBenchmarkTiming(); } -BENCHMARK(BM_stdio_fopen_fgets_fclose_locking); -static void BM_stdio_fopen_fgets_fclose_no_locking(int iters) { +BENCHMARK_NO_ARG(BM_stdio_fopen_fgets_fclose_no_locking); +void BM_stdio_fopen_fgets_fclose_no_locking::Run(int iters) { + StartBenchmarkTiming(); FopenFgetsFclose(iters, true); + StopBenchmarkTiming(); } -BENCHMARK(BM_stdio_fopen_fgets_fclose_no_locking); diff --git a/benchmarks/string_benchmark.cpp b/benchmarks/string_benchmark.cpp index 536e253..866aa00 100644 --- a/benchmarks/string_benchmark.cpp +++ b/benchmarks/string_benchmark.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "benchmark.h" - +#include <stdint.h> #include <string.h> +#include <benchmark/Benchmark.h> + #define KB 1024 #define MB 1024*KB @@ -26,7 +27,8 @@ // TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.) -static void BM_string_memcmp(int iters, int nbytes) { +BENCHMARK_WITH_ARG(BM_string_memcmp, int)->AT_COMMON_SIZES; +void BM_string_memcmp::Run(int iters, int nbytes) { StopBenchmarkTiming(); char* src = new char[nbytes]; char* dst = new char[nbytes]; memset(src, 'x', nbytes); @@ -39,13 +41,13 @@ static void BM_string_memcmp(int iters, int nbytes) { } StopBenchmarkTiming(); - SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes)); + SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); delete[] src; delete[] dst; } -BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES; -static void BM_string_memcpy(int iters, int nbytes) { +BENCHMARK_WITH_ARG(BM_string_memcpy, int)->AT_COMMON_SIZES; +void BM_string_memcpy::Run(int iters, int nbytes) { StopBenchmarkTiming(); char* src = new char[nbytes]; char* dst = new char[nbytes]; memset(src, 'x', nbytes); @@ -56,13 +58,13 @@ static void BM_string_memcpy(int iters, int nbytes) { } StopBenchmarkTiming(); - SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes)); + SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); delete[] src; delete[] dst; } -BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES; -static void BM_string_memmove(int iters, int nbytes) { +BENCHMARK_WITH_ARG(BM_string_memmove, int)->AT_COMMON_SIZES; +void BM_string_memmove::Run(int iters, int nbytes) { StopBenchmarkTiming(); char* buf = new char[nbytes + 64]; memset(buf, 'x', nbytes + 64); @@ -73,12 +75,12 @@ static void BM_string_memmove(int iters, int nbytes) { } StopBenchmarkTiming(); - SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes)); + SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); delete[] buf; } -BENCHMARK(BM_string_memmove)->AT_COMMON_SIZES; -static void BM_string_memset(int iters, int nbytes) { +BENCHMARK_WITH_ARG(BM_string_memset, int)->AT_COMMON_SIZES; +void BM_string_memset::Run(int iters, int nbytes) { StopBenchmarkTiming(); char* dst = new char[nbytes]; StartBenchmarkTiming(); @@ -88,12 +90,12 @@ static void BM_string_memset(int iters, int nbytes) { } StopBenchmarkTiming(); - SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes)); + SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); delete[] dst; } -BENCHMARK(BM_string_memset)->AT_COMMON_SIZES; -static void BM_string_strlen(int iters, int nbytes) { +BENCHMARK_WITH_ARG(BM_string_strlen, int)->AT_COMMON_SIZES; +void BM_string_strlen::Run(int iters, int nbytes) { StopBenchmarkTiming(); char* s = new char[nbytes]; memset(s, 'x', nbytes); @@ -106,7 +108,6 @@ static void BM_string_strlen(int iters, int nbytes) { } StopBenchmarkTiming(); - SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes)); + SetBenchmarkBytesProcessed(uint64_t(iters) * uint64_t(nbytes)); delete[] s; } -BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES; diff --git a/benchmarks/time_benchmark.cpp b/benchmarks/time_benchmark.cpp index f093ec1..6688bbc 100644 --- a/benchmarks/time_benchmark.cpp +++ b/benchmarks/time_benchmark.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ -#include "benchmark.h" - -#include <unistd.h> #include <sys/syscall.h> #include <sys/time.h> #include <time.h> -static void BM_time_clock_gettime(int iters) { +#include <benchmark/Benchmark.h> + +BENCHMARK_NO_ARG(BM_time_clock_gettime); +void BM_time_clock_gettime::Run(int iters) { StartBenchmarkTiming(); timespec t; @@ -31,9 +31,9 @@ static void BM_time_clock_gettime(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_time_clock_gettime); -static void BM_time_clock_gettime_syscall(int iters) { +BENCHMARK_NO_ARG(BM_time_clock_gettime_syscall); +void BM_time_clock_gettime_syscall::Run(int iters) { StartBenchmarkTiming(); timespec t; @@ -43,9 +43,9 @@ static void BM_time_clock_gettime_syscall(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_time_clock_gettime_syscall); -static void BM_time_gettimeofday(int iters) { +BENCHMARK_NO_ARG(BM_time_gettimeofday); +void BM_time_gettimeofday::Run(int iters) { StartBenchmarkTiming(); timeval tv; @@ -55,9 +55,9 @@ static void BM_time_gettimeofday(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_time_gettimeofday); -static void BM_time_gettimeofday_syscall(int iters) { +BENCHMARK_NO_ARG(BM_time_gettimeofday_syscall); +void BM_time_gettimeofday_syscall::Run(int iters) { StartBenchmarkTiming(); timeval tv; @@ -67,9 +67,9 @@ static void BM_time_gettimeofday_syscall(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_time_gettimeofday_syscall); -static void BM_time_time(int iters) { +BENCHMARK_NO_ARG(BM_time_time); +void BM_time_time::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { @@ -78,4 +78,3 @@ static void BM_time_time(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_time_time); diff --git a/benchmarks/unistd_benchmark.cpp b/benchmarks/unistd_benchmark.cpp index 94be1dd..09ca0e6 100644 --- a/benchmarks/unistd_benchmark.cpp +++ b/benchmarks/unistd_benchmark.cpp @@ -14,12 +14,13 @@ * limitations under the License. */ -#include "benchmark.h" - #include <sys/syscall.h> #include <unistd.h> -static void BM_unistd_getpid(int iters) { +#include <benchmark/Benchmark.h> + +BENCHMARK_NO_ARG(BM_unistd_getpid); +void BM_unistd_getpid::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { @@ -28,9 +29,9 @@ static void BM_unistd_getpid(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_unistd_getpid); -static void BM_unistd_getpid_syscall(int iters) { +BENCHMARK_NO_ARG(BM_unistd_getpid_syscall); +void BM_unistd_getpid_syscall::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { @@ -39,14 +40,14 @@ static void BM_unistd_getpid_syscall(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_unistd_getpid_syscall); #if defined(__BIONIC__) // Stop GCC optimizing out our pure function. /* Must not be static! */ pid_t (*gettid_fp)() = gettid; -static void BM_unistd_gettid(int iters) { +BENCHMARK_NO_ARG(BM_unistd_gettid); +void BM_unistd_gettid::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { @@ -55,11 +56,11 @@ static void BM_unistd_gettid(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_unistd_gettid); #endif -static void BM_unistd_gettid_syscall(int iters) { +BENCHMARK_NO_ARG(BM_unistd_gettid_syscall); +void BM_unistd_gettid_syscall::Run(int iters) { StartBenchmarkTiming(); for (int i = 0; i < iters; ++i) { @@ -68,4 +69,3 @@ static void BM_unistd_gettid_syscall(int iters) { StopBenchmarkTiming(); } -BENCHMARK(BM_unistd_gettid_syscall); diff --git a/benchmarks/utils.cpp b/benchmarks/utils.cpp new file mode 100644 index 0000000..863b9db --- /dev/null +++ b/benchmarks/utils.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 <inttypes.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#include <string> + +#include "utils.h" + +int Round(int n) { + int base = 1; + while (base*10 < n) { + base *= 10; + } + if (n < 2*base) { + return 2*base; + } + if (n < 5*base) { + return 5*base; + } + return 10*base; +} + +// Similar to the code in art, but supporting both binary and decimal prefixes. +std::string PrettyInt(long value, size_t base) { + if (base != 2 && base != 10) abort(); + + uint64_t count = static_cast<uint64_t>(value); + bool negative_number = false; + if (value < 0) { + negative_number = true; + count = static_cast<uint64_t>(-value); + } + + // The byte thresholds at which we display amounts. A count is displayed + // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1]. + static const uint64_t kUnitThresholds2[] = { + 1024*1024*1024 /* Gi */, 2*1024*1024 /* Mi */, 3*1024 /* Ki */, 0, + }; + static const uint64_t kUnitThresholds10[] = { + 1000*1000*1000 /* G */, 2*1000*1000 /* M */, 3*1000 /* k */, 0, + }; + static const uint64_t kAmountPerUnit2[] = { 1024*1024*1024, 1024*1024, 1024, 1 }; + static const uint64_t kAmountPerUnit10[] = { 1000*1000*1000, 1000*1000, 1000, 1 }; + static const char* const kUnitStrings2[] = { "Gi", "Mi", "Ki", "" }; + static const char* const kUnitStrings10[] = { "G", "M", "k", "" }; + + // Which set are we using? + const uint64_t* kUnitThresholds = ((base == 2) ? kUnitThresholds2 : kUnitThresholds10); + const uint64_t* kAmountPerUnit = ((base == 2) ? kAmountPerUnit2 : kAmountPerUnit10); + const char* const* kUnitStrings = ((base == 2) ? kUnitStrings2 : kUnitStrings10); + + size_t i = 0; + for (; kUnitThresholds[i] != 0; ++i) { + if (count >= kUnitThresholds[i]) { + break; + } + } + char* s = NULL; + asprintf(&s, "%s%" PRId64 "%s", (negative_number ? "-" : ""), + count / kAmountPerUnit[i], kUnitStrings[i]); + std::string result(s); + free(s); + return result; +} diff --git a/benchmarks/utils.h b/benchmarks/utils.h new file mode 100644 index 0000000..c3c64ba --- /dev/null +++ b/benchmarks/utils.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 BENCHMARKS_UTILS_H +#define BENCHMARKS_UTILS_H + +#include <stddef.h> +#include <string> + +int Round(int n); +std::string PrettyInt(long value, size_t base); + +#endif // BENCHMARKS_UTILS_H |