1 /*
2  * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package nsk.monitoring.ThreadMXBean;
25 
26 import java.util.ArrayList;
27 import java.util.List;
28 import nsk.share.gc.gp.GarbageProducer;
29 import nsk.share.gc.gp.GarbageUtils;
30 import nsk.share.test.Stresser;
31 
32 
33 public class MXBeanTestThread extends Thread {
34 
35     /**
36      * BarrierHandler instance for synchronization with management thread
37      */
38     protected BarrierHandler handler;
39 
40     /**
41      * List where allocated objects are stored
42      */
43     private List<Object> allocatedList;
44     /**
45      * Number of simultaneously running threads
46      */
47     private static int threadCount;
48     /**
49      * java.util.Random instance for stress test (allocateStress())
50      */
51     private java.util.Random random = new java.util.Random();
52     /**
53      * Expected amount of memory allocated during stress test
54      */
55     private long stressAllocatedBytes;
56     /**
57      * Maximum memory in bytes that one thread is allowed to use at once
58      */
59     private long maxThreadMemory = 0;
60     /**
61      * GarbageProducer for objects creation
62      */
63     private GarbageProducer gp;
64     /**
65      * Stresser instance for allocateStress()
66      */
67     private Stresser stresser;
68 
warmUp(String garbageProducerId)69     public static void warmUp(String garbageProducerId) {
70         MXBeanTestThread warmUpThread = new MXBeanTestThread(garbageProducerId) {
71                 @Override
72                 public void doWork() {
73                     allocate();
74                 }
75             };
76         warmUpThread.start();
77         do {
78             try {
79                 warmUpThread.join();
80             } catch (InterruptedException ie) {}
81         } while(warmUpThread.isAlive());
82     }
83 
84     /**
85      * Sets BarrierHandler for this thread
86      *
87      * @param handler BarrierHandler to synchronize with
88      */
setHandler(BarrierHandler handler)89     public void setHandler(BarrierHandler handler) {
90         this.handler = handler;
91     }
92 
93     /**
94      * Returns an instance of MXBeanTestThread with already defined
95      * allocatedList List and GarbageProducer
96      */
MXBeanTestThread(String garbageProducerId)97     public MXBeanTestThread(String garbageProducerId) {
98         super(Integer.toString(++threadCount));
99         allocatedList = new ArrayList<Object>();
100         gp = GarbageUtils.getGarbageProducer(garbageProducerId);
101         maxThreadMemory = Runtime.getRuntime().maxMemory()/4;
102     }
103 
104     /**
105      * Returns an instance of MXBeanTestThread with already defined
106      * allocatedList List and default GarbageProducer
107      */
MXBeanTestThread()108     public MXBeanTestThread() {
109         this("intArr");
110     }
111 
112     /**
113      * Returns an instance of MXBeanTestThread with already defined
114      * allocatedList List and Stresser
115      */
MXBeanTestThread(Stresser stresser)116     public MXBeanTestThread(Stresser stresser) {
117         this("intArr");
118         this.stresser = stresser;
119     }
120 
121     /**
122      * Sets maximum amount of memory that could be used at once for each
123      * TestThread in StressTest
124      */
setMaxThreadMemory(long memory)125     public void setMaxThreadMemory (long memory) {
126         maxThreadMemory = memory;
127     }
128 
129     /**
130      * Returns expected memory allocated by TestThread during StressTest
131      * @return expected memory amount
132      */
getStressAllocatedBytes()133     public long getStressAllocatedBytes() {
134         return stressAllocatedBytes;
135     }
136 
137     @Override
run()138     public void run() {
139         doWork();
140     }
141 
142     /**
143      * Implementation of TestThread behavior logic
144      */
doWork()145     public void doWork() {
146         handler.ready();
147         allocate();
148         handler.ready();
149     }
150 
151     /**
152      * Allocates memory for amount of time specified in Stresser instance
153      */
allocateStress()154     protected void allocateStress() {
155         // Size of long[] array that allocates 2 Mb + 1 byte
156         int MAX_ARR_SIZE=262146;
157         // Anount of memory allocated by thread with existing links
158         // Which means that these objects can't be collected by GC
159         long actuallyAllocated = 0;
160         try {
161             while (stresser.continueExecution()) {
162                 //int chunkSize = random.nextInt(MAX_OBJECT_SIZE);
163                 //Object obj = gp.create(chunkSize);
164                 int chunkSize = random.nextInt(MAX_ARR_SIZE);
165                 Object obj = new long[chunkSize];
166                 allocatedList.add(obj);
167                 actuallyAllocated += chunkSize*8;
168                 if (actuallyAllocated > maxThreadMemory) {
169                     // Allocated more then allowed to one thread
170                     // re-define allocatedList to allow GC to delete
171                     // created objects
172                     stressAllocatedBytes += actuallyAllocated;
173                     actuallyAllocated = 0;
174                     allocatedList = new ArrayList<Object>();
175                 }
176             }
177         } catch (OutOfMemoryError e) {
178         } finally {
179             stressAllocatedBytes += actuallyAllocated;
180         }
181     }
182 
183     /**
184      * Allocates memory once according test settings
185      */
allocate()186     protected void allocate() {
187         long actuallyAllocated = 0;
188         for (int i = 0; i < ThreadMXBeanTestBase.allocArr.length; i++) {
189             long size = ThreadMXBeanTestBase.allocArr[i];
190             if (actuallyAllocated + size > maxThreadMemory) {
191                 break;
192             }
193             allocatedList.add(gp.create(size));
194             actuallyAllocated += size;
195         }
196     }
197 }
198