summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hans Boehm <hboehm@google.com> 2021-05-25 22:08:59 +0000
committer Hans Boehm <hboehm@google.com> 2021-06-03 18:29:57 +0000
commit6031ec1e5d916c3537dbbacb14bc16c6fff4bf3c (patch)
treeb1de00d51735244272733237889077dd39571287
parentc8451cb4302e028d4e106c1a2a44749d5cb9bb31 (diff)
Re-land "Add 2040-huge-native-alloc test"
This reverts commit c256028e1fb92b47c741db67b6bc8ca6995e6c1b. Reason for revert: The underlying problem is fixed, and we need better testing. PS2 and later also contains the following change: More aggressively notify the collector of native allocation, to account for the fact that on host, only one notification in 384 is pass through, since mallinfo is SLOW. This version once again assumes that we sleep if necessary to allow the triggered collection to both get started and complete. Test: Treehugger Bug: 189150802 Bug: 189955496 Change-Id: I2ec4ca9a37fa9dbd9c7d351208d3d5ca2d4ee5d4
-rw-r--r--test/2040-huge-native-alloc/Android.bp40
-rw-r--r--test/2040-huge-native-alloc/expected-stderr.txt0
-rw-r--r--test/2040-huge-native-alloc/expected-stdout.txt3
-rw-r--r--test/2040-huge-native-alloc/huge_native_buf.cc38
-rw-r--r--test/2040-huge-native-alloc/info.txt2
-rw-r--r--test/2040-huge-native-alloc/src/Main.java99
-rw-r--r--test/Android.bp1
-rw-r--r--test/knownfailures.json3
8 files changed, 185 insertions, 1 deletions
diff --git a/test/2040-huge-native-alloc/Android.bp b/test/2040-huge-native-alloc/Android.bp
new file mode 100644
index 0000000000..8a5501d853
--- /dev/null
+++ b/test/2040-huge-native-alloc/Android.bp
@@ -0,0 +1,40 @@
+// Generated by `regen-test-files`. Do not edit manually.
+
+// Build rules for ART run-test `2040-huge-native-alloc`.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "art_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["art_license"],
+}
+
+// Test's Dex code.
+java_test {
+ name: "art-run-test-2040-huge-native-alloc",
+ defaults: ["art-run-test-defaults"],
+ test_config_template: ":art-run-test-target-no-test-suite-tag-template",
+ srcs: ["src/**/*.java"],
+ data: [
+ ":art-run-test-2040-huge-native-alloc-expected-stdout",
+ ":art-run-test-2040-huge-native-alloc-expected-stderr",
+ ],
+}
+
+// Test's expected standard output.
+genrule {
+ name: "art-run-test-2040-huge-native-alloc-expected-stdout",
+ out: ["art-run-test-2040-huge-native-alloc-expected-stdout.txt"],
+ srcs: ["expected-stdout.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
+
+// Test's expected standard error.
+genrule {
+ name: "art-run-test-2040-huge-native-alloc-expected-stderr",
+ out: ["art-run-test-2040-huge-native-alloc-expected-stderr.txt"],
+ srcs: ["expected-stderr.txt"],
+ cmd: "cp -f $(in) $(out)",
+}
diff --git a/test/2040-huge-native-alloc/expected-stderr.txt b/test/2040-huge-native-alloc/expected-stderr.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/2040-huge-native-alloc/expected-stderr.txt
diff --git a/test/2040-huge-native-alloc/expected-stdout.txt b/test/2040-huge-native-alloc/expected-stdout.txt
new file mode 100644
index 0000000000..f2fc51cbf2
--- /dev/null
+++ b/test/2040-huge-native-alloc/expected-stdout.txt
@@ -0,0 +1,3 @@
+JNI_OnLoad called
+Main Started
+Main Finished
diff --git a/test/2040-huge-native-alloc/huge_native_buf.cc b/test/2040-huge-native-alloc/huge_native_buf.cc
new file mode 100644
index 0000000000..06186c9371
--- /dev/null
+++ b/test/2040-huge-native-alloc/huge_native_buf.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "base/utils.h"
+#include "jni.h"
+#include <stddef.h>
+
+namespace art {
+
+static constexpr size_t HUGE_SIZE = 10'000'000;
+
+extern "C" JNIEXPORT jobject JNICALL Java_Main_getHugeNativeBuffer(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
+ char* buffer = new char[HUGE_SIZE];
+ return env->NewDirectByteBuffer(buffer, HUGE_SIZE);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_deleteHugeNativeBuffer(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject jbuffer) {
+ delete [] static_cast<char*>(env->GetDirectBufferAddress(jbuffer));
+}
+
+} // namespace art
+
+
diff --git a/test/2040-huge-native-alloc/info.txt b/test/2040-huge-native-alloc/info.txt
new file mode 100644
index 0000000000..41c5ef60b4
--- /dev/null
+++ b/test/2040-huge-native-alloc/info.txt
@@ -0,0 +1,2 @@
+Check that we properly trigger world stop collections after a lot of native
+allocation.
diff --git a/test/2040-huge-native-alloc/src/Main.java b/test/2040-huge-native-alloc/src/Main.java
new file mode 100644
index 0000000000..0366e5e7d1
--- /dev/null
+++ b/test/2040-huge-native-alloc/src/Main.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import dalvik.system.VMRuntime;
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+
+public class Main {
+
+ static final int HOW_MANY_HUGE = 110; // > 1GB to trigger blocking in default config.
+ int allocated = 0;
+ int deallocated = 0;
+ static Object lock = new Object();
+ WeakReference<BufferHolder>[] references = new WeakReference[HOW_MANY_HUGE];
+
+ class BufferHolder {
+ private ByteBuffer buffer;
+ BufferHolder() {
+ ++allocated;
+ buffer = getHugeNativeBuffer();
+ }
+ protected void finalize() {
+ synchronized(lock) {
+ ++deallocated;
+ }
+ deleteHugeNativeBuffer(buffer);
+ buffer = null;
+ }
+ }
+
+ // Repeatedly inform the GC of native allocations. Return the time (in nsecs) this takes.
+ private static long timeNotifications() {
+ VMRuntime vmr = VMRuntime.getRuntime();
+ long startNanos = System.nanoTime();
+ // Iteration count must be >= Heap::kNotifyNativeInterval.
+ for (int i = 0; i < 400; ++i) {
+ vmr.notifyNativeAllocation();
+ }
+ return System.nanoTime() - startNanos;
+ }
+
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+ System.out.println("Main Started");
+ new Main().run();
+ System.out.println("Main Finished");
+ }
+
+ void run() {
+ timeNotifications(); // warm up.
+ long referenceTime1 = timeNotifications();
+ long referenceTime2 = timeNotifications();
+ long referenceTime = Math.min(referenceTime1, referenceTime2);
+
+ // Allocate half a GB of native memory without informing the GC.
+ for (int i = 0; i < HOW_MANY_HUGE; ++i) {
+ new BufferHolder();
+ }
+
+ // One of the notifications should block for GC to catch up.
+ long actualTime = timeNotifications();
+
+ if (actualTime > 500_000_000) {
+ System.out.println("Notifications ran too slowly; excessive blocking? msec = "
+ + (actualTime / 1_000_000));
+ } else if (actualTime < 3 * referenceTime + 2_000_000) {
+ System.out.println("Notifications ran too quickly; no blocking GC? msec = "
+ + (actualTime / 1_000_000));
+ }
+
+ // Let finalizers run.
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ System.out.println("Unexpected interrupt");
+ }
+
+ if (deallocated > allocated || deallocated < allocated - 5 /* slop for register references */) {
+ System.out.println("Unexpected number of deallocated objects:");
+ System.out.println("Allocated = " + allocated + " deallocated = " + deallocated);
+ }
+ }
+
+ private static native ByteBuffer getHugeNativeBuffer();
+ private static native void deleteHugeNativeBuffer(ByteBuffer buf);
+}
diff --git a/test/Android.bp b/test/Android.bp
index e710509bd9..e393f06a3b 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -730,6 +730,7 @@ cc_defaults {
"2033-shutdown-mechanics/native_shutdown.cc",
"2036-jni-filechannel/jni_filechannel.cc",
"2037-thread-name-inherit/thread_name_inherit.cc",
+ "2040-huge-native-alloc/huge_native_buf.cc",
"common/runtime_state.cc",
"common/stack_inspect.cc",
],
diff --git a/test/knownfailures.json b/test/knownfailures.json
index d9b089d17a..10da9ab062 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1190,7 +1190,8 @@
"2033-shutdown-mechanics",
"2035-structural-native-method",
"2036-structural-subclass-shadow",
- "2038-hiddenapi-jvmti-ext"],
+ "2038-hiddenapi-jvmti-ext",
+ "2040-huge-native-alloc"],
"variant": "jvm",
"description": ["Doesn't run on RI."]
},