Bug 1517412 - Adapt wasm buffer management parameters for android-on-arm64. r=luke
authorLars T Hansen <lhansen@mozilla.com>
Fri, 04 Jan 2019 16:49:36 +0100
changeset 510001 81ddd47b2cae63f03d4e70853f5bd5262ff1afc4
parent 510000 0db2741d6edaefd516f8baa2041cf670a25aeb06
child 510002 d3d18e1a63e346bc4e8cb6aba3a59bf9a28181ee
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1517412
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1517412 - Adapt wasm buffer management parameters for android-on-arm64. r=luke Android on ARM64 only has 4TB of available address space per process, leaving room for relatively few wasm memory objects (6GB each currently). We therefore adjust the wasm GC trigger parameters to account for this limitation.
js/src/jit-test/tests/wasm/atomic.js
js/src/jit-test/tests/wasm/baseline-abs-addr-opt.js
js/src/jit-test/tests/wasm/bce.js
js/src/jit-test/tests/wasm/memory.js
js/src/vm/ArrayBufferObject.cpp
--- a/js/src/jit-test/tests/wasm/atomic.js
+++ b/js/src/jit-test/tests/wasm/atomic.js
@@ -1,10 +1,9 @@
-// |jit-test| skip-if: !wasmThreadsSupported() || getBuildConfiguration()['arm64']
-// skip arm64 due to bug 1513231
+// |jit-test| skip-if: !wasmThreadsSupported()
 
 const oob = /index out of bounds/;
 const unaligned = /unaligned memory access/;
 const RuntimeError = WebAssembly.RuntimeError;
 
 // Check that the output of wasmTextToBinary verifies correctly.
 
 let SHARED = 'shared';
--- a/js/src/jit-test/tests/wasm/baseline-abs-addr-opt.js
+++ b/js/src/jit-test/tests/wasm/baseline-abs-addr-opt.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm64']
-// skip arm64 due to bug 1513231
 // Test bounds checking at the end of memory with a constant base pointer.
 // This is intended to verify a bounds check elimination optimization in
 // the baseline compiler.
 
 // This can be only a functional test, we can't really see whether
 // the optimization is being applied.  However, manual inspection
 // of the generated code has verified that the optimization is
 // being applied.
--- a/js/src/jit-test/tests/wasm/bce.js
+++ b/js/src/jit-test/tests/wasm/bce.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm64']
-// skip arm64 due to bug 1513231
 mem='\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'+
     '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'+
     '\x00'.repeat(65488) +
     '\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'
 
 let accessWidth = {
   '8_s':  1,
   '8_u':  1,
--- a/js/src/jit-test/tests/wasm/memory.js
+++ b/js/src/jit-test/tests/wasm/memory.js
@@ -1,10 +1,8 @@
-// |jit-test| skip-if: getBuildConfiguration()['arm64']
-// skip arm64 due to bug 1513231
 const RuntimeError = WebAssembly.RuntimeError;
 
 function loadModuleSrc(type, ext, offset, align, drop = false) {
     let maybeResult = drop ? '' : `(result ${type})`;
     let maybeDrop = drop ? 'drop' : '';
     return `(module
        (memory 1)
        (data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -82,42 +82,67 @@ bool js::ToClampedIndex(JSContext* cx, H
     }
   } else if (uint32_t(result) > length) {
     result = length;
   }
   *out = uint32_t(result);
   return true;
 }
 
-// If there are too many 4GB buffers live we run up against system resource
-// exhaustion (address space or number of memory map descriptors), see
-// bug 1068684, bug 1073934 for details.  The limiting case seems to be
-// Windows Vista Home 64-bit, where the per-process address space is limited
-// to 8TB.  Thus we track the number of live objects, and set a limit of
-// 1000 live objects per process and we throw an OOM error if the per-process
-// limit is exceeded.
+// If there are too many wasm memory buffers (typically 6GB each) live we run up
+// against system resource exhaustion (address space or number of memory map
+// descriptors), see bug 1068684, bug 1073934, bug 1517412, bug 1502733 for
+// details.  The limiting case seems to be Android on ARM64, where the
+// per-process address space is limited to 4TB (39 bits) by the organization of
+// the page tables.  An earlier problem was Windows Vista Home 64-bit, where the
+// per-process address space is limited to 8TB (40 bits).
+//
+// Thus we track the number of live objects, and set a limit of the number of
+// live buffer objects per process.  We trigger GC work when we approach the
+// limit and we throw an OOM error if the per-process limit is exceeded.  The
+// limit (MaximumLiveMappedBuffers) is specific to architecture, OS, and OS
+// configuration.
 //
 // Since the MaximumLiveMappedBuffers limit is not generally accounted for by
 // any existing GC-trigger heuristics, we need an extra heuristic for triggering
 // GCs when the caller is allocating memories rapidly without other garbage.
-// Thus, once the live buffer count crosses a certain threshold, we start
-// triggering GCs every N allocations. As we get close to the limit, perform
-// expensive non-incremental full GCs as a last-ditch effort to avoid
-// unnecessary failure. The *Sans use a ton of vmem for bookkeeping leaving a
-// lot less for the program so use a lower limit.
+// Thus, once the live buffer count crosses the threshold
+// StartTriggeringAtLiveBufferCount, we start triggering GCs every
+// AllocatedBuffersPerTrigger allocations.  Once we reach
+// StartSyncFullGCAtLiveBufferCount live buffers, we perform expensive
+// non-incremental full GCs as a last-ditch effort to avoid unnecessary failure.
+// Once we reach MaximumLiveMappedBuffers, we perform further full GCs before
+// giving up.
 
-#if defined(MOZ_TSAN) || defined(MOZ_ASAN)
+#if defined(JS_CODEGEN_ARM64) && defined(ANDROID)
+// With 6GB mappings, the hard limit is 84 buffers.  75 cuts it close.
+static const int32_t MaximumLiveMappedBuffers = 75;
+#elif defined(MOZ_TSAN) || defined(MOZ_ASAN)
+// ASAN and TSAN use a ton of vmem for bookkeeping leaving a lot less for the
+// program so use a lower limit.
 static const int32_t MaximumLiveMappedBuffers = 500;
 #else
 static const int32_t MaximumLiveMappedBuffers = 1000;
 #endif
+
+// StartTriggeringAtLiveBufferCount + AllocatedBuffersPerTrigger must be well
+// below StartSyncFullGCAtLiveBufferCount in order to provide enough time for
+// incremental GC to do its job.
+
+#if defined(JS_CODEGEN_ARM64) && defined(ANDROID)
+static const int32_t StartTriggeringAtLiveBufferCount = 15;
+static const int32_t StartSyncFullGCAtLiveBufferCount =
+    MaximumLiveMappedBuffers - 15;
+static const int32_t AllocatedBuffersPerTrigger = 15;
+#else
 static const int32_t StartTriggeringAtLiveBufferCount = 100;
 static const int32_t StartSyncFullGCAtLiveBufferCount =
     MaximumLiveMappedBuffers - 100;
 static const int32_t AllocatedBuffersPerTrigger = 100;
+#endif
 
 static Atomic<int32_t, mozilla::ReleaseAcquire> liveBufferCount(0);
 static Atomic<int32_t, mozilla::ReleaseAcquire> allocatedSinceLastTrigger(0);
 
 int32_t js::LiveMappedBufferCount() { return liveBufferCount; }
 
 void* js::MapBufferMemory(size_t mappedSize, size_t initialCommittedSize) {
   MOZ_ASSERT(mappedSize % gc::SystemPageSize() == 0);