blob: 4b76243398a6ca605dd9fbbe140f59c7918bae22 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 4959889
27 * @summary Basic unit test of memory management testing:
28 * 1) setCollectionUsageThreshold() and getCollectionUsageThreshold()
29 * 2) test notification emitted for two different memory pools.
30 *
31 * @author Mandy Chung
32 *
33 * @build CollectionUsageThreshold MemoryUtil
34 * @run main/timeout=300 CollectionUsageThreshold
35 */
36
37import java.lang.management.*;
38import java.util.*;
39import javax.management.*;
40import javax.management.openmbean.CompositeData;
41
42public class CollectionUsageThreshold {
43 private static MemoryMXBean mm = ManagementFactory.getMemoryMXBean();
44 private static List pools = ManagementFactory.getMemoryPoolMXBeans();
45 private static List managers = ManagementFactory.getMemoryManagerMXBeans();
46 private static Map result = new HashMap();
47 private static boolean trace = false;
48 private static boolean testFailed = false;
49 private static final int EXPECTED_NUM_POOLS = 2;
50 private static final int NUM_GCS = 3;
51 private static final int THRESHOLD = 10;
52 private static Checker checker;
53 private static int numGCs = 0;
54
55 static class PoolRecord {
56 private MemoryPoolMXBean pool;
57 private int listenerInvoked = 0;
58 private long notifCount = 0;
59 PoolRecord(MemoryPoolMXBean p) {
60 this.pool = p;
61 }
62 int getListenerInvokedCount() {
63 return listenerInvoked;
64 }
65 long getNotifCount() {
66 return notifCount;
67 }
68 MemoryPoolMXBean getPool() {
69 return pool;
70 }
71 void addNotification(MemoryNotificationInfo minfo) {
72 listenerInvoked++;
73 notifCount = minfo.getCount();
74 }
75 }
76
77 static class SensorListener implements NotificationListener {
78 private int numNotifs = 0;
79 public void handleNotification(Notification notif, Object handback) {
80 String type = notif.getType();
81 if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) ||
82 type.equals(MemoryNotificationInfo.
83 MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) {
84 MemoryNotificationInfo minfo = MemoryNotificationInfo.
85 from((CompositeData) notif.getUserData());
86
87 MemoryUtil.printMemoryNotificationInfo(minfo, type);
88 PoolRecord pr = (PoolRecord) result.get(minfo.getPoolName());
89 if (pr == null) {
90 throw new RuntimeException("Pool " + minfo.getPoolName() +
91 " is not selected");
92 }
93 if (type != MemoryNotificationInfo.
94 MEMORY_COLLECTION_THRESHOLD_EXCEEDED) {
95 throw new RuntimeException("Pool " + minfo.getPoolName() +
96 " got unexpected notification type: " +
97 type);
98 }
99 pr.addNotification(minfo);
100 synchronized (this) {
101 numNotifs++;
102 if (numNotifs > 0 && (numNotifs % EXPECTED_NUM_POOLS) == 0) {
103 checker.goCheckResult();
104 }
105 }
106 }
107 }
108 }
109
110 private static long newThreshold;
111 public static void main(String args[]) throws Exception {
112 if (args.length > 0 && args[0].equals("trace")) {
113 trace = true;
114 }
115
116 if (trace) {
117 MemoryUtil.printMemoryPools(pools);
118 MemoryUtil.printMemoryManagers(managers);
119 }
120
121 // Find the Old generation which supports low memory detection
122 for (ListIterator iter = pools.listIterator(); iter.hasNext(); ) {
123 MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next();
124 MemoryUsage u = p.getUsage();
125 if (p.isUsageThresholdSupported() && p.isCollectionUsageThresholdSupported()) {
126 PoolRecord pr = new PoolRecord(p);
127 result.put(p.getName(), pr);
128 if (result.size() == EXPECTED_NUM_POOLS) {
129 break;
130 }
131 }
132 }
133 if (result.size() != EXPECTED_NUM_POOLS) {
134 throw new RuntimeException("Unexpected number of selected pools");
135 }
136
137 checker = new Checker("Checker thread");
138 checker.setDaemon(true);
139 checker.start();
140
141 for (Iterator iter = result.values().iterator(); iter.hasNext();) {
142 PoolRecord pr = (PoolRecord) iter.next();
143 pr.getPool().setCollectionUsageThreshold(THRESHOLD);
144 System.out.println("Collection usage threshold of " +
145 pr.getPool().getName() + " set to " + THRESHOLD);
146 }
147
148 SensorListener listener = new SensorListener();
149 NotificationEmitter emitter = (NotificationEmitter) mm;
150 emitter.addNotificationListener(listener, null, null);
151
152 mm.setVerbose(true);
153 for (int i = 0; i < NUM_GCS; i++) {
154 invokeGC();
155 checker.waitForCheckResult();
156 }
157
158 if (testFailed)
159 throw new RuntimeException("TEST FAILED.");
160
161 System.out.println("Test passed.");
162
163 }
164
165 private static void invokeGC() {
166 System.out.println("Calling System.gc()");
167 numGCs++;
168 mm.gc();
169
170 if (trace) {
171 for (Iterator iter = result.values().iterator(); iter.hasNext();) {
172 PoolRecord pr = (PoolRecord) iter.next();
173 System.out.println("Usage after GC for: " + pr.getPool().getName());
174 MemoryUtil.printMemoryUsage(pr.getPool().getUsage());
175 }
176 }
177 }
178
179 static class Checker extends Thread {
180 private Object lock = new Object();
181 private Object go = new Object();
182 private boolean checkerReady = false;
183 private int waiters = 0;
184 private boolean readyToCheck = false;
185 Checker(String name) {
186 super(name);
187 };
188 public void run() {
189 while (true) {
190 synchronized (lock) {
191 checkerReady = true;
192 try {
193 lock.wait();
194 } catch (InterruptedException e) {
195 // ignore
196 }
197 checkResult();
198 checkerReady = false;
199 }
200 }
201 }
202 private void checkResult() {
203 for (Iterator iter = result.values().iterator(); iter.hasNext();) {
204 PoolRecord pr = (PoolRecord) iter.next();
205 if (pr.getListenerInvokedCount() != numGCs) {
206 throw new RuntimeException("Listeners invoked count = " +
207 pr.getListenerInvokedCount() + " expected to be " +
208 numGCs);
209 }
210 if (pr.getNotifCount() != numGCs) {
211 throw new RuntimeException("Notif Count = " +
212 pr.getNotifCount() + " expected to be " +
213 numGCs);
214 }
215
216 long count = pr.getPool().getCollectionUsageThresholdCount();
217 if (count != numGCs) {
218 throw new RuntimeException("CollectionUsageThresholdCount = " +
219 count + " expected to be " + numGCs);
220 }
221 if (!pr.getPool().isCollectionUsageThresholdExceeded()) {
222 throw new RuntimeException("isCollectionUsageThresholdExceeded" +
223 " expected to be true");
224 }
225 }
226 synchronized (go) {
227 // wait until the main thread is waiting for notification
228 while (waiters == 0) {
229 try {
230 go.wait(50);
231 } catch (InterruptedException e) {
232 // ignore
233 }
234 }
235
236 System.out.println(Thread.currentThread().getName() +
237 " notifying main thread to continue - result checking finished");
238 go.notify();
239 }
240 }
241 public void goCheckResult() {
242 System.out.println(Thread.currentThread().getName() +
243 " notifying to check result");
244 synchronized (lock) {
245 while (!checkerReady) {
246 try {
247 lock.wait(50);
248 } catch (InterruptedException e) {
249 // ignore
250 }
251 }
252 lock.notify();
253 }
254 }
255
256 public void waitForCheckResult() {
257 System.out.println(Thread.currentThread().getName() +
258 " waiting for result checking finishes");
259 synchronized (go) {
260 waiters++;
261 try {
262 go.wait();
263 } catch (InterruptedException e) {
264 // ignore
265 }
266 waiters--;
267 }
268 }
269 }
270}