Merge changes I36924c4b,Ib6bdd09e

* changes:
  Expand swprintf tests.
  Expand wcsto* tests.
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index 0edba65..fae6f20 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -25,6 +25,7 @@
         "-Wunused",
     ],
     srcs: [
+        "bionic_benchmarks.cpp",
         "atomic_benchmark.cpp",
         "math_benchmark.cpp",
         "property_benchmark.cpp",
@@ -35,7 +36,11 @@
         "time_benchmark.cpp",
         "unistd_benchmark.cpp",
     ],
-    static_libs: ["libBionicBenchmarksUtils"],
+    shared_libs: ["libtinyxml2"],
+    static_libs: [
+        "libbase",
+        "libBionicBenchmarksUtils",
+    ],
 }
 
 cc_defaults {
@@ -54,6 +59,7 @@
 cc_benchmark {
     name: "bionic-benchmarks",
     defaults: ["bionic-benchmarks-defaults"],
+    data: ["suites/*"],
 }
 
 // We don't build a static benchmark executable because it's not usually
@@ -87,6 +93,8 @@
     defaults: ["bionic-benchmarks-extras-defaults"],
     srcs: [
         "tests/benchmark_test.cpp",
+        "tests/interface_test.cpp",
     ],
     static_libs: ["libBionicBenchmarksUtils"],
+    data: ["suites/test_*.xml"],
 }
diff --git a/benchmarks/atomic_benchmark.cpp b/benchmarks/atomic_benchmark.cpp
index 66a0120..a584dce 100644
--- a/benchmarks/atomic_benchmark.cpp
+++ b/benchmarks/atomic_benchmark.cpp
@@ -20,10 +20,12 @@
 // Expected mappings from C++ atomics to hardware primitives can be found at
 // http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html .
 
-#include <benchmark/benchmark.h>
 #include <atomic>
 #include <mutex>
 
+#include <benchmark/benchmark.h>
+#include "util.h"
+
 // We time atomic operations separated by a volatile (not atomic!) increment.  This ensures
 // that the compiler emits memory instructions (e.g. load or store) prior to any fence or the
 // like.  That in turn ensures that the CPU has outstanding memory operations when the fence
@@ -48,7 +50,7 @@
     ++counter;
   }
 }
-BENCHMARK(BM_empty);
+BIONIC_BENCHMARK(BM_empty);
 
 static void BM_load_relaxed(benchmark::State& state) {
   unsigned result = 0;
@@ -58,7 +60,7 @@
   }
   sink = result;
 }
-BENCHMARK(BM_load_relaxed);
+BIONIC_BENCHMARK(BM_load_relaxed);
 
 static void BM_load_acquire(benchmark::State& state) {
   unsigned result = 0;
@@ -68,7 +70,7 @@
   }
   sink = result;
 }
-BENCHMARK(BM_load_acquire);
+BIONIC_BENCHMARK(BM_load_acquire);
 
 static void BM_store_release(benchmark::State& state) {
   int i = counter;
@@ -77,7 +79,7 @@
     ++counter;
   }
 }
-BENCHMARK(BM_store_release);
+BIONIC_BENCHMARK(BM_store_release);
 
 static void BM_store_seq_cst(benchmark::State& state) {
   int i = counter;
@@ -86,7 +88,7 @@
     ++counter;
   }
 }
-BENCHMARK(BM_store_seq_cst);
+BIONIC_BENCHMARK(BM_store_seq_cst);
 
 static void BM_fetch_add_relaxed(benchmark::State& state) {
   unsigned result = 0;
@@ -96,7 +98,7 @@
   }
   sink = result;
 }
-BENCHMARK(BM_fetch_add_relaxed);
+BIONIC_BENCHMARK(BM_fetch_add_relaxed);
 
 static void BM_fetch_add_seq_cst(benchmark::State& state) {
   unsigned result = 0;
@@ -106,7 +108,7 @@
   }
   sink = result;
 }
-BENCHMARK(BM_fetch_add_seq_cst);
+BIONIC_BENCHMARK(BM_fetch_add_seq_cst);
 
 // The fence benchmarks include a relaxed load to make it much harder to optimize away
 // the fence.
@@ -120,7 +122,7 @@
   }
   sink = result;
 }
-BENCHMARK(BM_acquire_fence);
+BIONIC_BENCHMARK(BM_acquire_fence);
 
 static void BM_seq_cst_fence(benchmark::State& state) {
   unsigned result = 0;
@@ -131,7 +133,7 @@
   }
   sink = result;
 }
-BENCHMARK(BM_seq_cst_fence);
+BIONIC_BENCHMARK(BM_seq_cst_fence);
 
 // For comparison, also throw in a critical section version:
 
@@ -145,4 +147,4 @@
   }
   sink = result;
 }
-BENCHMARK(BM_fetch_add_cs);
+BIONIC_BENCHMARK(BM_fetch_add_cs);
diff --git a/benchmarks/bionic_benchmarks.cpp b/benchmarks/bionic_benchmarks.cpp
new file mode 100644
index 0000000..f1ae4ff
--- /dev/null
+++ b/benchmarks/bionic_benchmarks.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2017 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 <getopt.h>
+#include <math.h>
+#include <sys/resource.h>
+
+#include <map>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "android-base/strings.h"
+#include <benchmark/benchmark.h>
+#include <tinyxml2.h>
+#include "util.h"
+
+std::map<std::string, benchmark_func_t> g_str_to_func;
+
+std::mutex g_map_lock;
+
+static struct option g_long_options[] =
+{
+  {"bionic_cpu", required_argument, 0, 'c'},
+  {"bionic_xml", required_argument, 0, 'x'},
+  {"bionic_iterations", required_argument, 0, 'i'},
+  {"bionic_extra", required_argument, 0, 'a'},
+  {"help", no_argument, 0, 'h'},
+  {0, 0, 0, 0},
+};
+
+typedef std::vector<std::vector<int>> args_vector_t;
+
+void Usage() {
+  printf("Usage:\n");
+  printf("bionic_benchmarks [--bionic_cpu=<cpu_to_isolate>] [--bionic_xml=<path_to_xml>]\n");
+  printf("                  [--bionic_iterations=<num_iter>]\n");
+  printf("                  [--bionic_extra=\"<fn_name> <arg1> <arg 2> ... \n]");
+  printf("                  [<Google benchmark flags>]\n");
+  printf("Google benchmark flags:\n");
+
+  int fake_argc = 2;
+  char argv0[] = "bionic_benchmarks";
+  char argv1[] = "--help";
+  char* fake_argv[3] {argv0, argv1, NULL};
+  benchmark::Initialize(&fake_argc, fake_argv);
+  abort();
+}
+
+// This function removes any bionic benchmarks command line arguments by checking them
+// against g_long_options. It fills new_argv with the filtered args.
+void SanitizeOpts(int argc, char** argv, std::vector<char*>* new_argv) {
+  // TO THOSE ADDING OPTIONS: This currently doesn't support optional arguments.
+  (*new_argv)[0] = argv[0];
+  for (int i = 1; i < argc; ++i) {
+    char* optarg = argv[i];
+    size_t opt_idx = 0;
+
+    // Iterate through g_long_options until either we hit the end or we have a match.
+    for (opt_idx = 0; g_long_options[opt_idx].name &&
+                      strncmp(g_long_options[opt_idx].name, optarg + 2,
+                              strlen(g_long_options[opt_idx].name)); ++opt_idx) {
+    }
+
+    if (!g_long_options[opt_idx].name) {
+      new_argv->push_back(optarg);
+    } else {
+      if (g_long_options[opt_idx].has_arg == required_argument) {
+        // If the arg was passed in with an =, it spans one char *.
+        // Otherwise, we skip a spot for the argument.
+        if (!strchr(optarg, '=')) {
+          i++;
+        }
+      }
+    }
+  }
+  new_argv->push_back(0);
+}
+
+bench_opts_t ParseOpts(int argc, char** argv) {
+  bench_opts_t opts;
+  int opt;
+  int option_index = 0;
+
+  opts.cpu_to_lock = LONG_MAX;
+  opts.num_iterations = 0;
+
+  // To make this parser handle the benchmark options silently:
+  extern int opterr;
+  opterr = 0;
+
+  while ((opt = getopt_long(argc, argv, "c:x:i:a:h", g_long_options, &option_index)) != -1) {
+    if (opt == -1) {
+      break;
+    }
+    switch (opt) {
+      case 'c':
+        if (*optarg) {
+          char* check_null;
+          opts.cpu_to_lock = strtol(optarg, &check_null, 10);
+          if (*check_null) {
+            printf("ERROR: Args %s is not a valid integer.\n", optarg);
+            abort();
+          }
+        } else {
+          printf("ERROR: no argument specified for bionic_cpu\n");
+          Usage();
+        }
+        break;
+      case 'x':
+        if (*optarg) {
+          opts.xmlpath = optarg;
+        } else {
+          printf("ERROR: no argument specified for bionic_xml\n");
+          Usage();
+        }
+        break;
+      case 'a':
+        if (*optarg) {
+          opts.extra_benchmarks.push_back(optarg);
+        } else {
+          printf("ERROR: no argument specified for bionic_extra\n");
+          Usage();
+        }
+        break;
+      case 'i':
+        if (*optarg){
+          char* check_null;
+          opts.num_iterations = strtol(optarg, &check_null, 10);
+          if (*check_null != '\0') {
+            printf("ERROR: Args %s is not a valid integer.\n", optarg);
+            abort();
+          }
+        } else {
+          printf("ERROR: no argument specified for bionic_iterations\n");
+          Usage();
+        }
+        break;
+      case 'h':
+        Usage();
+        break;
+      case '?':
+        break;
+      default:
+        abort();
+    }
+  }
+  return opts;
+}
+
+// This is a wrapper for every function call for per-benchmark cpu pinning.
+void LockAndRun(benchmark::State& state, benchmark_func_t func_to_bench, long cpu_to_lock) {
+  if (cpu_to_lock != LONG_MAX) LockToCPU(cpu_to_lock);
+  // To avoid having to link against Google benchmarks in libutil,
+  // benchmarks are kept without parameter information, necessitating this cast.
+  reinterpret_cast<void(*) (benchmark::State&)>(func_to_bench)(state);
+}
+
+args_vector_t* ResolveArgs(args_vector_t* to_populate, std::string args,
+                           std::map<std::string, args_vector_t>& args_shorthand) {
+  // args is either a space-separated list of ints or a macro name.
+  // To ease formatting in XML files, args is left and right trimmed.
+  if (args_shorthand.count(args)) {
+    return &args_shorthand[args];
+  }
+  to_populate->push_back(std::vector<int>());
+  std::stringstream sstream(args);
+  std::string argstr;
+  while (sstream >> argstr) {
+    char* check_null;
+    int converted = static_cast<int>(strtol(argstr.c_str(), &check_null, 10));
+    if (*check_null) {
+      printf("ERROR: Args str %s contains an invalid macro or int.\n", args.c_str());
+      abort();
+    }
+    (*to_populate)[0].push_back(converted);
+  }
+  return to_populate;
+}
+
+void RegisterGoogleBenchmarks(bench_opts_t primary_opts, bench_opts_t secondary_opts,
+                         std::string fn_name, args_vector_t* run_args) {
+  if (g_str_to_func.find(fn_name) == g_str_to_func.end()) {
+    printf("ERROR:No benchmark for function %s\n", fn_name.c_str());
+    abort();
+  }
+  long iterations_to_use = primary_opts.num_iterations ? primary_opts.num_iterations :
+                                                         secondary_opts.num_iterations;
+  int cpu_to_use = INT_MAX;
+  if (primary_opts.cpu_to_lock != INT_MAX) {
+    cpu_to_use = primary_opts.cpu_to_lock;
+
+  } else if (secondary_opts.cpu_to_lock != INT_MAX) {
+    cpu_to_use = secondary_opts.cpu_to_lock;
+  }
+
+  for (std::vector<int> args : (*run_args)) {
+    auto registration = benchmark::RegisterBenchmark(fn_name.c_str(), LockAndRun,
+                                                     g_str_to_func.at(fn_name),
+                                                     cpu_to_use)->Args(args);
+    if (iterations_to_use > 0) {
+      registration->Iterations(iterations_to_use);
+    }
+  }
+}
+
+void RegisterCliBenchmarks(bench_opts_t cmdline_opts,
+                           std::map<std::string, args_vector_t>& args_shorthand) {
+  // Register any of the extra benchmarks that were specified in the options.
+  args_vector_t arg_vector;
+  args_vector_t* run_args = &arg_vector;
+  for (std::string extra_fn : cmdline_opts.extra_benchmarks) {
+    android::base::Trim(extra_fn);
+    size_t first_space_pos = extra_fn.find(" ");
+    std::string fn_name = extra_fn.substr(0, first_space_pos);
+    std::string cmd_args;
+    if (first_space_pos != std::string::npos) {
+      cmd_args = extra_fn.substr(extra_fn.find(" ") + 1);
+    } else {
+      cmd_args = "";
+    }
+    run_args = ResolveArgs(run_args, cmd_args, args_shorthand);
+    RegisterGoogleBenchmarks(bench_opts_t(), cmdline_opts, fn_name, run_args);
+
+    run_args = &arg_vector;
+    arg_vector.clear();
+  }
+}
+
+int RegisterXmlBenchmarks(bench_opts_t cmdline_opts,
+                          std::map<std::string, args_vector_t>& args_shorthand) {
+  // Structure of the XML file:
+  // - Element "fn"           Function to benchmark.
+  // - - Element "iterations" Number of iterations to run. Leaving this blank uses
+  //                          Google benchmarks' convergence heuristics.
+  // - - Element "cpu"        CPU to isolate to, if any.
+  // - - Element "args"       Whitespace-separated list of per-function integer arguments, or
+  //                          one of the macros defined in util.h.
+  tinyxml2::XMLDocument doc;
+  if (doc.LoadFile(cmdline_opts.xmlpath.c_str()) != tinyxml2::XML_SUCCESS) {
+    doc.PrintError();
+    return doc.ErrorID();
+  }
+
+  // Read and register the functions.
+  tinyxml2::XMLNode* fn = doc.FirstChildElement("fn");
+  args_vector_t arg_vector;
+  args_vector_t* run_args = &arg_vector;
+  while (fn) {
+    auto fn_elem = fn->FirstChildElement("name");
+    if (!fn_elem) {
+      printf("Error: Malformed XML entry: missing name element.\n");
+      abort();
+    }
+    std::string fn_name = fn_elem->GetText();
+    if (fn_name.empty()) {
+      printf("Error: Malformed XML entry: error parsing name text.");
+      abort();
+    }
+    auto* xml_args = fn->FirstChildElement("args");
+    run_args = ResolveArgs(run_args, xml_args ? android::base::Trim(xml_args->GetText()) : "",
+                           args_shorthand);
+
+    // XML values for CPU and iterations take precedence over those passed in via CLI.
+    bench_opts_t xml_opts{};
+    auto* num_iterations_elem = fn->FirstChildElement("iterations");
+    if (num_iterations_elem) {
+      int temp;
+      num_iterations_elem->QueryIntText(&temp);
+      xml_opts.num_iterations = temp;
+    } else {
+      xml_opts.num_iterations = 0;
+    }
+    auto* cpu_to_lock_elem = fn->FirstChildElement("cpu");
+    if (cpu_to_lock_elem) {
+      int temp;
+      cpu_to_lock_elem->QueryIntText(&temp);
+      xml_opts.cpu_to_lock = temp;
+    } else {
+      xml_opts.cpu_to_lock = INT_MAX;
+    }
+
+    RegisterGoogleBenchmarks(xml_opts, cmdline_opts, fn_name, run_args);
+
+    fn = fn->NextSibling();
+    run_args = &arg_vector;
+    arg_vector.clear();
+  }
+  return 0;
+}
+
+std::map<std::string, args_vector_t> GetShorthand() {
+  std::map<std::string, args_vector_t> args_shorthand {
+    {"AT_ALIGNED_TWOBUF", args_vector_t{ {8, 0, 0},
+                                       {64, 0, 0},
+                                       {512, 0, 0},
+                                       {1 * KB, 0, 0},
+                                       {8 * KB, 0, 0},
+                                       {16 * KB, 0, 0},
+                                       {32 * KB, 0, 0},
+                                       {64 * KB, 0, 0} }},
+    {"AT_ALIGNED_ONEBUF", args_vector_t{ {(8), 0},
+                                           {(64), 0},
+                                           {(512), 0},
+                                           {(1*KB), 0},
+                                           {(8*KB), 0},
+                                           {(16*KB), 0},
+                                           {(32*KB), 0},
+                                           {(64*KB), 0}}},
+
+    {"AT_COMMON_SIZES", args_vector_t{ {8}, {64}, {512}, {1*KB}, {8*KB}, {16*KB},
+                                                       {32*KB}, {64*KB}}},
+
+    // Do not exceed 512. that is about the largest number of properties
+    // that can be created with the current property area size.
+    {"NUM_PROPS", args_vector_t{ {1}, {4}, {16}, {64}, {128}, {256}, {512} }},
+
+    {"MATH_COMMON", args_vector_t{ {0}, {1}, {2}, {3} }}
+  };
+  for (int i = 1; i < 15; i++) {
+    int align = pow(2, i);
+    std::stringstream sstream;
+    sstream << "AT_" << align << "_ALIGN_TWOBUF";
+    args_shorthand.emplace(sstream.str(),
+                           args_vector_t{ {8, align, align},
+                                          {64, align, align},
+                                          {512, align, align},
+                                          {1 * KB, align, align},
+                                          {8 * KB, align, align},
+                                          {16 * KB, align, align},
+                                          {32 * KB, align, align},
+                                          {64 * KB, align, align} });
+    sstream.str("");
+    sstream << "AT_" << align << "_ALIGN_ONEBUF";
+    args_shorthand.emplace(sstream.str(),
+                            args_vector_t{ {(8), align},
+                                           {(64), align},
+                                           {(512), align},
+                                           {(1*KB), align},
+                                           {(8*KB), align},
+                                           {(16*KB), align},
+                                           {(32*KB), align},
+                                           {(64*KB), align} });
+    sstream.str("");
+  }
+  return args_shorthand;
+}
+
+
+int main(int argc, char** argv) {
+  std::map<std::string, args_vector_t> args_shorthand = GetShorthand();
+  bench_opts_t opts = ParseOpts(argc, argv);
+  std::vector<char*> new_argv(argc);
+  SanitizeOpts(argc, argv, &new_argv);
+
+  if (!opts.xmlpath.empty()) {
+    if (int err = RegisterXmlBenchmarks(opts, args_shorthand)) {
+      return err;
+    }
+  }
+  RegisterCliBenchmarks(opts, args_shorthand);
+
+  // Set the thread priority to the maximum.
+  if (setpriority(PRIO_PROCESS, 0, -20)) {
+    perror("Failed to raise priority of process. Are you root?\n");
+  }
+
+  int new_argc = new_argv.size();
+  benchmark::Initialize(&new_argc, new_argv.data());
+  benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/benchmarks/math_benchmark.cpp b/benchmarks/math_benchmark.cpp
index a411c9c..7b9a283 100644
--- a/benchmarks/math_benchmark.cpp
+++ b/benchmarks/math_benchmark.cpp
@@ -18,11 +18,11 @@
 #include <math.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 static const double values[] = { 1234.0, nan(""), HUGE_VAL, 0.0 };
 static const char* names[] = { "1234.0", "nan", "HUGE_VAL", "0.0" };
 
-#define BENCHMARK_COMMON_VALS(name) BENCHMARK(name)->Arg(0)->Arg(1)->Arg(2)->Arg(3)
 
 static void SetLabel(benchmark::State& state) {
   state.SetLabel(names[state.range(0)]);
@@ -39,7 +39,7 @@
     d += sqrt(v);
   }
 }
-BENCHMARK(BM_math_sqrt);
+BIONIC_BENCHMARK(BM_math_sqrt);
 
 static void BM_math_log10(benchmark::State& state) {
   d = 0.0;
@@ -48,7 +48,7 @@
     d += log10(v);
   }
 }
-BENCHMARK(BM_math_log10);
+BIONIC_BENCHMARK(BM_math_log10);
 
 static void BM_math_logb(benchmark::State& state) {
   d = 0.0;
@@ -57,7 +57,7 @@
     d += logb(v);
   }
 }
-BENCHMARK(BM_math_logb);
+BIONIC_BENCHMARK(BM_math_logb);
 
 static void BM_math_isfinite_macro(benchmark::State& state) {
   d = 0.0;
@@ -67,7 +67,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isfinite_macro);
+BIONIC_BENCHMARK(BM_math_isfinite_macro);
 
 #if defined(__BIONIC__)
 #define test_isfinite __isfinite
@@ -82,7 +82,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isfinite);
+BIONIC_BENCHMARK(BM_math_isfinite);
 
 static void BM_math_isinf_macro(benchmark::State& state) {
   d = 0.0;
@@ -92,7 +92,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isinf_macro);
+BIONIC_BENCHMARK(BM_math_isinf_macro);
 
 static void BM_math_isinf(benchmark::State& state) {
   d = 0.0;
@@ -102,7 +102,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isinf);
+BIONIC_BENCHMARK(BM_math_isinf);
 
 static void BM_math_isnan_macro(benchmark::State& state) {
   d = 0.0;
@@ -112,7 +112,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isnan_macro);
+BIONIC_BENCHMARK(BM_math_isnan_macro);
 
 static void BM_math_isnan(benchmark::State& state) {
   d = 0.0;
@@ -122,7 +122,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isnan);
+BIONIC_BENCHMARK(BM_math_isnan);
 
 static void BM_math_isnormal_macro(benchmark::State& state) {
   d = 0.0;
@@ -132,7 +132,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isnormal_macro);
+BIONIC_BENCHMARK(BM_math_isnormal_macro);
 
 #if defined(__BIONIC__)
 static void BM_math_isnormal(benchmark::State& state) {
@@ -143,7 +143,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_isnormal);
+BIONIC_BENCHMARK(BM_math_isnormal);
 #endif
 
 static void BM_math_sin_fast(benchmark::State& state) {
@@ -152,7 +152,7 @@
     d += sin(d);
   }
 }
-BENCHMARK(BM_math_sin_fast);
+BIONIC_BENCHMARK(BM_math_sin_fast);
 
 static void BM_math_sin_feupdateenv(benchmark::State& state) {
   d = 1.0;
@@ -164,7 +164,7 @@
     feupdateenv(&__libc_save_rm);
   }
 }
-BENCHMARK(BM_math_sin_feupdateenv);
+BIONIC_BENCHMARK(BM_math_sin_feupdateenv);
 
 static void BM_math_sin_fesetenv(benchmark::State& state) {
   d = 1.0;
@@ -176,7 +176,7 @@
     fesetenv(&__libc_save_rm);
   }
 }
-BENCHMARK(BM_math_sin_fesetenv);
+BIONIC_BENCHMARK(BM_math_sin_fesetenv);
 
 static void BM_math_fpclassify(benchmark::State& state) {
   d = 0.0;
@@ -186,7 +186,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_fpclassify);
+BIONIC_BENCHMARK(BM_math_fpclassify);
 
 static void BM_math_signbit_macro(benchmark::State& state) {
   d = 0.0;
@@ -196,7 +196,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_signbit_macro);
+BIONIC_BENCHMARK(BM_math_signbit_macro);
 
 static void BM_math_signbit(benchmark::State& state) {
   d = 0.0;
@@ -206,7 +206,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_signbit);
+BIONIC_BENCHMARK(BM_math_signbit);
 
 static void BM_math_fabs_macro(benchmark::State& state) {
   d = 0.0;
@@ -216,7 +216,7 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_fabs_macro);
+BIONIC_BENCHMARK(BM_math_fabs_macro);
 
 static void BM_math_fabs(benchmark::State& state) {
   d = 0.0;
@@ -226,4 +226,4 @@
   }
   SetLabel(state);
 }
-BENCHMARK_COMMON_VALS(BM_math_fabs);
+BIONIC_BENCHMARK(BM_math_fabs);
diff --git a/benchmarks/property_benchmark.cpp b/benchmarks/property_benchmark.cpp
index 97eb832..a099494 100644
--- a/benchmarks/property_benchmark.cpp
+++ b/benchmarks/property_benchmark.cpp
@@ -27,11 +27,7 @@
 #include <sys/_system_properties.h>
 
 #include <benchmark/benchmark.h>
-
-// Do not exceed 512, that is about the largest number of properties
-// that can be created with the current property area size.
-#define TEST_NUM_PROPS \
-    Arg(1)->Arg(4)->Arg(16)->Arg(64)->Arg(128)->Arg(256)->Arg(512)
+#include "util.h"
 
 struct LocalPropertyTestState {
   explicit LocalPropertyTestState(int nprops) : nprops(nprops), valid(false) {
@@ -145,7 +141,7 @@
     __system_property_get(pa.names[random() % nprops], value);
   }
 }
-BENCHMARK(BM_property_get)->TEST_NUM_PROPS;
+BIONIC_BENCHMARK(BM_property_get);
 
 static void BM_property_find(benchmark::State& state) {
   const size_t nprops = state.range(0);
@@ -157,7 +153,7 @@
     __system_property_find(pa.names[random() % nprops]);
   }
 }
-BENCHMARK(BM_property_find)->TEST_NUM_PROPS;
+BIONIC_BENCHMARK(BM_property_find);
 
 static void BM_property_read(benchmark::State& state) {
   const size_t nprops = state.range(0);
@@ -180,7 +176,7 @@
 
   delete[] pinfo;
 }
-BENCHMARK(BM_property_read)->TEST_NUM_PROPS;
+BIONIC_BENCHMARK(BM_property_read);
 
 static void BM_property_serial(benchmark::State& state) {
   const size_t nprops = state.range(0);
@@ -201,6 +197,6 @@
 
   delete[] pinfo;
 }
-BENCHMARK(BM_property_serial)->TEST_NUM_PROPS;
+BIONIC_BENCHMARK(BM_property_serial);
 
 #endif  // __BIONIC__
diff --git a/benchmarks/pthread_benchmark.cpp b/benchmarks/pthread_benchmark.cpp
index d3c2de8..7a967ef 100644
--- a/benchmarks/pthread_benchmark.cpp
+++ b/benchmarks/pthread_benchmark.cpp
@@ -17,6 +17,7 @@
 #include <pthread.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 // Stop GCC optimizing out our pure function.
 /* Must not be static! */ pthread_t (*pthread_self_fp)() = pthread_self;
@@ -26,7 +27,7 @@
     pthread_self_fp();
   }
 }
-BENCHMARK(BM_pthread_self);
+BIONIC_BENCHMARK(BM_pthread_self);
 
 static void BM_pthread_getspecific(benchmark::State& state) {
   pthread_key_t key;
@@ -38,7 +39,7 @@
 
   pthread_key_delete(key);
 }
-BENCHMARK(BM_pthread_getspecific);
+BIONIC_BENCHMARK(BM_pthread_getspecific);
 
 static void BM_pthread_setspecific(benchmark::State& state) {
   pthread_key_t key;
@@ -50,7 +51,7 @@
 
   pthread_key_delete(key);
 }
-BENCHMARK(BM_pthread_setspecific);
+BIONIC_BENCHMARK(BM_pthread_setspecific);
 
 static void DummyPthreadOnceInitFunction() {
 }
@@ -63,7 +64,7 @@
     pthread_once(&once, DummyPthreadOnceInitFunction);
   }
 }
-BENCHMARK(BM_pthread_once);
+BIONIC_BENCHMARK(BM_pthread_once);
 
 static void BM_pthread_mutex_lock(benchmark::State& state) {
   pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -73,7 +74,7 @@
     pthread_mutex_unlock(&mutex);
   }
 }
-BENCHMARK(BM_pthread_mutex_lock);
+BIONIC_BENCHMARK(BM_pthread_mutex_lock);
 
 static void BM_pthread_mutex_lock_ERRORCHECK(benchmark::State& state) {
   pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
@@ -83,7 +84,7 @@
     pthread_mutex_unlock(&mutex);
   }
 }
-BENCHMARK(BM_pthread_mutex_lock_ERRORCHECK);
+BIONIC_BENCHMARK(BM_pthread_mutex_lock_ERRORCHECK);
 
 static void BM_pthread_mutex_lock_RECURSIVE(benchmark::State& state) {
   pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -93,7 +94,7 @@
     pthread_mutex_unlock(&mutex);
   }
 }
-BENCHMARK(BM_pthread_mutex_lock_RECURSIVE);
+BIONIC_BENCHMARK(BM_pthread_mutex_lock_RECURSIVE);
 
 static void BM_pthread_rwlock_read(benchmark::State& state) {
   pthread_rwlock_t lock;
@@ -106,7 +107,7 @@
 
   pthread_rwlock_destroy(&lock);
 }
-BENCHMARK(BM_pthread_rwlock_read);
+BIONIC_BENCHMARK(BM_pthread_rwlock_read);
 
 static void BM_pthread_rwlock_write(benchmark::State& state) {
   pthread_rwlock_t lock;
@@ -119,7 +120,7 @@
 
   pthread_rwlock_destroy(&lock);
 }
-BENCHMARK(BM_pthread_rwlock_write);
+BIONIC_BENCHMARK(BM_pthread_rwlock_write);
 
 static void* IdleThread(void*) {
   return NULL;
@@ -134,7 +135,7 @@
     state.ResumeTiming();
   }
 }
-BENCHMARK(BM_pthread_create);
+BIONIC_BENCHMARK(BM_pthread_create);
 
 static void* RunThread(void* arg) {
   benchmark::State& state = *reinterpret_cast<benchmark::State*>(arg);
@@ -150,7 +151,7 @@
     state.ResumeTiming();
   }
 }
-BENCHMARK(BM_pthread_create_and_run);
+BIONIC_BENCHMARK(BM_pthread_create_and_run);
 
 static void* ExitThread(void* arg) {
   benchmark::State& state = *reinterpret_cast<benchmark::State*>(arg);
@@ -166,7 +167,7 @@
     pthread_join(thread, NULL);
   }
 }
-BENCHMARK(BM_pthread_exit_and_join);
+BIONIC_BENCHMARK(BM_pthread_exit_and_join);
 
 static void BM_pthread_key_create(benchmark::State& state) {
   while (state.KeepRunning()) {
@@ -178,7 +179,7 @@
     state.ResumeTiming();
   }
 }
-BENCHMARK(BM_pthread_key_create);
+BIONIC_BENCHMARK(BM_pthread_key_create);
 
 static void BM_pthread_key_delete(benchmark::State& state) {
   while (state.KeepRunning()) {
@@ -190,4 +191,4 @@
     pthread_key_delete(key);
   }
 }
-BENCHMARK(BM_pthread_key_delete);
+BIONIC_BENCHMARK(BM_pthread_key_delete);
diff --git a/benchmarks/semaphore_benchmark.cpp b/benchmarks/semaphore_benchmark.cpp
index b932a2b3..a4aa7bb 100644
--- a/benchmarks/semaphore_benchmark.cpp
+++ b/benchmarks/semaphore_benchmark.cpp
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 static void BM_semaphore_sem_getvalue(benchmark::State& state) {
   sem_t semaphore;
@@ -31,7 +32,7 @@
     sem_getvalue(&semaphore, &dummy);
   }
 }
-BENCHMARK(BM_semaphore_sem_getvalue);
+BIONIC_BENCHMARK(BM_semaphore_sem_getvalue);
 
 static void BM_semaphore_sem_wait_sem_post(benchmark::State& state) {
   sem_t semaphore;
@@ -42,7 +43,7 @@
     sem_post(&semaphore);
   }
 }
-BENCHMARK(BM_semaphore_sem_wait_sem_post);
+BIONIC_BENCHMARK(BM_semaphore_sem_wait_sem_post);
 
 // This test reports the overhead of the underlying futex wake syscall on
 // the producer. It does not report the overhead from issuing the wake to the
@@ -119,7 +120,9 @@
   bool setup = false;
 };
 
-BENCHMARK_F(SemaphoreFixture, semaphore_sem_post)(benchmark::State& state) {
+// This is commented out because dynamic benchmark registering doesn't currently support fixtures.
+// Uncomment it and recompile to run this benchmark on every run.
+/* BENCHMARK_F(SemaphoreFixture, semaphore_sem_post)(benchmark::State& state) {
   while (state.KeepRunning()) {
     state.PauseTiming();
 
@@ -149,4 +152,4 @@
     param.sched_priority = 0;
     sched_setscheduler(0, SCHED_IDLE, &param);
   }
-}
+}*/
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index f496779..756a698 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -19,12 +19,7 @@
 #include <stdlib.h>
 
 #include <benchmark/benchmark.h>
-
-constexpr auto KB = 1024;
-
-#define AT_COMMON_SIZES \
-    Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(8)->Arg(16)->Arg(32)->Arg(64)->Arg(512)-> \
-    Arg(1*KB)->Arg(4*KB)->Arg(8*KB)->Arg(16*KB)->Arg(64*KB)
+#include "util.h"
 
 template <typename Fn>
 void ReadWriteTest(benchmark::State& state, Fn f, bool buffered) {
@@ -50,22 +45,22 @@
 void BM_stdio_fread(benchmark::State& state) {
   ReadWriteTest(state, fread, true);
 }
-BENCHMARK(BM_stdio_fread)->AT_COMMON_SIZES;
+BIONIC_BENCHMARK(BM_stdio_fread);
 
 void BM_stdio_fwrite(benchmark::State& state) {
   ReadWriteTest(state, fwrite, true);
 }
-BENCHMARK(BM_stdio_fwrite)->AT_COMMON_SIZES;
+BIONIC_BENCHMARK(BM_stdio_fwrite);
 
 void BM_stdio_fread_unbuffered(benchmark::State& state) {
   ReadWriteTest(state, fread, false);
 }
-BENCHMARK(BM_stdio_fread_unbuffered)->AT_COMMON_SIZES;
+BIONIC_BENCHMARK(BM_stdio_fread_unbuffered);
 
 void BM_stdio_fwrite_unbuffered(benchmark::State& state) {
   ReadWriteTest(state, fwrite, false);
 }
-BENCHMARK(BM_stdio_fwrite_unbuffered)->AT_COMMON_SIZES;
+BIONIC_BENCHMARK(BM_stdio_fwrite_unbuffered);
 
 static void FopenFgetsFclose(benchmark::State& state, bool no_locking) {
   char buf[1024];
@@ -80,9 +75,9 @@
 static void BM_stdio_fopen_fgets_fclose_locking(benchmark::State& state) {
   FopenFgetsFclose(state, false);
 }
-BENCHMARK(BM_stdio_fopen_fgets_fclose_locking);
+BIONIC_BENCHMARK(BM_stdio_fopen_fgets_fclose_locking);
 
 void BM_stdio_fopen_fgets_fclose_no_locking(benchmark::State& state) {
   FopenFgetsFclose(state, true);
 }
-BENCHMARK(BM_stdio_fopen_fgets_fclose_no_locking);
+BIONIC_BENCHMARK(BM_stdio_fopen_fgets_fclose_no_locking);
diff --git a/benchmarks/string_benchmark.cpp b/benchmarks/string_benchmark.cpp
index 2ab65a8..729b20d 100644
--- a/benchmarks/string_benchmark.cpp
+++ b/benchmarks/string_benchmark.cpp
@@ -18,27 +18,7 @@
 #include <string.h>
 
 #include <benchmark/benchmark.h>
-#include "util.h"
-
-constexpr auto KB = 1024;
-
-// NOTE: these constants are temporary replacements for AT_COMMON_SIZES until
-// the new interface for Bionic benchmarks is implemented.
-
-// Set all four to 0 to test normal alignment.
-#define AT_SRC_ALIGN 0
-#define AT_DST_ALIGN 0
-
-#define AT_ALIGNED_TWOBUF \
-    Args({(8), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
-    Args({(512), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(1*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
-    Args({(8*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(16*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
-    Args({(32*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64*KB), AT_SRC_ALIGN, AT_DST_ALIGN})
-
-#define AT_ALIGNED_ONEBUF \
-    Args({(8), AT_SRC_ALIGN})->Args({(64), AT_SRC_ALIGN})->Args({(512), AT_SRC_ALIGN})-> \
-    Args({(1*KB), AT_SRC_ALIGN})->Args({(8*KB), AT_SRC_ALIGN})->Args({(16*KB), AT_SRC_ALIGN})-> \
-    Args({(32*KB), AT_SRC_ALIGN})->Args({(64*KB), AT_SRC_ALIGN})
+#include <util.h>
 
 static void BM_string_memcmp(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -57,7 +37,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memcmp)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_memcmp);
 
 static void BM_string_memcpy(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -75,7 +55,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memcpy)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_memcpy);
 
 static void BM_string_memmove_non_overlapping(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -93,7 +73,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_non_overlapping)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_memmove_non_overlapping);
 
 static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -108,7 +88,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_ALIGNED_ONEBUF;
+BIONIC_BENCHMARK(BM_string_memmove_overlap_dst_before_src);
 
 static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -123,7 +103,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_ALIGNED_ONEBUF;
+BIONIC_BENCHMARK(BM_string_memmove_overlap_src_before_dst);
 
 static void BM_string_memset(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -138,7 +118,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memset)->AT_ALIGNED_ONEBUF;
+BIONIC_BENCHMARK(BM_string_memset);
 
 static void BM_string_strlen(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -155,7 +135,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strlen)->AT_ALIGNED_ONEBUF;
+BIONIC_BENCHMARK(BM_string_strlen);
 
 static void BM_string_strcat_copy_only(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -178,7 +158,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_copy_only)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_strcat_copy_only);
 
 static void BM_string_strcat_seek_only(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -199,7 +179,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_seek_only)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_strcat_seek_only);
 
 static void BM_string_strcat_half_copy_half_seek(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -220,7 +200,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_strcat_half_copy_half_seek);
 
 static void BM_string_strcpy(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -239,7 +219,7 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcpy)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_strcpy);
 
 static void BM_string_strcmp(benchmark::State& state) {
   const size_t nbytes = state.range(0);
@@ -260,4 +240,4 @@
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcmp)->AT_ALIGNED_TWOBUF;
+BIONIC_BENCHMARK(BM_string_strcmp);
diff --git a/benchmarks/suites/full.xml b/benchmarks/suites/full.xml
new file mode 100644
index 0000000..707a3d6
--- /dev/null
+++ b/benchmarks/suites/full.xml
@@ -0,0 +1,267 @@
+<fn>
+  <name>BM_empty</name>
+</fn>
+<fn>
+  <name>BM_load_relaxed</name>
+</fn>
+<fn>
+  <name>BM_load_acquire</name>
+</fn>
+<fn>
+  <name>BM_store_release</name>
+</fn>
+<fn>
+  <name>BM_store_seq_cst</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_relaxed</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_seq_cst</name>
+</fn>
+<fn>
+  <name>BM_acquire_fence</name>
+</fn>
+<fn>
+  <name>BM_seq_cst_fence</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_cs</name>
+</fn>
+<fn>
+  <name>BM_math_sqrt</name>
+</fn>
+<fn>
+  <name>BM_math_log10</name>
+</fn>
+<fn>
+  <name>BM_math_logb</name>
+</fn>
+<fn>
+  <name>BM_math_isfinite_macro</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isfinite</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isinf_macro</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isinf</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isnan_macro</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isnan</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isnormal_macro</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_isnormal</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_sin_fast</name>
+</fn>
+<fn>
+  <name>BM_math_sin_feupdateenv</name>
+</fn>
+<fn>
+  <name>BM_math_sin_fesetenv</name>
+</fn>
+<fn>
+  <name>BM_math_fpclassify</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_signbit_macro</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_signbit</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_fabs_macro</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_math_fabs</name>
+  <args>MATH_COMMON</args>
+</fn>
+<fn>
+  <name>BM_property_get</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_property_find</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_property_read</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_property_serial</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_pthread_self</name>
+</fn>
+<fn>
+  <name>BM_pthread_getspecific</name>
+</fn>
+<fn>
+  <name>BM_pthread_setspecific</name>
+</fn>
+<fn>
+  <name>BM_pthread_once</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock_ERRORCHECK</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock_RECURSIVE</name>
+</fn>
+<fn>
+  <name>BM_pthread_rwlock_read</name>
+</fn>
+<fn>
+  <name>BM_pthread_rwlock_write</name>
+</fn>
+<fn>
+  <name>BM_pthread_create</name>
+</fn>
+<fn>
+  <name>BM_pthread_create_and_run</name>
+</fn>
+<fn>
+  <name>BM_pthread_exit_and_join</name>
+</fn>
+<fn>
+  <name>BM_pthread_key_create</name>
+</fn>
+<fn>
+  <name>BM_pthread_key_delete</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_getvalue</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_wait_sem_post</name>
+</fn>
+<fn>
+  <name>BM_stdio_fread</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fwrite</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fread_unbuffered</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fwrite_unbuffered</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgets_fclose_locking</name>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgets_fclose_no_locking</name>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcpy</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_non_overlapping</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_overlap_dst_before_src</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_overlap_src_before_dst</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memset</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_copy_only</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_seek_only</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_half_copy_half_seek</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcpy</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime</name>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime_syscall</name>
+</fn>
+<fn>
+  <name>BM_time_gettimeofday</name>
+</fn>
+<fn>
+  <name>BM_time_gettimeofday_syscall</name>
+</fn>
+<fn>
+  <name>BM_time_time</name>
+</fn>
+<fn>
+  <name>BM_time_localtime</name>
+</fn>
+<fn>
+  <name>BM_time_localtime_r</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid_syscall</name>
+</fn>
+<fn>
+  <name>BM_unistd_gettid</name>
+</fn>
+<fn>
+  <name>BM_unistd_gettid_syscall</name>
+</fn>
diff --git a/benchmarks/suites/host.xml b/benchmarks/suites/host.xml
new file mode 100644
index 0000000..c4d0d3a
--- /dev/null
+++ b/benchmarks/suites/host.xml
@@ -0,0 +1,244 @@
+<fn>
+  <name>BM_empty</name>
+</fn>
+<fn>
+  <name>BM_load_relaxed</name>
+</fn>
+<fn>
+  <name>BM_load_acquire</name>
+</fn>
+<fn>
+  <name>BM_store_release</name>
+</fn>
+<fn>
+  <name>BM_store_seq_cst</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_relaxed</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_seq_cst</name>
+</fn>
+<fn>
+  <name>BM_acquire_fence</name>
+</fn>
+<fn>
+  <name>BM_seq_cst_fence</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_cs</name>
+</fn>
+<fn>
+  <name>BM_math_sqrt</name>
+</fn>
+<fn>
+  <name>BM_math_log10</name>
+</fn>
+<fn>
+  <name>BM_math_logb</name>
+</fn>
+<fn>
+  <name>BM_math_isfinite_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isfinite</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isinf_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isinf</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnan_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnan</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnormal_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_sin_fast</name>
+</fn>
+<fn>
+  <name>BM_math_sin_feupdateenv</name>
+</fn>
+<fn>
+  <name>BM_math_sin_fesetenv</name>
+</fn>
+<fn>
+  <name>BM_math_fpclassify</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_signbit_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_signbit</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_fabs_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_fabs</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_pthread_self</name>
+</fn>
+<fn>
+  <name>BM_pthread_getspecific</name>
+</fn>
+<fn>
+  <name>BM_pthread_setspecific</name>
+</fn>
+<fn>
+  <name>BM_pthread_once</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock_ERRORCHECK</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock_RECURSIVE</name>
+</fn>
+<fn>
+  <name>BM_pthread_rwlock_read</name>
+</fn>
+<fn>
+  <name>BM_pthread_rwlock_write</name>
+</fn>
+<fn>
+  <name>BM_pthread_create</name>
+</fn>
+<fn>
+  <name>BM_pthread_create_and_run</name>
+</fn>
+<fn>
+  <name>BM_pthread_exit_and_join</name>
+</fn>
+<fn>
+  <name>BM_pthread_key_create</name>
+</fn>
+<fn>
+  <name>BM_pthread_key_delete</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_getvalue</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_wait_sem_post</name>
+</fn>
+<fn>
+  <name>BM_stdio_fread</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fwrite</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fread_unbuffered</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fwrite_unbuffered</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgets_fclose_locking</name>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgets_fclose_no_locking</name>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcpy</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_non_overlapping</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_overlap_dst_before_src</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_overlap_src_before_dst</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memset</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_copy_only</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_seek_only</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_half_copy_half_seek</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcpy</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime</name>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime_syscall</name>
+</fn>
+<fn>
+  <name>BM_time_gettimeofday</name>
+</fn>
+<fn>
+  <name>BM_time_gettimeofday_syscall</name>
+</fn>
+<fn>
+  <name>BM_time_time</name>
+</fn>
+<fn>
+  <name>BM_time_localtime</name>
+</fn>
+<fn>
+  <name>BM_time_localtime_r</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid_syscall</name>
+</fn>
+<fn>
+  <name>BM_unistd_gettid_syscall</name>
+</fn>
diff --git a/benchmarks/suites/test_alignment.xml b/benchmarks/suites/test_alignment.xml
new file mode 100644
index 0000000..20df320
--- /dev/null
+++ b/benchmarks/suites/test_alignment.xml
@@ -0,0 +1,50 @@
+<fn>
+  <name>BM_string_memcmp</name>
+  <iterations>1</iterations>
+  <args>AT_2_ALIGN_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <iterations>1</iterations>
+  <args>AT_4_ALIGN_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <iterations>1</iterations>
+  <args>AT_16_ALIGN_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <iterations>1</iterations>
+  <args>AT_512_ALIGN_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <iterations>1</iterations>
+  <args>AT_2048_ALIGN_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <iterations>1</iterations>
+  <args>AT_2_ALIGN_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <iterations>1</iterations>
+  <args>AT_4_ALIGN_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <iterations>1</iterations>
+  <args>AT_16_ALIGN_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <iterations>1</iterations>
+  <args>AT_512_ALIGN_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <iterations>1</iterations>
+  <args>AT_2048_ALIGN_ONEBUF</args>
+</fn>
diff --git a/benchmarks/suites/test_from_each.xml b/benchmarks/suites/test_from_each.xml
new file mode 100644
index 0000000..0118365
--- /dev/null
+++ b/benchmarks/suites/test_from_each.xml
@@ -0,0 +1,30 @@
+<fn>
+  <name>BM_empty</name>
+</fn>
+<fn>
+  <name>BM_math_sqrt</name>
+</fn>
+<fn>
+  <name>BM_property_get</name>
+  <args>1</args>
+</fn>
+<fn>
+  <name>BM_pthread_self</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_getvalue</name>
+</fn>
+<fn>
+  <name>BM_stdio_fread</name>
+  <args>64</args>
+</fn>
+<fn>
+  <name>BM_string_memcpy</name>
+  <args>512 4 4</args>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid</name>
+</fn>
diff --git a/benchmarks/suites/test_full.xml b/benchmarks/suites/test_full.xml
new file mode 100644
index 0000000..f9d97ee
--- /dev/null
+++ b/benchmarks/suites/test_full.xml
@@ -0,0 +1,261 @@
+<fn>
+  <name>BM_empty</name>
+</fn>
+<fn>
+  <name>BM_load_relaxed</name>
+</fn>
+<fn>
+  <name>BM_load_acquire</name>
+</fn>
+<fn>
+  <name>BM_store_release</name>
+</fn>
+<fn>
+  <name>BM_store_seq_cst</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_relaxed</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_seq_cst</name>
+</fn>
+<fn>
+  <name>BM_acquire_fence</name>
+</fn>
+<fn>
+  <name>BM_seq_cst_fence</name>
+</fn>
+<fn>
+  <name>BM_fetch_add_cs</name>
+</fn>
+<fn>
+  <name>BM_math_sqrt</name>
+</fn>
+<fn>
+  <name>BM_math_log10</name>
+</fn>
+<fn>
+  <name>BM_math_logb</name>
+</fn>
+<fn>
+  <name>BM_math_isfinite_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isfinite</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isinf_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isinf</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnan_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnan</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnormal_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_isnormal</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_sin_fast</name>
+</fn>
+<fn>
+  <name>BM_math_sin_feupdateenv</name>
+</fn>
+<fn>
+  <name>BM_math_sin_fesetenv</name>
+</fn>
+<fn>
+  <name>BM_math_fpclassify</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_signbit_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_signbit</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_fabs_macro</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_math_fabs</name>
+  <args>0</args>
+</fn>
+<fn>
+  <name>BM_property_get</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_property_find</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_property_read</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_property_serial</name>
+  <args>NUM_PROPS</args>
+</fn>
+<fn>
+  <name>BM_pthread_self</name>
+</fn>
+<fn>
+  <name>BM_pthread_getspecific</name>
+</fn>
+<fn>
+  <name>BM_pthread_setspecific</name>
+</fn>
+<fn>
+  <name>BM_pthread_once</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock_ERRORCHECK</name>
+</fn>
+<fn>
+  <name>BM_pthread_mutex_lock_RECURSIVE</name>
+</fn>
+<fn>
+  <name>BM_pthread_rwlock_read</name>
+</fn>
+<fn>
+  <name>BM_pthread_rwlock_write</name>
+</fn>
+<fn>
+  <name>BM_pthread_create</name>
+</fn>
+<fn>
+  <name>BM_pthread_create_and_run</name>
+</fn>
+<fn>
+  <name>BM_pthread_exit_and_join</name>
+</fn>
+<fn>
+  <name>BM_pthread_key_create</name>
+</fn>
+<fn>
+  <name>BM_pthread_key_delete</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_getvalue</name>
+</fn>
+<fn>
+  <name>BM_semaphore_sem_wait_sem_post</name>
+</fn>
+<fn>
+  <name>BM_stdio_fread</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fwrite</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fread_unbuffered</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fwrite_unbuffered</name>
+  <args>AT_COMMON_SIZES</args>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgets_fclose_locking</name>
+</fn>
+<fn>
+  <name>BM_stdio_fopen_fgets_fclose_no_locking</name>
+</fn>
+<fn>
+  <name>BM_string_memcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memcpy</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_non_overlapping</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_overlap_dst_before_src</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memmove_overlap_src_before_dst</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_memset</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strlen</name>
+  <args>AT_ALIGNED_ONEBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_copy_only</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_seek_only</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcat_half_copy_half_seek</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcpy</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_string_strcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime</name>
+</fn>
+<fn>
+  <name>BM_time_clock_gettime_syscall</name>
+</fn>
+<fn>
+  <name>BM_time_gettimeofday</name>
+</fn>
+<fn>
+  <name>BM_time_gettimeofday_syscall</name>
+</fn>
+<fn>
+  <name>BM_time_time</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid</name>
+</fn>
+<fn>
+  <name>BM_unistd_getpid_syscall</name>
+</fn>
+<fn>
+  <name>BM_unistd_gettid</name>
+</fn>
+<fn>
+  <name>BM_unistd_gettid_syscall</name>
+</fn>
diff --git a/benchmarks/suites/test_medium.xml b/benchmarks/suites/test_medium.xml
new file mode 100644
index 0000000..9528af3
--- /dev/null
+++ b/benchmarks/suites/test_medium.xml
@@ -0,0 +1,16 @@
+<fn>
+  <name>BM_string_memcmp</name>
+  <args>AT_ALIGNED_TWOBUF</args>
+</fn>
+<fn>
+  <name>BM_math_sqrt</name>
+</fn>
+<fn>
+  <name>BM_string_memcpy</name>
+  <iterations>25</iterations>
+  <args>512 4 4</args>
+</fn>
+<fn>
+  <name>BM_property_get</name>
+  <args>1</args>
+</fn>
diff --git a/benchmarks/suites/test_small.xml b/benchmarks/suites/test_small.xml
new file mode 100644
index 0000000..a4cc285
--- /dev/null
+++ b/benchmarks/suites/test_small.xml
@@ -0,0 +1,11 @@
+<fn>
+  <name>BM_string_memcmp</name>
+  <args>8 8 8</args>
+</fn>
+<fn>
+  <name>BM_math_sqrt</name>
+</fn>
+<fn>
+  <name>BM_property_get</name>
+  <args>1</args>
+</fn>
diff --git a/benchmarks/tests/interface_test.cpp b/benchmarks/tests/interface_test.cpp
new file mode 100644
index 0000000..a9e3031
--- /dev/null
+++ b/benchmarks/tests/interface_test.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 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 <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <regex>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+class SystemTests : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    raw_output_ = "";
+    sanitized_output_ = "";
+    exitcode_ = 0;
+  }
+
+  void SanitizeOutput();
+
+  void Exec(std::vector<const char*> args);
+  void ExecAndCapture(std::vector<const char*> args);
+  void RunTest(std::vector<const char*> extra_args = {});
+  void Verify(const std::string& expected_output, int expected_exitcode,
+              std::vector<const char*> extra_args = {});
+
+  std::string raw_output_;
+  std::string sanitized_output_;
+  int exitcode_;
+  pid_t pid_;
+  int fd_;
+};
+
+void SystemTests::SanitizeOutput() {
+  // Cut off anything after the arguments, since that varies with time.
+  sanitized_output_ = std::regex_replace(raw_output_, std::regex(".+(BM_\\S+) +.+"), "$1");
+
+  // Remove everything before the header.
+  sanitized_output_.erase(0, sanitized_output_.find("------------------------------------------------"));
+
+  // Remove the header.
+  sanitized_output_.erase(0, sanitized_output_.find("BM_"));
+
+  // Remove any hanging output.
+  sanitized_output_.erase(sanitized_output_.find_last_of("BM_\\S+\n") + 1);
+}
+
+static void GetExe(std::string* exe_name) {
+  char path[PATH_MAX];
+  ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
+  ASSERT_TRUE(path_len >= 0);
+  *exe_name = std::string(std::regex_replace(path, std::regex("-tests"), ""));
+}
+
+void SystemTests::Exec(std::vector<const char*> args) {
+  int fds[2];
+  ASSERT_NE(-1, pipe(fds));
+  ASSERT_NE(-1, fcntl(fds[0], F_SETFL, O_NONBLOCK));
+
+  if ((pid_ = fork()) == 0) {
+    // Run the test.
+    close(fds[0]);
+    close(STDIN_FILENO);
+    close(STDOUT_FILENO);
+    close(STDERR_FILENO);
+    ASSERT_NE(0, dup2(fds[1], STDOUT_FILENO));
+    ASSERT_NE(0, dup2(fds[1], STDERR_FILENO));
+    close(fds[1]);
+
+    std::string exe_name;
+    GetExe(&exe_name);
+    args.insert(args.begin(), exe_name.c_str());
+    args.push_back(nullptr);
+    execv(args[0], reinterpret_cast<char* const*>(const_cast<char**>(args.data())));
+    exit(1);
+  }
+  ASSERT_NE(-1, pid_);
+
+  close(fds[1]);
+  fd_ = fds[0];
+}
+
+void SystemTests::Verify(const std::string& expected_output,
+                         int expected_exitcode, std::vector<const char*> extra_args) {
+  std::vector<const char*> args;
+  for (const auto& arg : extra_args) {
+    args.push_back(arg);
+  }
+
+  Exec(args);
+
+  raw_output_ = "";
+  while (true) {
+    char buffer[4097];
+    ssize_t bytes = TEMP_FAILURE_RETRY(read(fd_, buffer, sizeof(buffer) - 1));
+    if (bytes == -1 && errno == EAGAIN) {
+      continue;
+    }
+    ASSERT_NE(-1, bytes);
+    if (bytes == 0) {
+      break;
+    }
+    buffer[bytes] = '\0';
+    raw_output_ += buffer;
+  }
+  close(fd_);
+
+  int status;
+  ASSERT_EQ(pid_, TEMP_FAILURE_RETRY(waitpid(pid_, &status, 0))) << "Test output:\n" << raw_output_;
+  exitcode_ = WEXITSTATUS(status);
+  SanitizeOutput();
+
+  ASSERT_EQ(expected_exitcode, exitcode_) << "Test output:\n" << raw_output_;
+  if (!expected_output.empty()) {
+    ASSERT_EQ(expected_output, sanitized_output_);
+  }
+
+}
+
+TEST_F(SystemTests, full_suite) {
+  std::string expected =
+    "BM_empty/iterations:1\n"
+    "BM_load_relaxed/iterations:1\n"
+    "BM_load_acquire/iterations:1\n"
+    "BM_store_release/iterations:1\n"
+    "BM_store_seq_cst/iterations:1\n"
+    "BM_fetch_add_relaxed/iterations:1\n"
+    "BM_fetch_add_seq_cst/iterations:1\n"
+    "BM_acquire_fence/iterations:1\n"
+    "BM_seq_cst_fence/iterations:1\n"
+    "BM_fetch_add_cs/iterations:1\n"
+    "BM_math_sqrt/iterations:1\n"
+    "BM_math_log10/iterations:1\n"
+    "BM_math_logb/iterations:1\n"
+    "BM_math_isfinite_macro/0/iterations:1\n"
+    "BM_math_isfinite/0/iterations:1\n"
+    "BM_math_isinf_macro/0/iterations:1\n"
+    "BM_math_isinf/0/iterations:1\n"
+    "BM_math_isnan_macro/0/iterations:1\n"
+    "BM_math_isnan/0/iterations:1\n"
+    "BM_math_isnormal_macro/0/iterations:1\n"
+    "BM_math_isnormal/0/iterations:1\n"
+    "BM_math_sin_fast/iterations:1\n"
+    "BM_math_sin_feupdateenv/iterations:1\n"
+    "BM_math_sin_fesetenv/iterations:1\n"
+    "BM_math_fpclassify/0/iterations:1\n"
+    "BM_math_signbit_macro/0/iterations:1\n"
+    "BM_math_signbit/0/iterations:1\n"
+    "BM_math_fabs_macro/0/iterations:1\n"
+    "BM_math_fabs/0/iterations:1\n"
+    "BM_property_get/1/iterations:1\n"
+    "BM_property_get/4/iterations:1\n"
+    "BM_property_get/16/iterations:1\n"
+    "BM_property_get/64/iterations:1\n"
+    "BM_property_get/128/iterations:1\n"
+    "BM_property_get/256/iterations:1\n"
+    "BM_property_get/512/iterations:1\n"
+    "BM_property_find/1/iterations:1\n"
+    "BM_property_find/4/iterations:1\n"
+    "BM_property_find/16/iterations:1\n"
+    "BM_property_find/64/iterations:1\n"
+    "BM_property_find/128/iterations:1\n"
+    "BM_property_find/256/iterations:1\n"
+    "BM_property_find/512/iterations:1\n"
+    "BM_property_read/1/iterations:1\n"
+    "BM_property_read/4/iterations:1\n"
+    "BM_property_read/16/iterations:1\n"
+    "BM_property_read/64/iterations:1\n"
+    "BM_property_read/128/iterations:1\n"
+    "BM_property_read/256/iterations:1\n"
+    "BM_property_read/512/iterations:1\n"
+    "BM_property_serial/1/iterations:1\n"
+    "BM_property_serial/4/iterations:1\n"
+    "BM_property_serial/16/iterations:1\n"
+    "BM_property_serial/64/iterations:1\n"
+    "BM_property_serial/128/iterations:1\n"
+    "BM_property_serial/256/iterations:1\n"
+    "BM_property_serial/512/iterations:1\n"
+    "BM_pthread_self/iterations:1\n"
+    "BM_pthread_getspecific/iterations:1\n"
+    "BM_pthread_setspecific/iterations:1\n"
+    "BM_pthread_once/iterations:1\n"
+    "BM_pthread_mutex_lock/iterations:1\n"
+    "BM_pthread_mutex_lock_ERRORCHECK/iterations:1\n"
+    "BM_pthread_mutex_lock_RECURSIVE/iterations:1\n"
+    "BM_pthread_rwlock_read/iterations:1\n"
+    "BM_pthread_rwlock_write/iterations:1\n"
+    "BM_pthread_create/iterations:1\n"
+    "BM_pthread_create_and_run/iterations:1\n"
+    "BM_pthread_exit_and_join/iterations:1\n"
+    "BM_pthread_key_create/iterations:1\n"
+    "BM_pthread_key_delete/iterations:1\n"
+    "BM_semaphore_sem_getvalue/iterations:1\n"
+    "BM_semaphore_sem_wait_sem_post/iterations:1\n"
+    "BM_stdio_fread/8/iterations:1\n"
+    "BM_stdio_fread/64/iterations:1\n"
+    "BM_stdio_fread/512/iterations:1\n"
+    "BM_stdio_fread/1024/iterations:1\n"
+    "BM_stdio_fread/8192/iterations:1\n"
+    "BM_stdio_fread/16384/iterations:1\n"
+    "BM_stdio_fread/32768/iterations:1\n"
+    "BM_stdio_fread/65536/iterations:1\n"
+    "BM_stdio_fwrite/8/iterations:1\n"
+    "BM_stdio_fwrite/64/iterations:1\n"
+    "BM_stdio_fwrite/512/iterations:1\n"
+    "BM_stdio_fwrite/1024/iterations:1\n"
+    "BM_stdio_fwrite/8192/iterations:1\n"
+    "BM_stdio_fwrite/16384/iterations:1\n"
+    "BM_stdio_fwrite/32768/iterations:1\n"
+    "BM_stdio_fwrite/65536/iterations:1\n"
+    "BM_stdio_fread_unbuffered/8/iterations:1\n"
+    "BM_stdio_fread_unbuffered/64/iterations:1\n"
+    "BM_stdio_fread_unbuffered/512/iterations:1\n"
+    "BM_stdio_fread_unbuffered/1024/iterations:1\n"
+    "BM_stdio_fread_unbuffered/8192/iterations:1\n"
+    "BM_stdio_fread_unbuffered/16384/iterations:1\n"
+    "BM_stdio_fread_unbuffered/32768/iterations:1\n"
+    "BM_stdio_fread_unbuffered/65536/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/8/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/64/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/512/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/1024/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/8192/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/16384/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/32768/iterations:1\n"
+    "BM_stdio_fwrite_unbuffered/65536/iterations:1\n"
+    "BM_stdio_fopen_fgets_fclose_locking/iterations:1\n"
+    "BM_stdio_fopen_fgets_fclose_no_locking/iterations:1\n"
+    "BM_string_memcmp/8/0/0/iterations:1\n"
+    "BM_string_memcmp/64/0/0/iterations:1\n"
+    "BM_string_memcmp/512/0/0/iterations:1\n"
+    "BM_string_memcmp/1024/0/0/iterations:1\n"
+    "BM_string_memcmp/8192/0/0/iterations:1\n"
+    "BM_string_memcmp/16384/0/0/iterations:1\n"
+    "BM_string_memcmp/32768/0/0/iterations:1\n"
+    "BM_string_memcmp/65536/0/0/iterations:1\n"
+    "BM_string_memcpy/8/0/0/iterations:1\n"
+    "BM_string_memcpy/64/0/0/iterations:1\n"
+    "BM_string_memcpy/512/0/0/iterations:1\n"
+    "BM_string_memcpy/1024/0/0/iterations:1\n"
+    "BM_string_memcpy/8192/0/0/iterations:1\n"
+    "BM_string_memcpy/16384/0/0/iterations:1\n"
+    "BM_string_memcpy/32768/0/0/iterations:1\n"
+    "BM_string_memcpy/65536/0/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/8/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/64/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/512/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/1024/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/8192/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/16384/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/32768/0/iterations:1\n"
+    "BM_string_memmove_non_overlapping/65536/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/8/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/64/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/512/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/1024/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/8192/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/16384/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/32768/0/iterations:1\n"
+    "BM_string_memmove_overlap_dst_before_src/65536/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/8/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/64/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/512/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/1024/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/8192/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/16384/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/32768/0/iterations:1\n"
+    "BM_string_memmove_overlap_src_before_dst/65536/0/iterations:1\n"
+    "BM_string_memset/8/0/iterations:1\n"
+    "BM_string_memset/64/0/iterations:1\n"
+    "BM_string_memset/512/0/iterations:1\n"
+    "BM_string_memset/1024/0/iterations:1\n"
+    "BM_string_memset/8192/0/iterations:1\n"
+    "BM_string_memset/16384/0/iterations:1\n"
+    "BM_string_memset/32768/0/iterations:1\n"
+    "BM_string_memset/65536/0/iterations:1\n"
+    "BM_string_strlen/8/0/iterations:1\n"
+    "BM_string_strlen/64/0/iterations:1\n"
+    "BM_string_strlen/512/0/iterations:1\n"
+    "BM_string_strlen/1024/0/iterations:1\n"
+    "BM_string_strlen/8192/0/iterations:1\n"
+    "BM_string_strlen/16384/0/iterations:1\n"
+    "BM_string_strlen/32768/0/iterations:1\n"
+    "BM_string_strlen/65536/0/iterations:1\n"
+    "BM_string_strcat_copy_only/8/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/64/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/512/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/1024/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/8192/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/16384/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/32768/0/0/iterations:1\n"
+    "BM_string_strcat_copy_only/65536/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/8/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/64/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/512/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/1024/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/8192/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/16384/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/32768/0/0/iterations:1\n"
+    "BM_string_strcat_seek_only/65536/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/8/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/64/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/512/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/1024/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/8192/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/16384/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/32768/0/0/iterations:1\n"
+    "BM_string_strcat_half_copy_half_seek/65536/0/0/iterations:1\n"
+    "BM_string_strcpy/8/0/0/iterations:1\n"
+    "BM_string_strcpy/64/0/0/iterations:1\n"
+    "BM_string_strcpy/512/0/0/iterations:1\n"
+    "BM_string_strcpy/1024/0/0/iterations:1\n"
+    "BM_string_strcpy/8192/0/0/iterations:1\n"
+    "BM_string_strcpy/16384/0/0/iterations:1\n"
+    "BM_string_strcpy/32768/0/0/iterations:1\n"
+    "BM_string_strcpy/65536/0/0/iterations:1\n"
+    "BM_string_strcmp/8/0/0/iterations:1\n"
+    "BM_string_strcmp/64/0/0/iterations:1\n"
+    "BM_string_strcmp/512/0/0/iterations:1\n"
+    "BM_string_strcmp/1024/0/0/iterations:1\n"
+    "BM_string_strcmp/8192/0/0/iterations:1\n"
+    "BM_string_strcmp/16384/0/0/iterations:1\n"
+    "BM_string_strcmp/32768/0/0/iterations:1\n"
+    "BM_string_strcmp/65536/0/0/iterations:1\n"
+    "BM_time_clock_gettime/iterations:1\n"
+    "BM_time_clock_gettime_syscall/iterations:1\n"
+    "BM_time_gettimeofday/iterations:1\n"
+    "BM_time_gettimeofday_syscall/iterations:1\n"
+    "BM_time_time/iterations:1\n"
+    "BM_unistd_getpid/iterations:1\n"
+    "BM_unistd_getpid_syscall/iterations:1\n"
+    "BM_unistd_gettid/iterations:1\n"
+    "BM_unistd_gettid_syscall/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_full.xml",
+                                                "--bionic_iterations=1"});
+}
+
+TEST_F(SystemTests, small) {
+  std::string expected =
+    "BM_string_memcmp/8/8/8\n"
+    "BM_math_sqrt\n"
+    "BM_property_get/1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_small.xml"});
+}
+
+TEST_F(SystemTests, medium) {
+  std::string expected =
+    "BM_string_memcmp/8/0/0/iterations:1\n"
+    "BM_string_memcmp/64/0/0/iterations:1\n"
+    "BM_string_memcmp/512/0/0/iterations:1\n"
+    "BM_string_memcmp/1024/0/0/iterations:1\n"
+    "BM_string_memcmp/8192/0/0/iterations:1\n"
+    "BM_string_memcmp/16384/0/0/iterations:1\n"
+    "BM_string_memcmp/32768/0/0/iterations:1\n"
+    "BM_string_memcmp/65536/0/0/iterations:1\n"
+    "BM_math_sqrt/iterations:1\n"
+    "BM_string_memcpy/512/4/4/iterations:25\n"
+    "BM_property_get/1/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_medium.xml",
+                                                "--bionic_iterations=1"});
+}
+
+TEST_F(SystemTests, from_each) {
+  std::string expected =
+    "BM_empty/iterations:1\n"
+    "BM_math_sqrt/iterations:1\n"
+    "BM_property_get/1/iterations:1\n"
+    "BM_pthread_self/iterations:1\n"
+    "BM_semaphore_sem_getvalue/iterations:1\n"
+    "BM_stdio_fread/64/iterations:1\n"
+    "BM_string_memcpy/512/4/4/iterations:1\n"
+    "BM_time_clock_gettime/iterations:1\n"
+    "BM_unistd_getpid/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_from_each.xml",
+                                                "--bionic_iterations=1"});
+}
+
+TEST_F(SystemTests, cmd_args) {
+  std::string expected =
+    "BM_string_memcpy/8/8/8/iterations:1\n"
+    "BM_math_log10/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_extra=BM_string_memcpy 8 8 8",
+                                                "--bionic_extra=BM_math_log10",
+                                                "--bionic_iterations=1"});
+}
+
+TEST_F(SystemTests, cmd_args_no_iter) {
+  std::string expected =
+    "BM_string_memcpy/8/8/8\n"
+    "BM_math_log10\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_extra=BM_string_memcpy 8 8 8",
+                                                "--bionic_extra=BM_math_log10"});
+}
+
+TEST_F(SystemTests, xml_and_args) {
+  std::string expected =
+    "BM_string_memcmp/8/0/0/iterations:1\n"
+    "BM_string_memcmp/64/0/0/iterations:1\n"
+    "BM_string_memcmp/512/0/0/iterations:1\n"
+    "BM_string_memcmp/1024/0/0/iterations:1\n"
+    "BM_string_memcmp/8192/0/0/iterations:1\n"
+    "BM_string_memcmp/16384/0/0/iterations:1\n"
+    "BM_string_memcmp/32768/0/0/iterations:1\n"
+    "BM_string_memcmp/65536/0/0/iterations:1\n"
+    "BM_math_sqrt/iterations:1\n"
+    "BM_string_memcpy/512/4/4/iterations:25\n"
+    "BM_property_get/1/iterations:1\n"
+    "BM_string_memcpy/8/0/0/iterations:1\n"
+    "BM_string_memcpy/64/0/0/iterations:1\n"
+    "BM_string_memcpy/512/0/0/iterations:1\n"
+    "BM_string_memcpy/1024/0/0/iterations:1\n"
+    "BM_string_memcpy/8192/0/0/iterations:1\n"
+    "BM_string_memcpy/16384/0/0/iterations:1\n"
+    "BM_string_memcpy/32768/0/0/iterations:1\n"
+    "BM_string_memcpy/65536/0/0/iterations:1\n"
+    "BM_math_log10/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_extra=BM_string_memcpy AT_ALIGNED_TWOBUF",
+                                                "--bionic_extra=BM_math_log10",
+                                                "--bionic_cpu -1",
+                                                "--bionic_xml=suites/test_medium.xml",
+                                                "--bionic_iterations=1"});
+}
+
+TEST_F(SystemTests, alignment) {
+  std::string expected =
+    "BM_string_memcmp/8/2/2/iterations:1\n"
+    "BM_string_memcmp/64/2/2/iterations:1\n"
+    "BM_string_memcmp/512/2/2/iterations:1\n"
+    "BM_string_memcmp/1024/2/2/iterations:1\n"
+    "BM_string_memcmp/8192/2/2/iterations:1\n"
+    "BM_string_memcmp/16384/2/2/iterations:1\n"
+    "BM_string_memcmp/32768/2/2/iterations:1\n"
+    "BM_string_memcmp/65536/2/2/iterations:1\n"
+    "BM_string_memcmp/8/4/4/iterations:1\n"
+    "BM_string_memcmp/64/4/4/iterations:1\n"
+    "BM_string_memcmp/512/4/4/iterations:1\n"
+    "BM_string_memcmp/1024/4/4/iterations:1\n"
+    "BM_string_memcmp/8192/4/4/iterations:1\n"
+    "BM_string_memcmp/16384/4/4/iterations:1\n"
+    "BM_string_memcmp/32768/4/4/iterations:1\n"
+    "BM_string_memcmp/65536/4/4/iterations:1\n"
+    "BM_string_memcmp/8/16/16/iterations:1\n"
+    "BM_string_memcmp/64/16/16/iterations:1\n"
+    "BM_string_memcmp/512/16/16/iterations:1\n"
+    "BM_string_memcmp/1024/16/16/iterations:1\n"
+    "BM_string_memcmp/8192/16/16/iterations:1\n"
+    "BM_string_memcmp/16384/16/16/iterations:1\n"
+    "BM_string_memcmp/32768/16/16/iterations:1\n"
+    "BM_string_memcmp/65536/16/16/iterations:1\n"
+    "BM_string_memcmp/8/512/512/iterations:1\n"
+    "BM_string_memcmp/64/512/512/iterations:1\n"
+    "BM_string_memcmp/512/512/512/iterations:1\n"
+    "BM_string_memcmp/1024/512/512/iterations:1\n"
+    "BM_string_memcmp/8192/512/512/iterations:1\n"
+    "BM_string_memcmp/16384/512/512/iterations:1\n"
+    "BM_string_memcmp/32768/512/512/iterations:1\n"
+    "BM_string_memcmp/65536/512/512/iterations:1\n"
+    "BM_string_memcmp/8/2048/2048/iterations:1\n"
+    "BM_string_memcmp/64/2048/2048/iterations:1\n"
+    "BM_string_memcmp/512/2048/2048/iterations:1\n"
+    "BM_string_memcmp/1024/2048/2048/iterations:1\n"
+    "BM_string_memcmp/8192/2048/2048/iterations:1\n"
+    "BM_string_memcmp/16384/2048/2048/iterations:1\n"
+    "BM_string_memcmp/32768/2048/2048/iterations:1\n"
+    "BM_string_memcmp/65536/2048/2048/iterations:1\n"
+    "BM_string_strlen/8/2/iterations:1\n"
+    "BM_string_strlen/64/2/iterations:1\n"
+    "BM_string_strlen/512/2/iterations:1\n"
+    "BM_string_strlen/1024/2/iterations:1\n"
+    "BM_string_strlen/8192/2/iterations:1\n"
+    "BM_string_strlen/16384/2/iterations:1\n"
+    "BM_string_strlen/32768/2/iterations:1\n"
+    "BM_string_strlen/65536/2/iterations:1\n"
+    "BM_string_strlen/8/4/iterations:1\n"
+    "BM_string_strlen/64/4/iterations:1\n"
+    "BM_string_strlen/512/4/iterations:1\n"
+    "BM_string_strlen/1024/4/iterations:1\n"
+    "BM_string_strlen/8192/4/iterations:1\n"
+    "BM_string_strlen/16384/4/iterations:1\n"
+    "BM_string_strlen/32768/4/iterations:1\n"
+    "BM_string_strlen/65536/4/iterations:1\n"
+    "BM_string_strlen/8/16/iterations:1\n"
+    "BM_string_strlen/64/16/iterations:1\n"
+    "BM_string_strlen/512/16/iterations:1\n"
+    "BM_string_strlen/1024/16/iterations:1\n"
+    "BM_string_strlen/8192/16/iterations:1\n"
+    "BM_string_strlen/16384/16/iterations:1\n"
+    "BM_string_strlen/32768/16/iterations:1\n"
+    "BM_string_strlen/65536/16/iterations:1\n"
+    "BM_string_strlen/8/512/iterations:1\n"
+    "BM_string_strlen/64/512/iterations:1\n"
+    "BM_string_strlen/512/512/iterations:1\n"
+    "BM_string_strlen/1024/512/iterations:1\n"
+    "BM_string_strlen/8192/512/iterations:1\n"
+    "BM_string_strlen/16384/512/iterations:1\n"
+    "BM_string_strlen/32768/512/iterations:1\n"
+    "BM_string_strlen/65536/512/iterations:1\n"
+    "BM_string_strlen/8/2048/iterations:1\n"
+    "BM_string_strlen/64/2048/iterations:1\n"
+    "BM_string_strlen/512/2048/iterations:1\n"
+    "BM_string_strlen/1024/2048/iterations:1\n"
+    "BM_string_strlen/8192/2048/iterations:1\n"
+    "BM_string_strlen/16384/2048/iterations:1\n"
+    "BM_string_strlen/32768/2048/iterations:1\n"
+    "BM_string_strlen/65536/2048/iterations:1\n";
+  Verify(expected, 0, std::vector<const char *>{"--bionic_xml=suites/test_alignment.xml",
+                                                "--bionic_iterations=100"});
+}
diff --git a/benchmarks/time_benchmark.cpp b/benchmarks/time_benchmark.cpp
index c90dfad..4c6d5dd 100644
--- a/benchmarks/time_benchmark.cpp
+++ b/benchmarks/time_benchmark.cpp
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 static void BM_time_clock_gettime(benchmark::State& state) {
   timespec t;
@@ -27,7 +28,7 @@
     clock_gettime(CLOCK_MONOTONIC, &t);
   }
 }
-BENCHMARK(BM_time_clock_gettime);
+BIONIC_BENCHMARK(BM_time_clock_gettime);
 
 static void BM_time_clock_gettime_syscall(benchmark::State& state) {
   timespec t;
@@ -35,7 +36,7 @@
     syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &t);
   }
 }
-BENCHMARK(BM_time_clock_gettime_syscall);
+BIONIC_BENCHMARK(BM_time_clock_gettime_syscall);
 
 static void BM_time_gettimeofday(benchmark::State& state) {
   timeval tv;
@@ -43,7 +44,7 @@
     gettimeofday(&tv, nullptr);
   }
 }
-BENCHMARK(BM_time_gettimeofday);
+BIONIC_BENCHMARK(BM_time_gettimeofday);
 
 void BM_time_gettimeofday_syscall(benchmark::State& state) {
   timeval tv;
@@ -51,14 +52,14 @@
     syscall(__NR_gettimeofday, &tv, nullptr);
   }
 }
-BENCHMARK(BM_time_gettimeofday_syscall);
+BIONIC_BENCHMARK(BM_time_gettimeofday_syscall);
 
 void BM_time_time(benchmark::State& state) {
   while (state.KeepRunning()) {
     time(nullptr);
   }
 }
-BENCHMARK(BM_time_time);
+BIONIC_BENCHMARK(BM_time_time);
 
 void BM_time_localtime(benchmark::State& state) {
   time_t t = time(nullptr);
@@ -66,7 +67,7 @@
     localtime(&t);
   }
 }
-BENCHMARK(BM_time_localtime);
+BIONIC_BENCHMARK(BM_time_localtime);
 
 void BM_time_localtime_r(benchmark::State& state) {
   time_t t = time(nullptr);
@@ -75,4 +76,4 @@
     localtime_r(&t, &tm);
   }
 }
-BENCHMARK(BM_time_localtime_r);
+BIONIC_BENCHMARK(BM_time_localtime_r);
diff --git a/benchmarks/unistd_benchmark.cpp b/benchmarks/unistd_benchmark.cpp
index b78d3eb..98e8858 100644
--- a/benchmarks/unistd_benchmark.cpp
+++ b/benchmarks/unistd_benchmark.cpp
@@ -18,20 +18,21 @@
 #include <unistd.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 static void BM_unistd_getpid(benchmark::State& state) {
   while (state.KeepRunning()) {
     getpid();
   }
 }
-BENCHMARK(BM_unistd_getpid);
+BIONIC_BENCHMARK(BM_unistd_getpid);
 
 static void BM_unistd_getpid_syscall(benchmark::State& state) {
   while (state.KeepRunning()) {
     syscall(__NR_getpid);
   }
 }
-BENCHMARK(BM_unistd_getpid_syscall);
+BIONIC_BENCHMARK(BM_unistd_getpid_syscall);
 
 #if defined(__BIONIC__)
 
