1 /* 2 * Copyright (C) 2016 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 17 package art; 18 19 import java.lang.ref.WeakReference; 20 import java.util.ArrayList; 21 import java.util.Arrays; 22 import java.util.concurrent.CountDownLatch; 23 import java.util.concurrent.Semaphore; 24 25 public class Test1900 { checkLE(long exp, long o)26 public static void checkLE(long exp, long o) { 27 if (exp > o) { 28 throw new Error("Expected: " + exp + " Got: " + o); 29 } 30 } checkEq(long exp, long o)31 public static void checkEq(long exp, long o) { 32 if (exp != o) { 33 throw new Error("Expected: " + exp + " Got: " + o); 34 } 35 } 36 runConcurrent(Runnable... rs)37 public static void runConcurrent(Runnable... rs) throws Exception { 38 final CountDownLatch latch = new CountDownLatch(rs.length); 39 Thread[] thrs = new Thread[rs.length]; 40 for (int i = 0; i < rs.length; i++) { 41 final Runnable r = rs[i]; 42 thrs[i] = new Thread(() -> { 43 latch.countDown(); 44 r.run(); 45 }); 46 thrs[i].start(); 47 } 48 for (Thread thr : thrs) { 49 thr.join(); 50 } 51 } 52 static class Holder { 53 public long val; 54 } 55 run()56 public static void run() throws Exception { 57 initializeTest(); 58 // Get the overhead for the native part of this test. 59 final long base_state = getAmountAllocated(); 60 61 // Basic alloc-dealloc 62 checkEq(base_state + 0, getAmountAllocated()); 63 long abc = doAllocate(10); 64 checkLE(base_state + 10, getAmountAllocated()); 65 long def = doAllocate(10); 66 checkLE(base_state + 20, getAmountAllocated()); 67 doDeallocate(abc); 68 checkLE(base_state + 10, getAmountAllocated()); 69 70 doDeallocate(def); 71 72 checkEq(base_state + 0, getAmountAllocated()); 73 74 // Try doing it concurrently. 75 Runnable add10 = () -> { long x = doAllocate(10); doDeallocate(x); }; 76 Runnable[] rs = new Runnable[100]; 77 Arrays.fill(rs, add10); 78 runConcurrent(rs); 79 checkEq(base_state + 0, getAmountAllocated()); 80 81 // Try doing it concurrently with different threads to allocate and deallocate. 82 final Semaphore sem = new Semaphore(0); 83 final Holder h = new Holder(); 84 runConcurrent( 85 () -> { 86 try { 87 h.val = doAllocate(100); 88 checkLE(base_state + 100, getAmountAllocated()); 89 sem.release(); 90 } catch (Exception e) { throw new Error("exception!", e); } 91 }, 92 () -> { 93 try { 94 sem.acquire(); 95 long after_acq = getAmountAllocated(); 96 doDeallocate(h.val); 97 checkLE(base_state + 100, after_acq); 98 } catch (Exception e) { throw new Error("exception!", e); } 99 } 100 ); 101 checkEq(base_state + 0, getAmountAllocated()); 102 103 // Try doing it with multiple jvmtienvs. 104 long env1 = newJvmtiEnv(); 105 long env2 = newJvmtiEnv(); 106 107 final long new_base_state = getAmountAllocated(); 108 // new jvmtienvs shouldn't save us memory. 109 checkLE(base_state, new_base_state); 110 // Make sure we track both. 111 abc = doAllocate(env1, 10); 112 checkLE(new_base_state + 10, getAmountAllocated()); 113 def = doAllocate(env2, 10); 114 checkLE(new_base_state + 20, getAmountAllocated()); 115 doDeallocate(env1, abc); 116 checkLE(new_base_state + 10, getAmountAllocated()); 117 118 doDeallocate(env2, def); 119 120 checkEq(new_base_state + 0, getAmountAllocated()); 121 122 destroyJvmtiEnv(env1); 123 destroyJvmtiEnv(env2); 124 125 // Back to normal after getting rid of the envs. 126 checkEq(base_state + 0, getAmountAllocated()); 127 128 // Try adding some tags 129 Object a = new Object(); 130 Object b = new Object(); 131 Main.setTag(a, 100); 132 Main.setTag(b, 200); 133 134 // tags should be counted and should have some data associated with them. 135 checkLE(base_state + 1, getAmountAllocated()); 136 } 137 doAllocate(long jvmtienv, long size)138 private static native long doAllocate(long jvmtienv, long size); doAllocate(long size)139 private static long doAllocate(long size) { 140 return doAllocate(getDefaultJvmtiEnv(), size); 141 } 142 doDeallocate(long jvmtienv, long ptr)143 private static native void doDeallocate(long jvmtienv, long ptr); doDeallocate(long size)144 private static void doDeallocate(long size) { 145 doDeallocate(getDefaultJvmtiEnv(), size); 146 } 147 getDefaultJvmtiEnv()148 private static native long getDefaultJvmtiEnv(); newJvmtiEnv()149 private static native long newJvmtiEnv(); destroyJvmtiEnv(long jvmtienv)150 private static native void destroyJvmtiEnv(long jvmtienv); getAmountAllocated()151 private static native long getAmountAllocated(); initializeTest()152 private static native void initializeTest(); 153 } 154