Use cmdline gc-type and phenotype to decide which GC to run
Bug: 242553398
Bug: 160737021
Test: manual with android builds and module installations
Change-Id: Icfc25058e669406a0c3eb178376db8041e11c27b
diff --git a/build/art.go b/build/art.go
index 970af8a..cc53719 100644
--- a/build/art.go
+++ b/build/art.go
@@ -70,10 +70,11 @@
if !ctx.Config().IsEnvFalse("ART_USE_GENERATIONAL_CC") {
cflags = append(cflags, "-DART_USE_GENERATIONAL_CC=1")
}
- // For now force CC as we don't want to make userfaultfd GC the default.
- // Eventually, make it such that we force CC only if ART_USE_READ_BARRIER
- // was set to true explicitly during build time.
- cflags = append(cflags, "-DART_FORCE_USE_READ_BARRIER=1")
+ // Force CC only if ART_USE_READ_BARRIER was set to true explicitly during
+ // build time.
+ if ctx.Config().IsEnvTrue("ART_USE_READ_BARRIER") {
+ cflags = append(cflags, "-DART_FORCE_USE_READ_BARRIER=1")
+ }
tlab = true
} else if gcType == "CMC" {
tlab = true
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index d73418b..71e5a13 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -16,10 +16,13 @@
#include "mark_compact-inl.h"
+#include "android-base/file.h"
+#include "android-base/properties.h"
#include "base/quasi_atomic.h"
#include "base/systrace.h"
#include "base/utils.h"
#include "gc/accounting/mod_union_table-inl.h"
+#include "gc/collector_type.h"
#include "gc/reference_processor.h"
#include "gc/space/bump_pointer_space.h"
#include "gc/task_processor.h"
@@ -36,6 +39,7 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
+
#include <fstream>
#include <numeric>
@@ -58,6 +62,12 @@
#endif // __NR_userfaultfd
#endif // __BIONIC__
+namespace {
+
+using ::android::base::GetBoolProperty;
+
+}
+
namespace art {
// We require MREMAP_DONTUNMAP functionality of the mremap syscall, which was
@@ -82,11 +92,28 @@
// userfaultfd is enabled.
static const bool gKernelHasFaultRetry = kIsTargetAndroid || IsKernelVersionAtLeast(5, 7);
-#ifndef ART_FORCE_USE_READ_BARRIER
-static bool ShouldUseUserfaultfd() {
-#if !defined(__linux__)
- return false;
-#endif
+// The other cases are defined as constexpr in runtime/read_barrier_config.h
+#if !defined(ART_FORCE_USE_READ_BARRIER) && defined(ART_USE_READ_BARRIER)
+// Returns collector type asked to be used on the cmdline.
+static gc::CollectorType FetchCmdlineGcType() {
+ std::string argv;
+ gc::CollectorType gc_type = gc::CollectorType::kCollectorTypeNone;
+ if (android::base::ReadFileToString("/proc/self/cmdline", &argv)) {
+ if (argv.find("-Xgc:CMC") != std::string::npos) {
+ gc_type = gc::CollectorType::kCollectorTypeCMC;
+ } else if (argv.find("-Xgc:CC") != std::string::npos) {
+ gc_type = gc::CollectorType::kCollectorTypeCC;
+ }
+ }
+ return gc_type;
+}
+
+static bool SysPropSaysUffdGc() {
+ return GetBoolProperty("persist.device_config.runtime_native_boot.enable_uffd_gc",
+ GetBoolProperty("ro.dalvik.vm.enable_uffd_gc", false));
+}
+
+static bool KernelSupportsUffd() {
int fd = syscall(__NR_userfaultfd, O_CLOEXEC | UFFD_USER_MODE_ONLY);
// On non-android devices we may not have the kernel patches that restrict
// userfaultfd to user mode. But that is not a security concern as we are
@@ -101,15 +128,26 @@
return false;
}
}
-#endif
-// The other cases are defined as a constexpr in runtime/read_barrier_config.h
-#ifndef ART_FORCE_USE_READ_BARRIER
-const bool gUseReadBarrier = (kUseBakerReadBarrier || kUseTableLookupReadBarrier)
- && !ShouldUseUserfaultfd();
-#ifdef ART_DEFAULT_GC_TYPE_IS_CMC
-const bool gUseUserfaultfd = !gUseReadBarrier;
+static bool ShouldUseUserfaultfd() {
+ static_assert(kUseBakerReadBarrier || kUseTableLookupReadBarrier);
+#ifdef __linux__
+ // Use CMC/CC if that is being explicitly asked for on cmdline. Otherwise,
+ // always use CC on host. On target, use CMC only if system properties says so
+ // and the kernel supports it.
+ gc::CollectorType gc_type = FetchCmdlineGcType();
+ return gc_type == gc::CollectorType::kCollectorTypeCMC ||
+ (gc_type == gc::CollectorType::kCollectorTypeNone &&
+ kIsTargetAndroid &&
+ SysPropSaysUffdGc() &&
+ KernelSupportsUffd());
+#else
+ return false;
#endif
+}
+
+const bool gUseUserfaultfd = ShouldUseUserfaultfd();
+const bool gUseReadBarrier = !gUseUserfaultfd;
#endif
namespace gc {
diff --git a/runtime/read_barrier_config.h b/runtime/read_barrier_config.h
index 53274ea..876e3d7 100644
--- a/runtime/read_barrier_config.h
+++ b/runtime/read_barrier_config.h
@@ -71,16 +71,24 @@
static constexpr bool kUseTableLookupReadBarrier = false;
#endif
+// Only if read-barrier isn't forced (see build/art.go) but is selected, that we need
+// to see if we support userfaultfd GC. All the other cases can be constexpr here.
#ifdef ART_FORCE_USE_READ_BARRIER
constexpr bool gUseReadBarrier = kUseBakerReadBarrier || kUseTableLookupReadBarrier;
constexpr bool gUseUserfaultfd = !gUseReadBarrier;
+static_assert(!gUseUserfaultfd);
#else
-extern const bool gUseReadBarrier;
+#ifndef ART_USE_READ_BARRIER
+constexpr bool gUseReadBarrier = false;
#ifdef ART_DEFAULT_GC_TYPE_IS_CMC
-extern const bool gUseUserfaultfd;
+constexpr bool gUseUserfaultfd = true;
#else
constexpr bool gUseUserfaultfd = false;
#endif
+#else
+extern const bool gUseReadBarrier;
+extern const bool gUseUserfaultfd;
+#endif
#endif
// Disabled for performance reasons.