Merge "versioner: Migrate to clang-r370808"
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index a7be965..b4176de 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -33,6 +33,7 @@
         "get_heap_size_benchmark.cpp",
         "inttypes_benchmark.cpp",
         "malloc_benchmark.cpp",
+        "malloc_sql_benchmark.cpp",
         "math_benchmark.cpp",
         "property_benchmark.cpp",
         "pthread_benchmark.cpp",
diff --git a/benchmarks/malloc_benchmark.cpp b/benchmarks/malloc_benchmark.cpp
index ca54f11..18ba523 100644
--- a/benchmarks/malloc_benchmark.cpp
+++ b/benchmarks/malloc_benchmark.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,102 +27,46 @@
  */
 
 #include <malloc.h>
-#include <stdlib.h>
+#include <unistd.h>
+
+#include <vector>
 
 #include <benchmark/benchmark.h>
 #include "util.h"
 
 #if defined(__BIONIC__)
 
-enum AllocEnum : uint8_t {
-  MALLOC = 0,
-  CALLOC,
-  MEMALIGN,
-  REALLOC,
-  FREE,
-};
-
-struct MallocEntry {
-  AllocEnum type;
-  size_t idx;
-  size_t size;
-  size_t arg2;
-};
-
-void BenchmarkMalloc(MallocEntry entries[], size_t total_entries, size_t max_allocs) {
-  void* ptrs[max_allocs];
-
-  for (size_t i = 0; i < total_entries; i++) {
-    switch (entries[i].type) {
-    case MALLOC:
-      ptrs[entries[i].idx] = malloc(entries[i].size);
-      // Touch at least one byte of the allocation to make sure that
-      // PSS for this allocation is counted.
-      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 10;
-      break;
-    case CALLOC:
-      ptrs[entries[i].idx] = calloc(entries[i].arg2, entries[i].size);
-      // Touch at least one byte of the allocation to make sure that
-      // PSS for this allocation is counted.
-      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 20;
-      break;
-    case MEMALIGN:
-      ptrs[entries[i].idx] = memalign(entries[i].arg2, entries[i].size);
-      // Touch at least one byte of the allocation to make sure that
-      // PSS for this allocation is counted.
-      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 30;
-      break;
-    case REALLOC:
-      if (entries[i].arg2 == 0) {
-        ptrs[entries[i].idx] = realloc(nullptr, entries[i].size);
-      } else {
-        ptrs[entries[i].idx] = realloc(ptrs[entries[i].arg2 - 1], entries[i].size);
-      }
-      // Touch at least one byte of the allocation to make sure that
-      // PSS for this allocation is counted.
-      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 40;
-      break;
-    case FREE:
-      free(ptrs[entries[i].idx]);
-      break;
-    }
-  }
-}
-
-// This codifies playing back a single threaded trace of the allocations
-// when running the SQLite BenchMark app.
-// Instructions for recreating:
-//   - Enable malloc debug
-//       setprop wrap.com.wtsang02.sqliteutil "LIBC_DEBUG_MALLOC_OPTIONS=record_allocs logwrapper"
-//   - Start the SQLite BenchMark app
-//   - Dump allocs using the signal to get rid of non sql allocs(kill -47 <SQLITE_PID>)
-//   - Run the benchmark.
-//   - Dump allocs using the signal again.
-//   - Find the thread that has the most allocs and run the helper script
-//       bionic/libc/malloc_debug/tools/gen_malloc.pl -i <THREAD_ID> g_sql_entries kMaxSqlAllocSlots < <ALLOC_FILE> > malloc_sql.h
-#include "malloc_sql.h"
-
-static void BM_malloc_sql_trace_default(benchmark::State& state) {
-  // The default is expected to be a zero decay time.
-  mallopt(M_DECAY_TIME, 0);
-
-  for (auto _ : state) {
-    BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
-                    kMaxSqlAllocSlots);
-  }
-}
-BIONIC_BENCHMARK(BM_malloc_sql_trace_default);
-
-static void BM_malloc_sql_trace_decay1(benchmark::State& state) {
+static void BM_mallopt_purge(benchmark::State& state) {
+  static size_t sizes[] = {8, 16, 32, 64, 128, 1024, 4096, 16384, 65536, 131072, 1048576};
+  static int pagesize = getpagesize();
   mallopt(M_DECAY_TIME, 1);
-
+  mallopt(M_PURGE, 0);
   for (auto _ : state) {
-    BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
-                    kMaxSqlAllocSlots);
-  }
+    state.PauseTiming();
+    std::vector<void*> ptrs;
+    for (auto size : sizes) {
+      // Allocate at least two pages worth of the allocations.
+      for (size_t allocated = 0; allocated < 2 * static_cast<size_t>(pagesize); allocated += size) {
+        void* ptr = malloc(size);
+        if (ptr == nullptr) {
+          state.SkipWithError("Failed to allocate memory");
+        }
+        MakeAllocationResident(ptr, size, pagesize);
+        ptrs.push_back(ptr);
+      }
+    }
+    // Free the memory, which should leave many of the pages resident until
+    // the purge call.
+    for (auto ptr : ptrs) {
+      free(ptr);
+    }
+    ptrs.clear();
+    state.ResumeTiming();
 
+    mallopt(M_PURGE, 0);
+  }
   mallopt(M_DECAY_TIME, 0);
 }
