Improve benchmarking tool, add a few math benchmarks.

Change-Id: I641305dd0e4ac0705381e735ed1604c5be7aa536
diff --git a/tests/Android.mk b/tests/Android.mk
index ed1df6e..3217a4d 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -26,9 +26,11 @@
     -O2 \
     -Wall -Wextra \
     -Werror \
+    -fno-builtin \
 
 benchmark_src_files = \
     benchmark_main.cpp \
+    math_benchmark.cpp \
     string_benchmark.cpp \
 
 # Build benchmarks for the device (with bionic's .so). Run with:
diff --git a/tests/benchmark.h b/tests/benchmark.h
index 70d4c63..d7af50f 100644
--- a/tests/benchmark.h
+++ b/tests/benchmark.h
@@ -32,6 +32,8 @@
 
   Benchmark* Arg(int x);
 
+  const char* Name();
+
   bool ShouldRun(int argc, char* argv[]);
   void Run();
 
diff --git a/tests/benchmark_main.cpp b/tests/benchmark_main.cpp
index 4fbeb07..e15a688 100644
--- a/tests/benchmark_main.cpp
+++ b/tests/benchmark_main.cpp
@@ -59,6 +59,10 @@
   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.
@@ -94,12 +98,16 @@
 }
 
 void Benchmark::Run() {
-  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]);
+  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]);
+    }
   }
 }
 
@@ -180,18 +188,31 @@
 
 int main(int argc, char* argv[]) {
   if (gBenchmarks.empty()) {
-    fprintf(stderr, "no benchmarks!\n");
+    fprintf(stderr, "No benchmarks registered!\n");
     exit(EXIT_FAILURE);
   }
 
-  printf("%-20s %10s %10s\n", "", "iterations", "ns/op");
-  fflush(stdout);
-
+  bool need_header = true;
   for (BenchmarkMapIt it = gBenchmarks.begin(); it != gBenchmarks.end(); ++it) {
     ::testing::Benchmark* b = it->second;
     if (b->ShouldRun(argc, argv)) {
+      if (need_header) {
+        printf("%-20s %10s %10s\n", "", "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 (BenchmarkMapIt it = gBenchmarks.begin(); it != gBenchmarks.end(); ++it) {
+      fprintf(stderr, "  %s\n", it->second->Name());
+    }
+    exit(EXIT_FAILURE);
+  }
+
   return 0;
 }
diff --git a/tests/math_benchmark.cpp b/tests/math_benchmark.cpp
new file mode 100644
index 0000000..a8c1cfa
--- /dev/null
+++ b/tests/math_benchmark.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 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 <math.h>
+
+// Avoid optimization.
+double d;
+double v;
+
+static void BM_math_sqrt(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 2.0;
+  for (int i = 0; i < iters; ++i) {
+    d += sqrt(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_sqrt);
+
+static void BM_math_log10(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 1234.0;
+  for (int i = 0; i < iters; ++i) {
+    d += log10(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_log10);
+
+static void BM_math_logb(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 1234.0;
+  for (int i = 0; i < iters; ++i) {
+    d += logb(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_logb);
diff --git a/tests/string_benchmark.cpp b/tests/string_benchmark.cpp
index 7ac8e98..536e253 100644
--- a/tests/string_benchmark.cpp
+++ b/tests/string_benchmark.cpp
@@ -26,7 +26,7 @@
 
 // TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.)
 
-static void BM_memcmp(int iters, int nbytes) {
+static void BM_string_memcmp(int iters, int nbytes) {
   StopBenchmarkTiming();
   char* src = new char[nbytes]; char* dst = new char[nbytes];
   memset(src, 'x', nbytes);
@@ -34,7 +34,7 @@
   StartBenchmarkTiming();
 
   volatile int c __attribute__((unused)) = 0;
-  for (int i = 0; i < iters; i++) {
+  for (int i = 0; i < iters; ++i) {
     c += memcmp(dst, src, nbytes);
   }
 
@@ -43,15 +43,15 @@
   delete[] src;
   delete[] dst;
 }
-BENCHMARK(BM_memcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES;
 
-static void BM_memcpy(int iters, int nbytes) {
+static void BM_string_memcpy(int iters, int nbytes) {
   StopBenchmarkTiming();
   char* src = new char[nbytes]; char* dst = new char[nbytes];
   memset(src, 'x', nbytes);
   StartBenchmarkTiming();
 
-  for (int i = 0; i < iters; i++) {
+  for (int i = 0; i < iters; ++i) {
     memcpy(dst, src, nbytes);
   }
 
@@ -60,15 +60,15 @@
   delete[] src;
   delete[] dst;
 }
-BENCHMARK(BM_memcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
 
-static void BM_memmove(int iters, int nbytes) {
+static void BM_string_memmove(int iters, int nbytes) {
   StopBenchmarkTiming();
   char* buf = new char[nbytes + 64];
   memset(buf, 'x', nbytes + 64);
   StartBenchmarkTiming();
 
-  for (int i = 0; i < iters; i++) {
+  for (int i = 0; i < iters; ++i) {
     memmove(buf, buf + 1, nbytes); // Worst-case overlap.
   }
 
@@ -76,14 +76,14 @@
   SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
   delete[] buf;
 }
-BENCHMARK(BM_memmove)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove)->AT_COMMON_SIZES;
 
-static void BM_memset(int iters, int nbytes) {
+static void BM_string_memset(int iters, int nbytes) {
   StopBenchmarkTiming();
   char* dst = new char[nbytes];
   StartBenchmarkTiming();
 
-  for (int i = 0; i < iters; i++) {
+  for (int i = 0; i < iters; ++i) {
     memset(dst, 0, nbytes);
   }
 
@@ -91,9 +91,9 @@
   SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
   delete[] dst;
 }
-BENCHMARK(BM_memset)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memset)->AT_COMMON_SIZES;
 
-static void BM_strlen(int iters, int nbytes) {
+static void BM_string_strlen(int iters, int nbytes) {
   StopBenchmarkTiming();
   char* s = new char[nbytes];
   memset(s, 'x', nbytes);
@@ -101,7 +101,7 @@
   StartBenchmarkTiming();
 
   volatile int c __attribute__((unused)) = 0;
-  for (int i = 0; i < iters; i++) {
+  for (int i = 0; i < iters; ++i) {
     c += strlen(s);
   }
 
@@ -109,4 +109,4 @@
   SetBenchmarkBytesProcessed(int64_t(iters) * int64_t(nbytes));
   delete[] s;
 }
-BENCHMARK(BM_strlen)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES;