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