@@ -43,7 +44,7 @@
     gettid_fp();
   }
 }
-BENCHMARK(BM_unistd_gettid);
+BIONIC_BENCHMARK(BM_unistd_gettid);
 
 #endif
 
@@ -52,6 +53,4 @@
     syscall(__NR_gettid);
   }
 }
-BENCHMARK(BM_unistd_gettid_syscall);
-
-BENCHMARK_MAIN()
+BIONIC_BENCHMARK(BM_unistd_gettid_syscall);
diff --git a/benchmarks/util.cpp b/benchmarks/util.cpp
index d9641cf..9afca6f 100644
--- a/benchmarks/util.cpp
+++ b/benchmarks/util.cpp
@@ -19,11 +19,11 @@
 #include <sched.h>
 #include <stdio.h>
 #include <string.h>
+
 #include <cstdlib>
-#include <vector>
 
 // This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
-char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask) {
+char* GetAlignedMemory(char* orig_ptr, size_t alignment, size_t or_mask) {
   if ((alignment & (alignment - 1)) != 0) {
     fprintf(stderr, "warning: alignment passed into GetAlignedMemory is not a power of two.\n");
     std::abort();
@@ -44,12 +44,12 @@
   return reinterpret_cast<char*>(ptr);
 }
 
-char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes) {
+char* GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes) {
   buf->resize(nbytes + 3 * alignment);
   return GetAlignedMemory(buf->data(), alignment, 0);
 }
 
-char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte) {
+char* GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte) {
   char* buf_aligned = GetAlignedPtr(buf, alignment, nbytes);
   memset(buf_aligned, fill_byte, nbytes);
   return buf_aligned;
@@ -64,7 +64,7 @@
 
 #else
 
-bool LockToCPU(int cpu_to_lock) {
+bool LockToCPU(long cpu_to_lock) {
   cpu_set_t cpuset;
 
   CPU_ZERO(&cpuset);
@@ -81,7 +81,7 @@
       }
     }
   } else if (!CPU_ISSET(cpu_to_lock, &cpuset)) {
-    printf("Cpu %d does not exist.\n", cpu_to_lock);
+    printf("Cpu %ld does not exist.\n", cpu_to_lock);
     return false;
   }
 
