blob: 3c090c7ad2b43912555d79bdd4731cde085a4ee8 [file] [log] [blame]
Hans Boehm6031ec12021-05-25 22:08:59 +00001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import dalvik.system.VMRuntime;
18import java.lang.ref.WeakReference;
19import java.nio.ByteBuffer;
20
21public class Main {
22
Hans Boehmd0020ba2021-06-07 15:44:45 -070023 static final int HOW_MANY_HUGE = 120; // > 1GB to trigger blocking in default config.
Hans Boehm6031ec12021-05-25 22:08:59 +000024 int allocated = 0;
25 int deallocated = 0;
26 static Object lock = new Object();
27 WeakReference<BufferHolder>[] references = new WeakReference[HOW_MANY_HUGE];
28
29 class BufferHolder {
30 private ByteBuffer buffer;
31 BufferHolder() {
32 ++allocated;
33 buffer = getHugeNativeBuffer();
34 }
35 protected void finalize() {
36 synchronized(lock) {
37 ++deallocated;
38 }
39 deleteHugeNativeBuffer(buffer);
40 buffer = null;
41 }
42 }
43
44 // Repeatedly inform the GC of native allocations. Return the time (in nsecs) this takes.
45 private static long timeNotifications() {
Hans Boehmd0020ba2021-06-07 15:44:45 -070046 final VMRuntime vmr = VMRuntime.getRuntime();
47 final long startNanos = System.nanoTime();
Hans Boehm6031ec12021-05-25 22:08:59 +000048 // Iteration count must be >= Heap::kNotifyNativeInterval.
49 for (int i = 0; i < 400; ++i) {
50 vmr.notifyNativeAllocation();
51 }
52 return System.nanoTime() - startNanos;
53 }
54
55 public static void main(String[] args) {
56 System.loadLibrary(args[0]);
57 System.out.println("Main Started");
Hans Boehm602da4f2021-06-14 17:51:41 -070058 while (true) {
59 Runtime.getRuntime().gc();
60 if (new Main().tryToRun()) {
61 break;
62 }
63 // Clean up and try again.
64 Runtime.getRuntime().gc();
65 System.runFinalization();
66 }
Hans Boehm6031ec12021-05-25 22:08:59 +000067 System.out.println("Main Finished");
68 }
69
Hans Boehm602da4f2021-06-14 17:51:41 -070070 boolean tryToRun() {
71 final int startingGcNum = getGcNum();
Hans Boehm6031ec12021-05-25 22:08:59 +000072 timeNotifications(); // warm up.
Hans Boehmd0020ba2021-06-07 15:44:45 -070073 final long referenceTime1 = timeNotifications();
74 final long referenceTime2 = timeNotifications();
75 final long referenceTime3 = timeNotifications();
76 final long referenceTime = Math.min(referenceTime1, Math.min(referenceTime2, referenceTime3));
Hans Boehm6031ec12021-05-25 22:08:59 +000077
Hans Boehm602da4f2021-06-14 17:51:41 -070078 // Allocate a GB+ of native memory without informing the GC.
Hans Boehm6031ec12021-05-25 22:08:59 +000079 for (int i = 0; i < HOW_MANY_HUGE; ++i) {
80 new BufferHolder();
81 }
82
Hans Boehm602da4f2021-06-14 17:51:41 -070083 if (startingGcNum != getGcNum()) {
84 // Happens rarely, fail and retry.
85 return false;
86 }
Hans Boehm6031ec12021-05-25 22:08:59 +000087 // One of the notifications should block for GC to catch up.
88 long actualTime = timeNotifications();
Hans Boehmd0020ba2021-06-07 15:44:45 -070089 final long minBlockingTime = 2 * referenceTime + 2_000_000;
Hans Boehm6031ec12021-05-25 22:08:59 +000090
Hans Boehm602da4f2021-06-14 17:51:41 -070091 if (startingGcNum == getGcNum()) {
92 System.out.println("No gc completed");
93 }
Hans Boehm6031ec12021-05-25 22:08:59 +000094 if (actualTime > 500_000_000) {
95 System.out.println("Notifications ran too slowly; excessive blocking? msec = "
96 + (actualTime / 1_000_000));
Hans Boehmd0020ba2021-06-07 15:44:45 -070097 } else if (actualTime < minBlockingTime) {
98 // Try again before reporting.
99 actualTime = timeNotifications();
100 if (actualTime < minBlockingTime) {
101 System.out.println("Notifications ran too quickly; no blocking GC? msec = "
102 + (actualTime / 1_000_000) + " reference(msec) = " + (referenceTime / 1_000_000));
103 }
Hans Boehm6031ec12021-05-25 22:08:59 +0000104 }
105
106 // Let finalizers run.
107 try {
108 Thread.sleep(3000);
109 } catch (InterruptedException e) {
110 System.out.println("Unexpected interrupt");
111 }
112
113 if (deallocated > allocated || deallocated < allocated - 5 /* slop for register references */) {
114 System.out.println("Unexpected number of deallocated objects:");
115 System.out.println("Allocated = " + allocated + " deallocated = " + deallocated);
116 }
Hans Boehm602da4f2021-06-14 17:51:41 -0700117 System.out.println("Succeeded");
118 return true;
Hans Boehm6031ec12021-05-25 22:08:59 +0000119 }
120
121 private static native ByteBuffer getHugeNativeBuffer();
122 private static native void deleteHugeNativeBuffer(ByteBuffer buf);
Hans Boehm602da4f2021-06-14 17:51:41 -0700123 private static native int getGcNum();
Hans Boehm6031ec12021-05-25 22:08:59 +0000124}