schwehr / gdal-autotest2

unittests based on gunit for C++ and Python's unittest module for GDAL
Apache License 2.0
0 stars 0 forks source link

setup microbenchmarks #2

Open schwehr opened 7 years ago

schwehr commented 7 years ago

https://github.com/google/benchmark

schwehr commented 7 years ago

e.g.

// https://trac.osgeo.org/gdal/ticket/6790
//
//
// double_is_a_type_test --benchmarks=all
//
// Result:
//
// The unsafe macro and the CPLIsDoubleAnInt2 with the cast tied for
// optimized mode speed.

#include <cmath>
#include <limits>

#include "benchmark.h"
#include "gunit.h"

namespace {

#define CPL_IS_DOUBLE_AN_INT_UNSAFE(d) ((double)(int)(d) == (d))
#define CPL_IS_DOUBLE_AN_INT(d) \
  ((d) >= INT_MIN && (d) <= INT_MAX && (double)(int)(d) == (d))

inline bool CPLIsDoubleAnInt0(double d) {
  return CPL_IS_DOUBLE_AN_INT_UNSAFE(d);
}

inline bool CPLIsDoubleAnInt1(double d) { return CPL_IS_DOUBLE_AN_INT(d); }

// Using "const double &d" was actually slower with -c dbg.
inline bool CPLIsDoubleAnInt2(double d) {
  if (d > std::numeric_limits<int>::max()) return false;
  if (d < std::numeric_limits<int>::min()) return false;
  return d == static_cast<double>(static_cast<int>(d));
}

inline bool CPLIsDoubleAnInt3(double d) {
  if (d > std::numeric_limits<int>::max()) return false;
  if (d < std::numeric_limits<int>::min()) return false;
  double dfTmp = 0.0;
  return modf(d, &dfTmp) == 0.0;
}

inline bool CPLIsDoubleAnInt4(const double& d) {
  if (d > std::numeric_limits<int>::max()) return false;
  if (d < std::numeric_limits<int>::min()) return false;
  double dfTmp = 0.0;
  return modf(d, &dfTmp) == 0.0;
}

const auto kValuesYes = {-1.0, 0.0, 1.0, -1000001.0, 1000001.0};
const auto kValuesNo = {-1.1,  1e-19,  1.00001,   -1000001.999, 1000001.999,
                        1e100, -1e100, 1.234e300, -1.234e300};

static void BM_MacroUnsafe(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPL_IS_DOUBLE_AN_INT_UNSAFE(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPL_IS_DOUBLE_AN_INT_UNSAFE(v)) << v;
    }
  }
}
//BENCHMARK(BM_MacroUnsafe);

static void BM_Macro(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPL_IS_DOUBLE_AN_INT(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPL_IS_DOUBLE_AN_INT(v)) << v;
    }
  }
}
// BENCHMARK(BM_Macro);

static void BM_MacroUnsafeInline(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPLIsDoubleAnInt0(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPLIsDoubleAnInt0(v)) << v;
    }
  }
}
// BENCHMARK(BM_MacroUnsafeInline);

static void BM_MacroInline(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPLIsDoubleAnInt1(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPLIsDoubleAnInt1(v)) << v;
    }
  }
}
// BENCHMARK(BM_MacroInline);

static void BM_Cast(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPLIsDoubleAnInt2(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPLIsDoubleAnInt2(v)) << v;
    }
  }
}
BENCHMARK(BM_MacroUnsafe);
BENCHMARK(BM_Cast);

static void BM_Modf(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPLIsDoubleAnInt3(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPLIsDoubleAnInt3(v)) << v;
    }
  }
}
// BENCHMARK(BM_Modf);

static void BM_ModfConstRef(benchmark::State& state) {
  while (state.KeepRunning()) {
    for (const auto& v : kValuesYes) {
      CHECK(CPLIsDoubleAnInt4(v)) << v;
    }
    for (const auto& v : kValuesNo) {
      CHECK(!CPLIsDoubleAnInt0(v)) << v;
    }
  }
}
// BENCHMARK(BM_ModfConstRef);

}  // namespace

int main(int argc, char** argv) {
  FLAGS_logtostderr = true;
  RunSpecifiedBenchmarks();
}