diff --git a/benchmarks/util.h b/benchmarks/util.h
index bd3d515..c8c39e3 100644
--- a/benchmarks/util.h
+++ b/benchmarks/util.h
@@ -17,15 +17,43 @@
 #ifndef _BIONIC_BENCHMARKS_UTIL_H_
 #define _BIONIC_BENCHMARKS_UTIL_H_
 
+#include <map>
+#include <mutex>
+#include <string>
 #include <vector>
 
+typedef void (*benchmark_func_t) (void);
+
+extern std::mutex g_map_lock;
+
+extern std::map<std::string, benchmark_func_t> g_str_to_func;
+
+static int  __attribute__((unused)) EmplaceBenchmark (std::string fn_name, benchmark_func_t fn_ptr) {
+  g_map_lock.lock();
+  g_str_to_func.emplace(std::string(fn_name), fn_ptr);
+  g_map_lock.unlock();
+  return 0;
+}
+
+#define BIONIC_BENCHMARK(n) \
+  int _bionic_benchmark_##n __attribute__((unused)) = EmplaceBenchmark(std::string(#n), reinterpret_cast<benchmark_func_t>(n))
+
+constexpr auto KB = 1024;
+
+typedef struct {
+  long cpu_to_lock;
+  long num_iterations;
+  std::string xmlpath;
+  std::vector<std::string> extra_benchmarks;
+} bench_opts_t;
+
 // This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
-char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask);
+char* GetAlignedMemory(char* orig_ptr, size_t alignment, size_t or_mask);
 
-char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes);
+char* GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes);
 
-char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
+char* GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
 
-bool LockToCPU(int cpu_to_lock);
+bool LockToCPU(long cpu_to_lock);
 
 #endif // _BIONIC_BENCHMARKS_UTIL_H
diff --git a/libc/include/android/legacy_stdlib_inlines.h b/libc/include/android/legacy_stdlib_inlines.h
index e26e5f2..0d6f2c2 100644
--- a/libc/include/android/legacy_stdlib_inlines.h
+++ b/libc/include/android/legacy_stdlib_inlines.h
@@ -38,6 +38,8 @@
 
 __BEGIN_DECLS
 
+__noreturn void _Exit(int) __RENAME(_exit);
+
 static __inline float strtof(const char* nptr, char** endptr) {
   double d = strtod(nptr, endptr);
   if (d > FLT_MAX) {
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 7165738..ccafd78 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -152,7 +152,7 @@
 int pthread_mutex_trylock(pthread_mutex_t*);
 int pthread_mutex_unlock(pthread_mutex_t*);
 
-#if defined(__LP32__) && __ANDROID_API__ < 21
+#if __ANDROID_API__ < 21
 /*
  * Cruft for supporting old API levels. Pre-L we didn't have the proper POSIX
  * APIs for things, but instead had some locally grown, artisan equivalents.
@@ -164,7 +164,6 @@
  *  * https://github.com/android-ndk/ndk/issues/423
  *  * https://stackoverflow.com/q/44580542/632035
  */
-
 int pthread_mutex_lock_timeout_np(pthread_mutex_t* mutex, unsigned msecs);
 int pthread_cond_timeout_np(pthread_cond_t* cond, pthread_mutex_t* mutex, unsigned msecs);
 int pthread_cond_timedwait_monotonic_np(pthread_cond_t*, pthread_mutex_t*, const struct timespec*);
diff --git a/tests/complex_test.cpp b/tests/complex_test.cpp
index f18fac5..3a5ef74 100644
--- a/tests/complex_test.cpp
+++ b/tests/complex_test.cpp
@@ -28,7 +28,7 @@
 
 // libc++ actively gets in the way of including <complex.h> from C++, so we
 // have to be naughty.
-#include <../libc/include/complex.h>
+#include "../libc/include/complex.h"
 
 // (libc++ also seems to have really bad implementations of its own that ignore
 // the intricacies of floating point math.)