-BIONIC_BENCHMARK(BM_malloc_sql_trace_decay1);
+BIONIC_BENCHMARK(BM_mallopt_purge);
 
 #endif
diff --git a/benchmarks/malloc_sql_benchmark.cpp b/benchmarks/malloc_sql_benchmark.cpp
new file mode 100644
index 0000000..383325c
--- /dev/null
+++ b/benchmarks/malloc_sql_benchmark.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <benchmark/benchmark.h>
+#include "util.h"
+
+#if defined(__BIONIC__)
+
+enum AllocEnum : uint8_t {
+  MALLOC = 0,
+  CALLOC,
+  MEMALIGN,
+  REALLOC,
+  FREE,
+};
+
+struct MallocEntry {
+  AllocEnum type;
+  size_t idx;
+  size_t size;
+  size_t arg2;
+};
+
+void BenchmarkMalloc(MallocEntry entries[], size_t total_entries, size_t max_allocs) {
+  void* ptrs[max_allocs];
+
+  for (size_t i = 0; i < total_entries; i++) {
+    switch (entries[i].type) {
+    case MALLOC:
+      ptrs[entries[i].idx] = malloc(entries[i].size);
+      // Touch at least one byte of the allocation to make sure that
+      // PSS for this allocation is counted.
+      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 10;
+      break;
+    case CALLOC:
+      ptrs[entries[i].idx] = calloc(entries[i].arg2, entries[i].size);
+      // Touch at least one byte of the allocation to make sure that
+      // PSS for this allocation is counted.
+      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 20;
+      break;
+    case MEMALIGN:
+      ptrs[entries[i].idx] = memalign(entries[i].arg2, entries[i].size);
+      // Touch at least one byte of the allocation to make sure that
+      // PSS for this allocation is counted.
+      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 30;
+      break;
+    case REALLOC:
+      if (entries[i].arg2 == 0) {
+        ptrs[entries[i].idx] = realloc(nullptr, entries[i].size);
+      } else {
+        ptrs[entries[i].idx] = realloc(ptrs[entries[i].arg2 - 1], entries[i].size);
+      }
+      // Touch at least one byte of the allocation to make sure that
+      // PSS for this allocation is counted.
+      reinterpret_cast<uint8_t*>(ptrs[entries[i].idx])[0] = 40;
+      break;
+    case FREE:
+      free(ptrs[entries[i].idx]);
+      break;
+    }
+  }
+}
+
+// This codifies playing back a single threaded trace of the allocations
+// when running the SQLite BenchMark app.
+// Instructions for recreating:
+//   - Enable malloc debug
+//       setprop wrap.com.wtsang02.sqliteutil "LIBC_DEBUG_MALLOC_OPTIONS=record_allocs logwrapper"
+//   - Start the SQLite BenchMark app
+//   - Dump allocs using the signal to get rid of non sql allocs(kill -47 <SQLITE_PID>)
+//   - Run the benchmark.
+//   - Dump allocs using the signal again.
+//   - Find the thread that has the most allocs and run the helper script
+//       bionic/libc/malloc_debug/tools/gen_malloc.pl -i <THREAD_ID> g_sql_entries kMaxSqlAllocSlots < <ALLOC_FILE> > malloc_sql.h
+#include "malloc_sql.h"
+
+static void BM_malloc_sql_trace_default(benchmark::State& state) {
+  // The default is expected to be a zero decay time.
+  mallopt(M_DECAY_TIME, 0);
+
+  for (auto _ : state) {
+    BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
+                    kMaxSqlAllocSlots);
+  }
+}
+BIONIC_BENCHMARK(BM_malloc_sql_trace_default);
+
+static void BM_malloc_sql_trace_decay1(benchmark::State& state) {
+  mallopt(M_DECAY_TIME, 1);
+
+  for (auto _ : state) {
+    BenchmarkMalloc(g_sql_entries, sizeof(g_sql_entries) / sizeof(MallocEntry),
+                    kMaxSqlAllocSlots);
+  }
+
+  mallopt(M_DECAY_TIME, 0);
+}
+BIONIC_BENCHMARK(BM_malloc_sql_trace_decay1);
+
+#endif
diff --git a/benchmarks/stdlib_benchmark.cpp b/benchmarks/stdlib_benchmark.cpp
index ffcedf0..61b51fa 100644
--- a/benchmarks/stdlib_benchmark.cpp
+++ b/benchmarks/stdlib_benchmark.cpp
@@ -24,13 +24,6 @@
 #include <benchmark/benchmark.h>
 #include "util.h"
 
