Replace ashmem in ART with prctl
ART use ashmem just for naming anonymous regions. This is a hack.
Further, we are moving away from ashmem in favor of native Linux based
shared-memory mechanims for Android. We already have a PRCTL for naming
maps in the Android kernels. Lets use that for Android.
This also results in removal of ashmem hacks for host-only builds.
As a side-effect, the naming of regions change from "/dev/ashmem/<name>"
to "[anon:<name>" so we need to update debug code in frameworks. Another
CL does that.
Note: The user pointers passed to the prctl should be available during
maps read time, so we cannot use pointers from the stack. To solve this,
we maintain an std::map of unique debug strings when we name the maps.
This doesn't result in more memory usage than before, since ashmem is
heavier storage-wise due to additional kernel data structure
allocations.
Performance of 'dumpsys meminfo' gone up by 25% (1s to 0.75s). Slab
memory consumption gone down by 3-5MB on boot.
Test: Boot and dumpsys meminfo before/after
Bug: 111903542
Internal gerrit: ag/4827680
Change-Id: Ia658fce62977f6c69dc4ce89ffdcfe2d9ae22738
Signed-off-by: Joel Fernandes <joelaf@google.com>
diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc
index d9760bd..a82da2d 100644
--- a/libartbase/base/mem_map.cc
+++ b/libartbase/base/mem_map.cc
@@ -23,6 +23,10 @@
#include <sys/resource.h>
#endif
+#if defined(__linux__)
+#include <sys/prctl.h>
+#endif
+
#include <map>
#include <memory>
#include <sstream>
@@ -30,12 +34,6 @@
#include "android-base/stringprintf.h"
#include "android-base/unique_fd.h"
-#if !defined(__Fuchsia__)
-#include "cutils/ashmem.h"
-#else
-#include "fuchsia_compat.h"
-#endif
-
#include "allocator.h"
#include "bit_utils.h"
#include "globals.h"
@@ -61,6 +59,9 @@
// All the non-empty MemMaps. Use a multimap as we do a reserve-and-divide (eg ElfMap::Load()).
static Maps* gMaps GUARDED_BY(MemMap::GetMemMapsLock()) = nullptr;
+// A map containing unique strings used for indentifying anonymous mappings
+static std::map<std::string, int> debugStrMap GUARDED_BY(MemMap::GetMemMapsLock());
+
// Retrieve iterator to a `gMaps` entry that is known to exist.
Maps::iterator GetGMapsEntry(const MemMap& map) REQUIRES(MemMap::GetMemMapsLock()) {
DCHECK(map.IsValid());
@@ -246,6 +247,33 @@
}
#endif
+void MemMap::SetDebugName(void* map_ptr, const char* name, size_t size) {
+ // Debug naming is only used for Android target builds. For Linux targets,
+ // we'll still call prctl but it wont do anything till we upstream the prctl.
+ if (kIsTargetFuchsia || !kIsTargetBuild) {
+ return;
+ }
+
+ // lock as std::map is not thread-safe
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
+
+ std::string debug_friendly_name("dalvik-");
+ debug_friendly_name += name;
+ auto it = debugStrMap.find(debug_friendly_name);
+
+ if (it == debugStrMap.end()) {
+ it = debugStrMap.insert(std::make_pair(std::move(debug_friendly_name), 1)).first;
+ }
+
+ DCHECK(it != debugStrMap.end());
+#if defined(PR_SET_VMA) && defined(__linux__)
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_ptr, size, it->first.c_str());
+#else
+ // Prevent variable unused compiler errors.
+ UNUSED(map_ptr, size);
+#endif
+}
+
MemMap MemMap::MapAnonymous(const char* name,
uint8_t* addr,
size_t byte_count,
@@ -253,11 +281,10 @@
bool low_4gb,
bool reuse,
std::string* error_msg,
- bool use_ashmem) {
+ bool use_debug_name) {
#ifndef __LP64__
UNUSED(low_4gb);
#endif
- use_ashmem = use_ashmem && !kIsTargetLinux && !kIsTargetFuchsia;
if (byte_count == 0) {
*error_msg = "Empty MemMap requested.";
return Invalid();
@@ -274,41 +301,8 @@
flags |= MAP_FIXED;
}
- if (use_ashmem) {
- if (!kIsTargetBuild) {
- // When not on Android (either host or assuming a linux target) ashmem is faked using
- // files in /tmp. Ensure that such files won't fail due to ulimit restrictions. If they
- // will then use a regular mmap.
- struct rlimit rlimit_fsize;
- CHECK_EQ(getrlimit(RLIMIT_FSIZE, &rlimit_fsize), 0);
- use_ashmem = (rlimit_fsize.rlim_cur == RLIM_INFINITY) ||
- (page_aligned_byte_count < rlimit_fsize.rlim_cur);
- }
- }
-
unique_fd fd;
-
- if (use_ashmem) {
- // android_os_Debug.cpp read_mapinfo assumes all ashmem regions associated with the VM are
- // prefixed "dalvik-".
- std::string debug_friendly_name("dalvik-");
- debug_friendly_name += name;
- fd.reset(ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count));
-
- if (fd.get() == -1) {
- // We failed to create the ashmem region. Print a warning, but continue
- // anyway by creating a true anonymous mmap with an fd of -1. It is
- // better to use an unlabelled anonymous map than to fail to create a
- // map at all.
- PLOG(WARNING) << "ashmem_create_region failed for '" << name << "'";
- } else {
- // We succeeded in creating the ashmem region. Use the created ashmem
- // region as backing for the mmap.
- flags &= ~MAP_ANONYMOUS;
- }
- }
-
// We need to store and potentially set an error number for pretty printing of errors
int saved_errno = 0;
@@ -341,6 +335,11 @@
if (!CheckMapRequest(addr, actual, page_aligned_byte_count, error_msg)) {
return Invalid();
}
+
+ if (use_debug_name) {
+ SetDebugName(actual, name, page_aligned_byte_count);
+ }
+
return MemMap(name,
reinterpret_cast<uint8_t*>(actual),
byte_count,
@@ -639,8 +638,7 @@
const char* tail_name,
int tail_prot,
std::string* error_msg,
- bool use_ashmem) {
- use_ashmem = use_ashmem && !kIsTargetLinux && !kIsTargetFuchsia;
+ bool use_debug_name) {
DCHECK_GE(new_end, Begin());
DCHECK_LE(new_end, End());
DCHECK_LE(begin_ + size_, reinterpret_cast<uint8_t*>(base_begin_) + base_size_);
@@ -666,19 +664,6 @@
unique_fd fd;
int flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
- if (use_ashmem) {
- // android_os_Debug.cpp read_mapinfo assumes all ashmem regions associated with the VM are
- // prefixed "dalvik-".
- std::string debug_friendly_name("dalvik-");
- debug_friendly_name += tail_name;
- fd.reset(ashmem_create_region(debug_friendly_name.c_str(), tail_base_size));
- flags = MAP_PRIVATE | MAP_FIXED;
- if (fd.get() == -1) {
- *error_msg = StringPrintf("ashmem_create_region failed for '%s': %s",
- tail_name, strerror(errno));
- return Invalid();
- }
- }
MEMORY_TOOL_MAKE_UNDEFINED(tail_base_begin, tail_base_size);
// Note: Do not explicitly unmap the tail region, mmap() with MAP_FIXED automatically
@@ -703,6 +688,11 @@
auto it = GetGMapsEntry(*this);
gMaps->erase(it);
}
+
+ if (use_debug_name) {
+ SetDebugName(actual, tail_name, tail_base_size);
+ }
+
size_ = new_size;
base_size_ = new_base_size;
// Return the new mapping.