Home | History | Annotate | Download | only in art
      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 {
     26   public static void checkLE(long exp, long o) {
     27     if (exp > o) {
     28       throw new Error("Expected: " + exp + " Got: " + o);
     29     }
     30   }
     31   public static void checkEq(long exp, long o) {
     32     if (exp != o) {
     33       throw new Error("Expected: " + exp + " Got: " + o);
     34     }
     35   }
     36 
     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 
     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 
    138   private static native long doAllocate(long jvmtienv, long size);
    139   private static long doAllocate(long size) {
    140     return doAllocate(getDefaultJvmtiEnv(), size);
    141   }
    142 
    143   private static native void doDeallocate(long jvmtienv, long ptr);
    144   private static void doDeallocate(long size) {
    145     doDeallocate(getDefaultJvmtiEnv(), size);
    146   }
    147 
    148   private static native long getDefaultJvmtiEnv();
    149   private static native long newJvmtiEnv();
    150   private static native void destroyJvmtiEnv(long jvmtienv);
    151   private static native long getAmountAllocated();
    152   private static native void initializeTest();
    153 }
    154