-static __always_inline void MakeAllocationResident(void* ptr, size_t nbytes, int pagesize) {
-  uint8_t* data = reinterpret_cast<uint8_t*>(ptr);
-  for (size_t i = 0; i < nbytes; i += pagesize) {
-    data[i] = 1;
-  }
-}
-
 static void MallocFree(benchmark::State& state) {
   const size_t nbytes = state.range(0);
   int pagesize = getpagesize();
diff --git a/benchmarks/util.h b/benchmarks/util.h
index ef4892d..99eed5f 100644
--- a/benchmarks/util.h
+++ b/benchmarks/util.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <stdint.h>
+
 #include <map>
 #include <mutex>
 #include <string>
@@ -68,3 +70,11 @@
 char* GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
 
 bool LockToCPU(int cpu_to_lock);
+
+static __inline __attribute__ ((__always_inline__)) void MakeAllocationResident(
+    void* ptr, size_t nbytes, int pagesize) {
+  uint8_t* data = reinterpret_cast<uint8_t*>(ptr);
+  for (size_t i = 0; i < nbytes; i += pagesize) {
+    data[i] = 1;
+  }
+}
diff --git a/docs/native_allocator.md b/docs/native_allocator.md
index 249b144..139d664 100644
--- a/docs/native_allocator.md
+++ b/docs/native_allocator.md
@@ -160,7 +160,7 @@
 any issue related to the code migrating from one core to another
 with different characteristics. For example, on a big-little cpu, if the
 benchmark moves from big to little or vice-versa, this can cause scores
-to fluctuate in indeterminte ways.
+to fluctuate in indeterminate ways.
 
 For most runs, the best set of options to add is:
 
@@ -278,6 +278,18 @@
 Calls to mallinfo are used in ART so a new allocator is required to be
 nearly as performant as the current allocator.
 
+#### mallopt M\_PURGE Benchmark
+This benchmark tracks the cost of calling `mallopt(M_PURGE, 0)`. As with the
+mallinfo benchmark, it's not necessary for this to be better than the previous
+allocator, only that the performance be in the same order of magnitude.
+
+To run the benchmark, use these commands:
+
+    adb shell /data/benchmarktest64/bionic-benchmarks/bionic-benchmarks --benchmark_filter=BM_mallopt_purge
+    adb shell /data/benchmarktest/bionic-benchmarks/bionic-benchmarks --benchmark_filter=BM_mallopt_purge
+
+These calls are used to free unused memory pages back to the kernel.
+
 ### Memory Trace Benchmarks
 These benchmarks measure all three axes of a native allocator, RSS, virtual
 address space consumed, speed of allocation. They are designed to