| /* |
| * Copyright (C) 2016 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. |
| */ |
| |
| package art; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.Semaphore; |
| |
| public class Test1900 { |
| public static void checkLE(long exp, long o) { |
| if (exp > o) { |
| throw new Error("Expected: " + exp + " Got: " + o); |
| } |
| } |
| public static void checkEq(long exp, long o) { |
| if (exp != o) { |
| throw new Error("Expected: " + exp + " Got: " + o); |
| } |
| } |
| |
| public static void runConcurrent(Runnable... rs) throws Exception { |
| final CountDownLatch latch = new CountDownLatch(rs.length); |
| Thread[] thrs = new Thread[rs.length]; |
| for (int i = 0; i < rs.length; i++) { |
| final Runnable r = rs[i]; |
| thrs[i] = new Thread(() -> { |
| latch.countDown(); |
| r.run(); |
| }); |
| thrs[i].start(); |
| } |
| for (Thread thr : thrs) { |
| thr.join(); |
| } |
| } |
| static class Holder { |
| public long val; |
| } |
| |
| public static void run() throws Exception { |
| initializeTest(); |
| // Get the overhead for the native part of this test. |
| final long base_state = getAmountAllocated(); |
| |
| // Basic alloc-dealloc |
| checkEq(base_state + 0, getAmountAllocated()); |
| long abc = doAllocate(10); |
| checkLE(base_state + 10, getAmountAllocated()); |
| long def = doAllocate(10); |
| checkLE(base_state + 20, getAmountAllocated()); |
| doDeallocate(abc); |
| checkLE(base_state + 10, getAmountAllocated()); |
| |
| doDeallocate(def); |
| |
| checkEq(base_state + 0, getAmountAllocated()); |
| |
| // Try doing it concurrently. |
| Runnable add10 = () -> { long x = doAllocate(10); doDeallocate(x); }; |
| Runnable[] rs = new Runnable[100]; |
| Arrays.fill(rs, add10); |
| runConcurrent(rs); |
| checkEq(base_state + 0, getAmountAllocated()); |
| |
| // Try doing it concurrently with different threads to allocate and deallocate. |
| final Semaphore sem = new Semaphore(0); |
| final Holder h = new Holder(); |
| runConcurrent( |
| () -> { |
| try { |
| h.val = doAllocate(100); |
| checkLE(base_state + 100, getAmountAllocated()); |
| sem.release(); |
| } catch (Exception e) { throw new Error("exception!", e); } |
| }, |
| () -> { |
| try { |
| sem.acquire(); |
| long after_acq = getAmountAllocated(); |
| doDeallocate(h.val); |
| checkLE(base_state + 100, after_acq); |
| } catch (Exception e) { throw new Error("exception!", e); } |
| } |
| ); |
| checkEq(base_state + 0, getAmountAllocated()); |
| |
| // Try doing it with multiple jvmtienvs. |
| long env1 = newJvmtiEnv(); |
| long env2 = newJvmtiEnv(); |
| |
| final long new_base_state = getAmountAllocated(); |
| // new jvmtienvs shouldn't save us memory. |
| checkLE(base_state, new_base_state); |
| // Make sure we track both. |
| abc = doAllocate(env1, 10); |
| checkLE(new_base_state + 10, getAmountAllocated()); |
| def = doAllocate(env2, 10); |
| checkLE(new_base_state + 20, getAmountAllocated()); |
| doDeallocate(env1, abc); |
| checkLE(new_base_state + 10, getAmountAllocated()); |
| |
| doDeallocate(env2, def); |
| |
| checkEq(new_base_state + 0, getAmountAllocated()); |
| |
| destroyJvmtiEnv(env1); |
| destroyJvmtiEnv(env2); |
| |
| // Back to normal after getting rid of the envs. |
| checkEq(base_state + 0, getAmountAllocated()); |
| |
| // Try adding some tags |
| Object a = new Object(); |
| Object b = new Object(); |
| Main.setTag(a, 100); |
| Main.setTag(b, 200); |
| |
| // tags should be counted and should have some data associated with them. |
| checkLE(base_state + 1, getAmountAllocated()); |
| } |
| |
| private static native long doAllocate(long jvmtienv, long size); |
| private static long doAllocate(long size) { |
| return doAllocate(getDefaultJvmtiEnv(), size); |
| } |
| |
| private static native void doDeallocate(long jvmtienv, long ptr); |
| private static void doDeallocate(long size) { |
| doDeallocate(getDefaultJvmtiEnv(), size); |
| } |
| |
| private static native long getDefaultJvmtiEnv(); |
| private static native long newJvmtiEnv(); |
| private static native void destroyJvmtiEnv(long jvmtienv); |
| private static native long getAmountAllocated(); |
| private static native void initializeTest(); |
| } |