Third step in moving towards adopting new timer semantics

This commit is contained in:
Eric Fiselier 2015-03-06 17:01:05 -05:00
parent f947cebe15
commit a187aa0803
16 changed files with 244 additions and 138 deletions

View File

@ -3,7 +3,8 @@ include_directories(${PROJECT_SOURCE_DIR}/src)
# Define the source files
set(SOURCE_FILES "benchmark.cc" "colorprint.cc" "commandlineflags.cc"
"log.cc" "sleep.cc" "sysinfo.cc" "walltime.cc")
"log.cc" "sleep.cc" "string_util.cc" "sysinfo.cc"
"walltime.cc")
# Determine the correct regular expression engine to use
if(HAVE_STD_REGEX)
set(RE_FILES "re_std.cc")

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@
#include "re.h"
#include "sleep.h"
#include "stat.h"
#include "string_util.h"
#include "sysinfo.h"
#include "walltime.h"
@ -82,108 +83,6 @@ DECLARE_string(heap_check);
namespace benchmark {
namespace {
// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
const char kBigSIUnits[] = "kMGTPEZY";
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
const char kBigIECUnits[] = "KMGTPEZY";
// milli, micro, nano, pico, femto, atto, zepto, yocto.
const char kSmallSIUnits[] = "munpfazy";
// We require that all three arrays have the same size.
static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits),
"SI and IEC unit arrays must be the same size");
static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits),
"Small SI and Big SI unit arrays must be the same size");
static const size_t kUnitsSize = arraysize(kBigSIUnits);
void ToExponentAndMantissa(double val, double thresh, int precision,
double one_k, std::string* mantissa, size_t* exponent) {
std::stringstream mantissa_stream;
if (val < 0) {
mantissa_stream << "-";
val = -val;
}
// Adjust threshold so that it never excludes things which can't be rendered
// in 'precision' digits.
const double adjusted_threshold =
std::max(thresh, 1.0 / pow(10.0, precision));
const double big_threshold = adjusted_threshold * one_k;
const double small_threshold = adjusted_threshold;
if (val > big_threshold) {
// Positive powers
double scaled = val;
for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) {
scaled /= one_k;
if (scaled <= big_threshold) {
mantissa_stream << scaled;
*exponent = i + 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << val;
*exponent = 0;
} else if (val < small_threshold) {
// Negative powers
double scaled = val;
for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) {
scaled *= one_k;
if (scaled >= small_threshold) {
mantissa_stream << scaled;
*exponent = -i - 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << val;
*exponent = 0;
} else {
mantissa_stream << val;
*exponent = 0;
}
*mantissa = mantissa_stream.str();
}
std::string ExponentToPrefix(size_t exponent, bool iec) {
if (exponent == 0) return "";
const size_t index = (exponent > 0 ? exponent - 1 : -exponent - 1);
if (index >= kUnitsSize) return "";
const char* array =
(exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits);
if (iec)
return array[index] + std::string("i");
else
return std::string(1, array[index]);
}
std::string ToBinaryStringFullySpecified(double value, double threshold,
int precision) {
std::string mantissa;
size_t exponent;
ToExponentAndMantissa(value, threshold, precision, 1024.0, &mantissa,
&exponent);
return mantissa + ExponentToPrefix(exponent, false);
}
inline void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
ss << "/" << ToBinaryStringFullySpecified(n, 1.0, 0);
*str += ss.str();
}
inline std::string HumanReadableNumber(double n) {
// 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);
}
// For non-dense Range, intermediate values are powers of kRangeMultiplier.
static const int kRangeMultiplier = 8;
@ -271,7 +170,7 @@ void ComputeStats(const std::vector<BenchmarkReporter::Run>& reports,
mean_data->iterations;
mean_data->bytes_per_second = bytes_per_second_stat.Mean();
mean_data->items_per_second = items_per_second_stat.Mean();
mean_data->max_heapbytes_used = max_heapbytes_used_stat.max();
mean_data->max_heapbytes_used = max_heapbytes_used_stat.Max();
// Only add label to mean/stddev if it is same for all runs
mean_data->report_label = reports[0].report_label;

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -14,9 +14,10 @@
#include "colorprint.h"
#include <stdarg.h>
#include <cstdarg>
#include "commandlineflags.h"
#include "internal_macros.h"
DECLARE_bool(color_print);

View File

@ -14,8 +14,7 @@
#include "commandlineflags.h"
#include <string.h>
#include <cstring>
#include <iostream>
#include <limits>
@ -75,10 +74,7 @@ bool ParseDouble(const std::string& src_text, const char* str, double* value) {
}
inline const char* GetEnv(const char* name) {
#if GTEST_OS_WINDOWS_MOBILE
// We are on Windows CE, which has no environment variables.
return NULL;
#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
#if defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
// Environment variables which we programmatically clear will be set to the
// empty string rather than unset (NULL). Handle that case.
const char* const env = getenv(name);

View File

@ -1,8 +1,7 @@
#ifndef BENCHMARK_COMMANDLINEFLAGS_H_
#define BENCHMARK_COMMANDLINEFLAGS_H_
#include <stdint.h>
#include <cstdint>
#include <string>
// Macro for referencing flags.
@ -72,6 +71,6 @@ bool ParseStringFlag(const char* str, const char* flag, std::string* value);
// Returns true if the string matches the flag.
bool IsFlag(const char* str, const char* flag);
} // end namespace gbenchmark
} // end namespace benchmark
#endif // BENCHMARK_COMMANDLINEFLAGS_H_

View File

@ -21,7 +21,10 @@
#ifndef BENCHMARK_CYCLECLOCK_H_
#define BENCHMARK_CYCLECLOCK_H_
#include <stdint.h>
#include <cstdint>
#include "benchmark/macros.h"
#include "internal_macros.h"
#if defined(OS_MACOSX)
#include <mach/mach_time.h>
@ -39,8 +42,6 @@ extern "C" uint64_t __rdtsc();
#endif
#include <sys/time.h>
#include "benchmark/macros.h"
namespace benchmark {
// NOTE: only i386 and x86_64 have been well tested.
// PPC, sparc, alpha, and ia64 are based on

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <benchmark/macros.h>
#include "re.h"
namespace benchmark {

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -14,8 +14,10 @@
#include "sleep.h"
#include <time.h>
#include <errno.h>
#include <cerrno>
#include <ctime>
#include "internal_macros.h"
namespace benchmark {
#ifdef OS_WINDOWS

View File

@ -1,7 +1,7 @@
#ifndef BENCHMARK_SLEEP_H_
#define BENCHMARK_SLEEP_H_
#include <stdint.h>
#include <cstdint>
namespace benchmark {
const int64_t kNumMillisPerSecond = 1000LL;

View File

@ -1,11 +1,12 @@
#ifndef BENCHMARK_STAT_H_
#define BENCHMARK_STAT_H_
#include <math.h>
#include <iostream>
#include <cmath>
#include <ostream>
#include <limits>
namespace benchmark {
template <typename VType, typename NumType>
class Stat1;
@ -103,7 +104,7 @@ class Stat1 {
NumType numSamples() const { return numsamples_; }
// Return the sum of this sample set
VType sum() const { return sum_; }
VType Sum() const { return sum_; }
// Return the mean of this sample set
VType Mean() const {
@ -267,9 +268,9 @@ class Stat1MinMax : public Stat1<VType, NumType> {
Self operator*(const VType &k) const { return Self(*this) *= k; }
// Return the maximal value in this sample set
VType max() const { return max_; }
VType Max() const { return max_; }
// Return the minimal value in this sample set
VType min() const { return min_; }
VType Min() const { return min_; }
private:
// The - operation makes no sense with Min/Max

157
src/string_util.cc Normal file
View File

@ -0,0 +1,157 @@
#include "string_util.h"
#include <cmath>
#include <cstdarg>
#include <array>
#include <memory>
#include <sstream>
#include "arraysize.h"
namespace benchmark {
namespace {
// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
const char kBigSIUnits[] = "kMGTPEZY";
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
const char kBigIECUnits[] = "KMGTPEZY";
// milli, micro, nano, pico, femto, atto, zepto, yocto.
const char kSmallSIUnits[] = "munpfazy";
// We require that all three arrays have the same size.
static_assert(arraysize(kBigSIUnits) == arraysize(kBigIECUnits),
"SI and IEC unit arrays must be the same size");
static_assert(arraysize(kSmallSIUnits) == arraysize(kBigSIUnits),
"Small SI and Big SI unit arrays must be the same size");
static const int kUnitsSize = arraysize(kBigSIUnits);
} // end anonymous namespace
void ToExponentAndMantissa(double val, double thresh, int precision,
double one_k, std::string* mantissa,
int* exponent) {
std::stringstream mantissa_stream;
if (val < 0) {
mantissa_stream << "-";
val = -val;
}
// Adjust threshold so that it never excludes things which can't be rendered
// in 'precision' digits.
const double adjusted_threshold =
std::max(thresh, 1.0 / std::pow(10.0, precision));
const double big_threshold = adjusted_threshold * one_k;
const double small_threshold = adjusted_threshold;
if (val > big_threshold) {
// Positive powers
double scaled = val;
for (size_t i = 0; i < arraysize(kBigSIUnits); ++i) {
scaled /= one_k;
if (scaled <= big_threshold) {
mantissa_stream << scaled;
*exponent = i + 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << val;
*exponent = 0;
} else if (val < small_threshold) {
// Negative powers
double scaled = val;
for (size_t i = 0; i < arraysize(kSmallSIUnits); ++i) {
scaled *= one_k;
if (scaled >= small_threshold) {
mantissa_stream << scaled;
*exponent = -i - 1;
*mantissa = mantissa_stream.str();
return;
}
}
mantissa_stream << val;
*exponent = 0;
} else {
mantissa_stream << val;
*exponent = 0;
}
*mantissa = mantissa_stream.str();
}
std::string ExponentToPrefix(int exponent, bool iec) {
if (exponent == 0) return "";
const int index = (exponent > 0 ? exponent - 1 : -exponent - 1);
if (index >= kUnitsSize) return "";
const char* array =
(exponent > 0 ? (iec ? kBigIECUnits : kBigSIUnits) : kSmallSIUnits);
if (iec)
return array[index] + std::string("i");
else
return std::string(1, array[index]);
}
std::string ToBinaryStringFullySpecified(double value, double threshold,
int precision) {
std::string mantissa;
int exponent;
ToExponentAndMantissa(value, threshold, precision, 1024.0, &mantissa,
&exponent);
return mantissa + ExponentToPrefix(exponent, false);
}
void AppendHumanReadable(int n, std::string* str) {
std::stringstream ss;
// Round down to the nearest SI prefix.
ss << "/" << ToBinaryStringFullySpecified(n, 1.0, 0);
*str += ss.str();
}
std::string HumanReadableNumber(double n) {
// 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);
}
std::string StringPrintFImp(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);
// TODO(ericwf): use std::array for first attempt to avoid one memory
// allocation guess what the size might be
std::array<char, 256> local_buff;
std::size_t size = local_buff.size();
auto ret = std::vsnprintf(local_buff.data(), size, msg, args_cp);
va_end(args_cp);
// handle empty expansion
if (ret == 0)
return std::string{};
if (static_cast<std::size_t>(ret) < size)
return std::string(local_buff.data());
// we did not provide a long enough buffer on our first attempt.
// add 1 to size to account for null-byte in size cast to prevent overflow
size = static_cast<std::size_t>(ret) + 1;
auto buff_ptr = std::unique_ptr<char[]>(new char[size]);
ret = std::vsnprintf(buff_ptr.get(), size, msg, args);
return std::string(buff_ptr.get());
}
std::string StringPrintF(const char* format, ...)
{
va_list args;
va_start(args, format);
std::string tmp = StringPrintFImp(format, args);
va_end(args);
return tmp;
}
} // end namespace benchmark

48
src/string_util.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef BENCHMARK_STRING_UTIL_H
#define BENCHMARK_STRING_UTIL_H
#include <string>
#include <sstream>
#include <utility>
namespace benchmark {
void ToExponentAndMantissa(double val, double thresh, int precision,
double one_k, std::string* mantissa, int* exponent);
std::string ExponentToPrefix(int exponent, bool iec);
std::string ToBinaryStringFullySpecified(double value, double threshold,
int precision);
void AppendHumanReadable(int n, std::string* str);
std::string HumanReadableNumber(double n);
std::string StringPrintF(const char* format, ...);
inline std::ostream&
StringCatImp(std::ostream& out) noexcept
{
return out;
}
template <class First, class ...Rest>
inline std::ostream&
StringCatImp(std::ostream& out, First&& f, Rest&&... rest)
{
out << std::forward<First>(f);
return StringCatImp(out, std::forward<Rest>(rest)...);
}
template<class ...Args>
inline std::string StrCat(Args&&... args)
{
std::ostringstream ss;
StringCatImp(ss, std::forward<Args>(args)...);
return ss.str();
}
} // end namespace benchmark
#endif // BENCHMARK_STRING_UTIL_H

View File

@ -14,24 +14,26 @@
#include "sysinfo.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/types.h> // this header must be included before 'sys/sysctl.h' to avoid compilation error on FreeBSD
#include <sys/sysctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <cerrno>
#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <limits>
#include <mutex>
#include "arraysize.h"
#include "check.h"
#include "cycleclock.h"
#include "internal_macros.h"
#include "sleep.h"
namespace benchmark {

View File

@ -1,4 +1,4 @@
// Copyright 2014 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.