/* * Copyright (C) 2012-2014 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 <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <vector> #ifndef BIONIC_BENCHMARK_H_ #define BIONIC_BENCHMARK_H_ namespace testing { class Benchmark; template <typename T> class BenchmarkWantsArg; template <typename T> class BenchmarkWithArg; void BenchmarkRegister(Benchmark* bm); int PrettyPrintInt(char* str, int len, unsigned int arg); class Benchmark { public: Benchmark(const char* name, void (*fn)(int)) : name_(strdup(name)), fn_(fn) { BenchmarkRegister(this); } explicit Benchmark(const char* name) : name_(strdup(name)), fn_(NULL) {} virtual ~Benchmark() { free(name_); } const char* Name() { return name_; } virtual const char* ArgName() { return NULL; } virtual void RunFn(int iterations) { fn_(iterations); } protected: char* name_; private: void (*fn_)(int); }; template <typename T> class BenchmarkWantsArgBase : public Benchmark { public: BenchmarkWantsArgBase(const char* name, void (*fn)(int, T)) : Benchmark(name) { fn_arg_ = fn; } BenchmarkWantsArgBase<T>* Arg(const char* arg_name, T arg) { BenchmarkRegister(new BenchmarkWithArg<T>(name_, fn_arg_, arg_name, arg)); return this; } protected: virtual void RunFn(int) { printf("can't run arg benchmark %s without arg\n", Name()); } void (*fn_arg_)(int, T); }; template <typename T> class BenchmarkWithArg : public BenchmarkWantsArg<T> { public: BenchmarkWithArg(const char* name, void (*fn)(int, T), const char* arg_name, T arg) : BenchmarkWantsArg<T>(name, fn), arg_(arg) { arg_name_ = strdup(arg_name); } virtual ~BenchmarkWithArg() { free(arg_name_); } virtual const char* ArgName() { return arg_name_; } protected: virtual void RunFn(int iterations) { BenchmarkWantsArg<T>::fn_arg_(iterations, arg_); } private: T arg_; char* arg_name_; }; template <typename T> class BenchmarkWantsArg : public BenchmarkWantsArgBase<T> { public: BenchmarkWantsArg<T>(const char* name, void (*fn)(int, T)) : BenchmarkWantsArgBase<T>(name, fn) { } }; template <> class BenchmarkWantsArg<int> : public BenchmarkWantsArgBase<int> { public: BenchmarkWantsArg<int>(const char* name, void (*fn)(int, int)) : BenchmarkWantsArgBase<int>(name, fn) { } BenchmarkWantsArg<int>* Arg(int arg) { char arg_name[100]; PrettyPrintInt(arg_name, sizeof(arg_name), arg); BenchmarkRegister(new BenchmarkWithArg<int>(name_, fn_arg_, arg_name, arg)); return this; } }; static inline Benchmark* BenchmarkFactory(const char* name, void (*fn)(int)) { return new Benchmark(name, fn); } template <typename T> static inline BenchmarkWantsArg<T>* BenchmarkFactory(const char* name, void (*fn)(int, T)) { return new BenchmarkWantsArg<T>(name, fn); } } // namespace testing template <typename T> static inline void BenchmarkAddArg(::testing::Benchmark* b, const char* name, T arg) { ::testing::BenchmarkWantsArg<T>* ba; ba = static_cast< ::testing::BenchmarkWantsArg<T>* >(b); ba->Arg(name, arg); } void SetBenchmarkBytesProcessed(uint64_t); void ResetBenchmarkTiming(void); void StopBenchmarkTiming(void); void StartBenchmarkTiming(void); void StartBenchmarkTiming(uint64_t); void StopBenchmarkTiming(uint64_t); #define BENCHMARK(f) \ static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = /* NOLINT */ \ (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f) /* NOLINT */ #endif // BIONIC_BENCHMARK_H_