1 /*
2  * Copyright (c) 2003, 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 package nsk.monitoring.share;
24 
25 import java.lang.management.*;
26 import javax.management.*;
27 import javax.management.openmbean.*;
28 import java.util.*;
29 
30 import nsk.share.*;
31 
32 /**
33  * <code>MemoryMonitor</code> class is a wrapper of <code>MemoryMXBean</code> and
34  * <code>MemoryPoolMXBean</code> interfaces. Depending on command line arguments,
35  * an instance of this class redirects invocations to the
36  * <code>MemoryMXBean</code> (or <code>MemoryPoolMXBean</code>) interface. If
37  * <code>-testMode="directly"</code> option is set, this instance directly
38  * invokes corresponding method of the <code>MemoryMXBean</code> (or
39  * <code>MemoryPoolMXBean</code>) interface. If <code>-testMode="server"</code>
40  * option is set it will make invocations via MBeanServer.
41  *
42  * @see ArgumentHandler
43  */
44 public class MemoryMonitor extends Monitor implements NotificationListener,
45         NotificationFilter {
46 
47     // Constants to define type of memory that will be allocated in
48     // MemoryMonitor. For heap memory objects will be allocated; for nonheap
49     // type classes will be loaded; for mixed type -- both (objects will be
50     // allocated and classes will be loaded).
51     public final static String HEAP_TYPE = "heap";
52     public final static String NONHEAP_TYPE = "nonheap";
53     public final static String MIXED_TYPE = "mixed";
54     // Names of the attributes of MemoryMXBean
55     private final static String POOL_TYPE = "Type";
56     private final static String POOL_RESET_PEAK = "resetPeakUsage";
57     private final static String POOL_PEAK = "PeakUsage";
58     private final static String POOL_VALID = "Valid";
59     private final static String POOL_U = "Usage";
60     private final static String UT = "UsageThreshold";
61     private final static String UT_COUNT = "UsageThresholdCount";
62     private final static String UT_SUPPORT = "UsageThresholdSupported";
63     private final static String UT_EXCEEDED = "UsageThresholdExceeded";
64     private final static String POOL_CU = "CollectionUsage";
65     private final static String CT = "CollectionUsageThreshold";
66     private final static String CT_COUNT = "CollectionUsageThresholdCount";
67     private final static String CT_SUPPORT = "CollectionUsageThresholdSupported";
68     private final static String CT_EXCEEDED = "CollectionUsageThresholdExceeded";
69     // Varibales to store options that are passed to the test
70     private static String memory;
71     private static int mode;
72     private static boolean isNotification;
73     private static boolean isUsageThreshold;
74     private static volatile boolean passed = true;
75     private Polling polling = new Polling();
76 
77     static {
78         Monitor.logPrefix = "MemoryMonitor   > ";
79     }
80 
81     /**
82      * Creates a new <code>MemoryMonitor</code> object.
83      *
84      * @param log <code>Log</code> object to print info to.
85      * @param handler <code>ArgumentHandler</code> object that saves
86      *        all info about test's arguments.
87      *
88      */
MemoryMonitor(Log log, ArgumentHandler handler)89     public MemoryMonitor(Log log, ArgumentHandler handler) {
90         super(log, handler);
91 
92         memory = handler.getTestedMemory();
93         mode = getTestMode();
94         isNotification = (handler.MON_NOTIF.equals(handler.getMonitoring()));
95         isUsageThreshold = (handler.TH_USAGE.equals(handler.getThreshold()));
96 
97         String s = "\t(This setting is used in lowmem* tests only)";
98 
99         display("Memory:\t" + handler.getTestedMemory() + s);
100         display("Monitoring:\t" + handler.getMonitoring() + s);
101         display("Threshold:\t" + handler.getThreshold() + s);
102         display("Timeout:\t" + handler.getTimeout() + s);
103     }
104 
105     /**
106      * Returns <code>true</code> if no failures were revealed during the test,
107      * <code>false</code> otherwise.
108      *
109      * @return <code>true</code> if no failures were revealed during the test,
110      * <code>false</code> otherwise.
111      *
112      */
getPassedStatus()113     public boolean getPassedStatus() {
114         return passed;
115     }
116 
117     /**
118      * Enables memory monitoring.
119      * <p>
120      * If notification type of monitoring is chosen, the method adds {@link
121      * javax.management.NotificationListener
122      * <code>javax.management.NotificationListener</code>} to enables low
123      * memory detection support. If monitoring type is polling, a new thread
124      * that manages the low memory detection is started.
125      *
126      * @throws InstanceNotFoundException The MemoryMXBean is not registered on
127      *                                   the server.
128      */
enableMonitoring()129     public void enableMonitoring() throws InstanceNotFoundException {
130         if (isNotification) {
131             switch (mode) {
132                 case DIRECTLY_MODE:
133                     MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
134                     NotificationEmitter emitter = (NotificationEmitter) mbean;
135                     emitter.addNotificationListener(this, this, null);
136                     break;
137 
138                 case SERVER_MODE:
139                 case PROXY_MODE:
140                     getMBeanServer().addNotificationListener(mbeanObjectName,
141                             this, this, null);
142                     break;
143 
144                 default:
145                     throw new TestBug("Unknown testMode " + mode);
146             }
147         } else {
148 
149             // Polling
150             // Start a thread that will manage all test modes
151             polling.start();
152 
153         }
154     } // enableMonitoring()
155 
156     /**
157      * Disables memory monitoring.
158      * <p>
159      * If monitoring type is polling, the thread that manages the low memory
160      * detection is stopped.
161      */
disableMonitoring()162     public void disableMonitoring() {
163         if (!isNotification) {
164 
165             // Stop polling thread
166             polling.goOn = false;
167         }
168     } // disableMonitoring()
169 
170     /**
171      * Updates thresholds. Thresholds values for all pools will be greater
172      * than <code>used</code> value.
173      * <p>
174      * If <code>usage</code> thresholds are chosen, the method updates just
175      * pools that support usage thresholds. If <code>collection</code>
176      * thresholds are chosen, the method updates memory pools that support
177      * collection usage thresholds.
178      *
179      * This method is synchronized because it may be invoked from
180      * <code>handleNotification</code> which is potentially done from
181      * multiple threads.
182      */
updateThresholds()183     public synchronized void updateThresholds() {
184         if (isUsageThreshold) {
185             updateUsageThresholds();
186         } else {
187             updateCollectionThresholds();
188         }
189     }
190 
191     /**
192      * Reset thresholds. Thresholds values for all pools will be 1.
193      * If <code>usage</code> thresholds are chosen, the method updates just
194      * pools that support usage thresholds. If <code>collection</code>
195      * thresholds are chosen, the method updates memory pools that support
196      * collection usage thresholds.
197      *
198      * This method is synchronized because it may be invoked from
199      * multiple threads.
200      */
resetThresholds(MemoryType type)201     public synchronized void resetThresholds(MemoryType type) {
202         List pools = getMemoryPoolMBeans();
203         for (int i = 0; i < pools.size(); i++) {
204             Object pool = pools.get(i);
205             if (isUsageThresholdSupported(pool)) {
206                 if (getType(pool).equals(type)) {
207                     setUsageThreshold(pool, 1);
208                 }
209             }
210         }
211     }
212 
213     /**
214      * The method is invoked before sending the notification to the listener.
215      *
216      * @param notification The notification to be sent.
217      * @return <i>true</i> if the notification has to be sent to the listener;
218      *         <i>false</i> otherwise.
219      *
220      * @see javax.management.NotificationFilter
221      */
isNotificationEnabled(Notification notification)222     public boolean isNotificationEnabled(Notification notification) {
223         String type = notification.getType();
224         String usage = MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED;
225         String collection = MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED;
226 
227         if (isUsageThreshold) {
228             return type.equals(usage);
229         } else {
230             return type.equals(collection);
231         }
232     } // isNotificationEnabled()
233 
234     /**
235      * The method is invoked when a JMX notification occurs.
236      *
237      * @param notification The notification to be sent.
238      * @param handback An opaque object which helps the listener to associate
239      *        information regarding the MBean emitter.
240      * @see javax.management.NotificationListener
241      */
handleNotification(Notification notification, Object handback)242     public void handleNotification(Notification notification, Object handback) {
243         CompositeData data = (CompositeData) notification.getUserData();
244         MemoryNotificationInfo mn = MemoryNotificationInfo.from(data);
245 
246         display(mn.getCount() + " notification \"" + notification.getMessage()
247                 + "\" is caught on " + (new Date(notification.getTimeStamp()))
248                 + " by " + mn.getPoolName() + " (" + mn.getUsage() + ")");
249         updateThresholds();
250     } // handleNotification()
251 
252     /**
253      * Redirects the invocation to {@link
254      * java.lang.management.MemoryPoolMXBean#resetPeakUsage
255      * <code>MemoryPoolMXBean.resetPeakUsage()</code>}.
256      *
257      * @param poolObject reference to the pool. The pool may be specified
258      *        either by <code>ObjectName</code>, or
259      *        <code>MemoryPoolMXBean</code>.
260      */
resetPeakUsage(Object poolObject)261     public void resetPeakUsage(Object poolObject) {
262         switch (mode) {
263             case DIRECTLY_MODE:
264                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
265                 directPool.resetPeakUsage();
266                 break;
267 
268             case SERVER_MODE:
269                 ObjectName serverPool = (ObjectName) poolObject;
270 
271                 try {
272                     getMBeanServer().invoke(serverPool, POOL_RESET_PEAK,
273                             null, null);
274                 } catch (Exception e) {
275                     e.printStackTrace(logger.getOutStream());
276                     throw new Failure(e);
277                 }
278                 break;
279 
280             case PROXY_MODE:
281                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
282                 proxyPool.resetPeakUsage();
283                 break;
284 
285             default:
286                 throw new TestBug("Unknown testMode " + mode);
287         }
288     } // resetPeakUsage()
289 
290     /**
291      * Redirects the invocation to {@link
292      * java.lang.management.MemoryPoolMXBean#getPeakUsage
293      * <code>MemoryPoolMXBean.getPeakUsage()</code>}.
294      *
295      * @param poolObject reference to the pool. The pool may be specified
296      *        either by <code>ObjectName</code>, or
297      *        <code>MemoryPoolMXBean</code>.
298      * @return a <code>MemoryUsage</code> object representing the peak memory
299      *         usage; <code>null</code> otherwise.
300      */
getPeakUsage(Object poolObject)301     public MemoryUsage getPeakUsage(Object poolObject) {
302         switch (mode) {
303             case DIRECTLY_MODE:
304                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
305                 return directPool.getPeakUsage();
306 
307             case SERVER_MODE:
308                 ObjectName serverPool = (ObjectName) poolObject;
309                 return getMemoryUsageAttribute(serverPool, POOL_PEAK);
310 
311             case PROXY_MODE:
312                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
313                 return proxyPool.getPeakUsage();
314 
315             default:
316                 throw new TestBug("Unknown testMode " + mode);
317         }
318     } // getPeakUsage()
319 
320     /**
321      * Redirects the invocation to {@link
322      * java.lang.management.MemoryPoolMXBean#getUsage
323      * <code>MemoryPoolMXBean.getUsage()</code>}.
324      *
325      * @param poolObject reference to the pool. The pool may be specified
326      *        either by <code>ObjectName</code>, or
327      *        <code>MemoryPoolMXBean</code>.
328      * @return a <code>MemoryUsage</code> object; or <code>null</code> if this
329      *         pool not valid.
330      */
getUsage(Object poolObject)331     public MemoryUsage getUsage(Object poolObject) {
332         switch (mode) {
333             case DIRECTLY_MODE:
334                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
335                 return directPool.getUsage();
336 
337             case SERVER_MODE:
338                 ObjectName serverPool = (ObjectName) poolObject;
339                 return getUsageOnServer(serverPool);
340 
341             case PROXY_MODE:
342                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
343                 return proxyPool.getUsage();
344 
345             default:
346                 throw new TestBug("Unknown testMode " + mode);
347         }
348     } // getUsage()
349 
350     /**
351      * Redirects the invocation to {@link
352      * java.lang.management.MemoryPoolMXBean#getCollectionUsage
353      * <code>MemoryPoolMXBean.getCollectionUsage()</code>}.
354      *
355      * @param poolObject reference to the pool. The pool may be specified
356      *        either by <code>ObjectName</code>, or
357      *        <code>MemoryPoolMXBean</code>.
358      * @return a <code>MemoryUsage</code> object; or <code>null</code> if this
359      *         method is not supported.
360      */
getCollectionUsage(Object poolObject)361     public MemoryUsage getCollectionUsage(Object poolObject) {
362         switch (mode) {
363             case DIRECTLY_MODE:
364                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
365                 return directPool.getCollectionUsage();
366 
367             case SERVER_MODE:
368                 ObjectName serverPool = (ObjectName) poolObject;
369                 return getCollectionUsageOnServer(serverPool);
370 
371             case PROXY_MODE:
372                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
373                 return proxyPool.getCollectionUsage();
374 
375             default:
376                 throw new TestBug("Unknown testMode " + mode);
377         }
378     } // getCollectionUsage()
379 
380     /**
381      * Redirects the invocation to {@link
382      * java.lang.management.MemoryPoolMXBean#isValid
383      * <code>MemoryPoolMXBean.isValid()</code>}.
384      *
385      * @param poolObject reference to the pool. The pool may be specified
386      *        either by <code>ObjectName</code>, or
387      *        <code>MemoryPoolMXBean</code>.
388      * @return a <code>true</code> if the memory pool is valid in the running
389      *         JVM; <code>null</code> otherwise.
390      */
isValid(Object poolObject)391     public boolean isValid(Object poolObject) {
392         switch (mode) {
393             case DIRECTLY_MODE:
394                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
395                 return directPool.isValid();
396 
397             case SERVER_MODE:
398                 ObjectName serverPool = (ObjectName) poolObject;
399                 return getBooleanAttribute(serverPool, POOL_VALID);
400 
401             case PROXY_MODE:
402                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
403                 return proxyPool.isValid();
404 
405             default:
406                 throw new TestBug("Unknown testMode " + mode);
407         }
408     } // isValid()
409 
410     /**
411      * Redirects the invocation to {@link
412      * java.lang.management.MemoryPoolMXBean#isUsageThresholdSupported
413      * <code>MemoryPoolMXBean.isUsageThresholdSupported()</code>}.
414      *
415      * @param poolObject reference to the pool. The pool may be specified
416      *        either by <code>ObjectName</code>, or
417      *        <code>MemoryPoolMXBean</code>.
418      * @return a <code>true</code> if the memory pool supports usage threshold;
419      *         <code>null</code> otherwise.
420      */
isUsageThresholdSupported(Object poolObject)421     public boolean isUsageThresholdSupported(Object poolObject) {
422         switch (mode) {
423             case DIRECTLY_MODE:
424                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
425                 return directPool.isUsageThresholdSupported();
426 
427             case SERVER_MODE:
428                 ObjectName serverPool = (ObjectName) poolObject;
429                 return isUsageThresholdSupportedOnServer(serverPool);
430 
431             case PROXY_MODE:
432                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
433                 return proxyPool.isUsageThresholdSupported();
434 
435             default:
436                 throw new TestBug("Unknown testMode " + mode);
437         }
438     } // isUsageThresholdSupported()
439 
440     /**
441      * Redirects the invocation to {@link
442      * java.lang.management.MemoryPoolMXBean#isCollectionUsageThresholdSupported
443      * <code>MemoryPoolMXBean.isCollectionUsageThresholdSupported()</code>}.
444      *
445      * @param poolObject reference to the pool. The pool may be specified
446      *        either by <code>ObjectName</code>, or
447      *        <code>MemoryPoolMXBean</code>.
448      * @return a <code>true</code> if the memory pool supports collection
449      *         usage threshold; <code>null</code> otherwise.
450      */
isCollectionThresholdSupported(Object poolObject)451     public boolean isCollectionThresholdSupported(Object poolObject) {
452         switch (mode) {
453             case DIRECTLY_MODE:
454                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
455                 return directPool.isCollectionUsageThresholdSupported();
456 
457             case SERVER_MODE:
458                 ObjectName serverPool = (ObjectName) poolObject;
459                 return isCollectionThresholdSupportedOnServer(serverPool);
460 
461             case PROXY_MODE:
462                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
463                 return proxyPool.isCollectionUsageThresholdSupported();
464 
465             default:
466                 throw new TestBug("Unknown testMode " + mode);
467         }
468     } // isCollectionThresholdSupported()
469 
470     /**
471      * Redirects the invocation to {@link
472      * java.lang.management.MemoryPoolMXBean#isUsageThresholdExceeded
473      * <code>MemoryPoolMXBean.isUsageThresholdExceeded()</code>}.
474      *
475      * @param poolObject reference to the pool. The pool may be specified
476      *        either by <code>ObjectName</code>, or
477      *        <code>MemoryPoolMXBean</code>.
478      * @return a <code>true</code> if the memory usage of this pool reaches or
479      *         exceeds the threshold value; <code>null</code> otherwise.
480      */
isUsageThresholdExceeded(Object poolObject)481     public boolean isUsageThresholdExceeded(Object poolObject) {
482         switch (mode) {
483             case DIRECTLY_MODE:
484                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
485                 return directPool.isUsageThresholdExceeded();
486 
487             case SERVER_MODE:
488                 ObjectName serverPool = (ObjectName) poolObject;
489                 return isUsageThresholdExceededOnServer(serverPool);
490 
491             case PROXY_MODE:
492                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
493                 return proxyPool.isUsageThresholdExceeded();
494 
495             default:
496                 throw new TestBug("Unknown testMode " + mode);
497         }
498     } // isUsageThresholdExceeded()
499 
500     /**
501      * Redirects the invocation to {@link
502      * java.lang.management.MemoryPoolMXBean#isCollectionUsageThresholdExceeded
503      * <code>MemoryPoolMXBean.isCollectionUsageThresholdExceeded()</code>}.
504      *
505      * @param poolObject reference to the pool. The pool may be specified
506      *        either by <code>ObjectName</code>, or
507      *        <code>MemoryPoolMXBean</code>.
508      * @return a <code>true</code> if the memory usage of this pool reaches or
509      *         exceeds the collection usage threshold value in the most recent
510      *         collection; <code>null</code> otherwise.
511      */
isCollectionThresholdExceeded(Object poolObject)512     public boolean isCollectionThresholdExceeded(Object poolObject) {
513         switch (mode) {
514             case DIRECTLY_MODE:
515                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
516                 return directPool.isCollectionUsageThresholdExceeded();
517 
518             case SERVER_MODE:
519                 ObjectName serverPool = (ObjectName) poolObject;
520                 return isCollectionThresholdExceededOnServer(serverPool);
521 
522             case PROXY_MODE:
523                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
524                 return proxyPool.isCollectionUsageThresholdExceeded();
525 
526             default:
527                 throw new TestBug("Unknown testMode " + mode);
528         }
529     } // isCollectionThresholdExceeded()
530 
531     /**
532      * Redirects the invocation to {@link
533      * java.lang.management.MemoryPoolMXBean#getUsageThreshold
534      * <code>MemoryPoolMXBean.getUsageThreshold()</code>}.
535      *
536      * @param poolObject reference to the pool. The pool may be specified
537      *        either by <code>ObjectName</code>, or
538      *        <code>MemoryPoolMXBean</code>.
539      * @return the usage threshold value of this memory pool in bytes.
540      */
getUsageThreshold(Object poolObject)541     public long getUsageThreshold(Object poolObject) {
542         switch (mode) {
543             case DIRECTLY_MODE:
544                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
545                 return directPool.getUsageThreshold();
546 
547             case SERVER_MODE:
548                 ObjectName serverPool = (ObjectName) poolObject;
549                 return getUsageThresholdOnServer(serverPool);
550 
551             case PROXY_MODE:
552                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
553                 return proxyPool.getUsageThreshold();
554 
555             default:
556                 throw new TestBug("Unknown testMode " + mode);
557         }
558     } // getUsageThreshold()
559 
560     /**
561      * Redirects the invocation to {@link
562      * java.lang.management.MemoryPoolMXBean#getCollectionUsageThreshold
563      * <code>MemoryPoolMXBean.getCollectionUsageThreshold()</code>}.
564      *
565      * @param poolObject reference to the pool. The pool may be specified
566      *        either by <code>ObjectName</code>, or
567      *        <code>MemoryPoolMXBean</code>.
568      * @return the collection usage threshold value of this memory pool in
569      *         bytes.
570      */
getCollectionThreshold(Object poolObject)571     public long getCollectionThreshold(Object poolObject) {
572         switch (mode) {
573             case DIRECTLY_MODE:
574                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
575                 return directPool.getCollectionUsageThreshold();
576 
577             case SERVER_MODE:
578                 ObjectName serverPool = (ObjectName) poolObject;
579                 return getCollectionThresholdOnServer(serverPool);
580 
581             case PROXY_MODE:
582                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
583                 return proxyPool.getCollectionUsageThreshold();
584 
585             default:
586                 throw new TestBug("Unknown testMode " + mode);
587         }
588     } // getCollectionThreshold()
589 
590     /**
591      * Redirects the invocation to {@link
592      * java.lang.management.MemoryPoolMXBean#getUsageThresholdCount
593      * <code>MemoryPoolMXBean.getUsageThresholdCount()</code>}.
594      *
595      * @param poolObject reference to the pool. The pool may be specified
596      *        either by <code>ObjectName</code>, or
597      *        <code>MemoryPoolMXBean</code>.
598      * @return number of times that the memory usage has crossed its usage
599      *         threshold value.
600      */
getUsageThresholdCount(Object poolObject)601     public long getUsageThresholdCount(Object poolObject) {
602         switch (mode) {
603             case DIRECTLY_MODE:
604                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
605                 return directPool.getUsageThresholdCount();
606 
607             case SERVER_MODE:
608                 ObjectName serverPool = (ObjectName) poolObject;
609                 return getUsageThresholdCountOnServer(serverPool);
610 
611             case PROXY_MODE:
612                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
613                 return proxyPool.getUsageThresholdCount();
614 
615             default:
616                 throw new TestBug("Unknown testMode " + mode);
617         }
618     } // getUsageThresholdCount()
619 
620     /**
621      * Redirects the invocation to {@link
622      * java.lang.management.MemoryPoolMXBean#getCollectionUsageThresholdCount
623      * <code>MemoryPoolMXBean.getCollectionUsageThresholdCount()</code>}.
624      *
625      * @param poolObject reference to the pool. The pool may be specified
626      *        either by <code>ObjectName</code>, or
627      *        <code>MemoryPoolMXBean</code>.
628      * @return number of times that the memory usage has crossed its collection
629      *         usage threshold value.
630      */
getCollectionThresholdCount(Object poolObject)631     public long getCollectionThresholdCount(Object poolObject) {
632         switch (mode) {
633             case DIRECTLY_MODE:
634                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
635                 return directPool.getCollectionUsageThresholdCount();
636 
637             case SERVER_MODE:
638                 ObjectName serverPool = (ObjectName) poolObject;
639                 return getCollectionThresholdCountOnServer(serverPool);
640 
641             case PROXY_MODE:
642                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
643                 return proxyPool.getCollectionUsageThresholdCount();
644 
645             default:
646                 throw new TestBug("Unknown testMode " + mode);
647         }
648     } // getCollectionThresholdCount()
649 
650     /**
651      * Redirects the invocation to {@link
652      * java.lang.management.MemoryPoolMXBean#setUsageThreshold
653      * <code>MemoryPoolMXBean.setUsageThreshold()</code>}.
654      *
655      * @param poolObject reference to the pool. The pool may be specified
656      *        either by <code>ObjectName</code>, or
657      *        <code>MemoryPoolMXBean</code>.
658      * @param threshold the new threshold value.
659      */
setUsageThreshold(Object poolObject, long threshold)660     public void setUsageThreshold(Object poolObject, long threshold) {
661         switch (mode) {
662             case DIRECTLY_MODE:
663                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
664                 directPool.setUsageThreshold(threshold);
665                 break;
666 
667             case SERVER_MODE:
668                 ObjectName serverPool = (ObjectName) poolObject;
669                 setUsageThresholdOnServer(serverPool, threshold);
670                 break;
671 
672             case PROXY_MODE:
673                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
674                 proxyPool.setUsageThreshold(threshold);
675                 break;
676 
677             default:
678                 throw new TestBug("Unknown testMode " + mode);
679         }
680     } // setUsageThreshold()
681 
682     /**
683      * Redirects the invocation to {@link
684      * java.lang.management.MemoryPoolMXBean#setCollectionUsageThreshold
685      * <code>MemoryPoolMXBean.setCollectionUsageThreshold()</code>}.
686      *
687      * @param poolObject reference to the pool. The pool may be specified
688      *        either by <code>ObjectName</code>, or
689      *        <code>MemoryPoolMXBean</code>.
690      * @param threshold the new collection usage threshold value.
691      */
setCollectionThreshold(Object poolObject, long threshold)692     public void setCollectionThreshold(Object poolObject, long threshold) {
693         switch (mode) {
694             case DIRECTLY_MODE:
695                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
696                 directPool.setCollectionUsageThreshold(threshold);
697                 break;
698 
699             case SERVER_MODE:
700                 ObjectName serverPool = (ObjectName) poolObject;
701                 setCollectionThresholdOnServer(serverPool, threshold);
702                 break;
703 
704             case PROXY_MODE:
705                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
706                 proxyPool.setCollectionUsageThreshold(threshold);
707                 break;
708 
709             default:
710                 throw new TestBug("Unknown testMode " + mode);
711         }
712     } // setCollectionThreshold()
713 
714     /**
715      * Redirects the invocation to {@link
716      * java.lang.management.MemoryPoolMXBean#getName
717      * <code>MemoryPoolMXBean.getName()</code>}.
718      *
719      * @param poolObject reference to the pool. The pool may be specified
720      *        either by <code>ObjectName</code>, or
721      *        <code>MemoryPoolMXBean</code>.
722      * @return the name of the memory pool.
723      */
getName(Object poolObject)724     public String getName(Object poolObject) {
725         switch (mode) {
726             case DIRECTLY_MODE:
727                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
728                 return directPool.getName();
729 
730             case SERVER_MODE:
731                 ObjectName serverPool = (ObjectName) poolObject;
732                 return serverPool.toString();
733 
734             case PROXY_MODE:
735                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
736                 return proxyPool.getName();
737 
738             default:
739                 throw new TestBug("Unknown testMode " + mode);
740         }
741     } // getName()
742 
743     /**
744      * Redirects the invocation to {@link
745      * java.lang.management.MemoryPoolMXBean#getType
746      * <code>MemoryPoolMXBean.getType()</code>}.
747      *
748      * @param poolObject reference to the pool. The pool may be specified
749      *        either by <code>ObjectName</code>, or
750      *        <code>MemoryPoolMXBean</code>.
751      * @return the name of the memory pool.
752      */
getType(Object poolObject)753     public MemoryType getType(Object poolObject) {
754         switch (mode) {
755             case DIRECTLY_MODE:
756                 MemoryPoolMXBean directPool = (MemoryPoolMXBean) poolObject;
757                 return directPool.getType();
758 
759             case SERVER_MODE:
760                 ObjectName serverPool = (ObjectName) poolObject;
761                 return getType(serverPool);
762 
763             case PROXY_MODE:
764                 MemoryPoolMXBean proxyPool = (MemoryPoolMXBean) poolObject;
765                 return proxyPool.getType();
766 
767             default:
768                 throw new TestBug("Unknown testMode " + mode);
769         }
770     }
771 
772     /**
773      * Redirects the invocation to {@link
774      * java.lang.management.ManagementFactory#getMemoryPoolMXBeans
775      * <code>ManagementFactory.getMemoryPoolMXBeans()</code>}.
776      *
777      * @return a list of <code>MemoryPoolMXBean</code> objects.
778      */
getMemoryPoolMBeans()779     public List<? extends Object> getMemoryPoolMBeans() {
780         switch (mode) {
781             case DIRECTLY_MODE:
782                 return ManagementFactory.getMemoryPoolMXBeans();
783 
784             case SERVER_MODE: {
785                 ObjectName[] names = getMemoryPoolMXBeansOnServer();
786                 ArrayList<ObjectName> list = new ArrayList<ObjectName>();
787 
788                 for (int i = 0; i < names.length; i++) {
789                     list.add(names[i]);
790                 }
791                 return list;
792             }
793 
794             case PROXY_MODE: {
795                 ObjectName[] names = getMemoryPoolMXBeansOnServer();
796                 ArrayList<MemoryPoolMXBean> list = new ArrayList<MemoryPoolMXBean>();
797 
798                 for (int i = 0; i < names.length; i++) {
799                     list.add(getProxy(names[i]));
800                 }
801                 return list;
802             }
803 
804             default:
805                 throw new TestBug("Unknown testMode " + mode);
806         }
807     } // getMemoryPoolMXBeans()
808 
809     // **********************************************************************
810     //
811     // Private methods
812     //
813     // **********************************************************************
getProxy(ObjectName objectName)814     private MemoryPoolMXBean getProxy(ObjectName objectName) {
815         try {
816             MemoryPoolMXBean proxy = (MemoryPoolMXBean) ManagementFactory.newPlatformMXBeanProxy(
817                     getMBeanServer(),
818                     objectName.toString(),
819                     MemoryPoolMXBean.class);
820             return proxy;
821         } catch (Exception e) {
822             throw new Failure(e);
823         }
824     }
825 
826     // Sets new usage threasholds in all pools that match the tested memory and
827     // support low memory detetion. A new value will be greater than used value
828     // for the pool.
updateUsageThresholds()829     private void updateUsageThresholds() {
830         switch (mode) {
831             case DIRECTLY_MODE:
832             // we can use the same code here for direct and proxy modes
833             case PROXY_MODE:
834                 List poolsMBean = ManagementFactory.getMemoryPoolMXBeans();
835 
836                 for (int i = 0; i < poolsMBean.size(); i++) {
837                     MemoryPoolMXBean pool = (MemoryPoolMXBean) poolsMBean.get(i);
838                     if (!pool.isUsageThresholdSupported()) {
839                         continue;
840                     }
841 
842                     MemoryType mt = pool.getType();
843                     if ((!mt.equals(MemoryType.HEAP)
844                             || !memory.equals(HEAP_TYPE))
845                             && (!mt.equals(MemoryType.NON_HEAP)
846                             || !memory.equals(NONHEAP_TYPE))
847                             && !memory.equals(MIXED_TYPE)) {
848                         continue;
849                     }
850 
851                     // Yes! We got the pool that
852                     // 1. supports usage threshold
853                     // 2. has type that match tested type
854                     // So, update the pool with new threshold
855                     long oldT = pool.getUsageThreshold();
856                     MemoryUsage usage = pool.getUsage();
857                     long newT = newThreshold(usage, oldT, pool.getName());
858 
859                     try {
860                         pool.setUsageThreshold(newT);
861                     } catch (IllegalArgumentException e) {
862                         /*
863                          * Max value might have changed since the call to newThreshold()
864                          * above. If it has fallen below the value of newT, which is certainly
865                          * possible, an exception like this one will be thrown from
866                          * sun.management.MemoryPoolImpl.setUsageThreshold():
867                          *
868                          * java.lang.IllegalArgumentException: Invalid threshold: 48332800 > max (47251456).
869                          *
870                          * We don't know the max value at the time of the failed call, and it
871                          * might have changed since the call once more. So there is no point
872                          * trying to detect whether the IllegalArgumentException had been
873                          * justified, we cannot know it at this point.
874                          *
875                          * The best we can do is log the fact and continue.
876                          */
877                         displayInfo("setUsageThreshold() failed with " + e + ", ignoring... ",
878                                 pool,
879                                 "current usage after the call to setUsageThreshold(): ", getUsage(pool),
880                                 "threshold: ", newT);
881                         continue;
882                     }
883                     displayInfo("Usage threshold is set", pool, "usage: ", pool.getUsage(), "threshold: ", pool.getUsageThreshold());
884                     if (pool.getUsageThreshold() != newT) {
885                         complain("Cannot reset usage threshold from " + oldT
886                                 + " to " + newT + " in pool " + pool.getName() + " "
887                                 + pool.getUsageThreshold());
888                         passed = false;
889                     }
890                 } // for i
891                 break;
892 
893             case SERVER_MODE:
894                 ObjectName[] pools = getMemoryPoolMXBeansOnServer();
895 
896                 for (int i = 0; i < pools.length; i++) {
897                     if (!isUsageThresholdSupportedOnServer(pools[i])) {
898                         continue;
899                     }
900 
901                     MemoryType mt = getType(pools[i]);
902                     if ((!mt.equals(MemoryType.HEAP)
903                             || !memory.equals(HEAP_TYPE))
904                             && (!mt.equals(MemoryType.NON_HEAP)
905                             || !memory.equals(NONHEAP_TYPE))
906                             && !memory.equals(MIXED_TYPE)) {
907                         continue;
908                     }
909 
910                     // Yes! We got the pool that
911                     // 1. supports usage threshold
912                     // 2. has type that match tested type
913                     // So, update the pool with new threshold
914                     long oldT = getUsageThreshold(pools[i]);
915                     long newT = newThreshold(getUsageOnServer(pools[i]), oldT,
916                             pools[i].toString());
917                     try {
918                         setUsageThresholdOnServer(pools[i], newT);
919                     } catch (Failure e) {
920                         /*
921                          * Max value might have changed since the call to newThreshold()
922                          * above. If it has fallen below the value of newT, which is certainly
923                          * possible, an exception like this one will be thrown from
924                          * sun.management.MemoryPoolImpl.setUsageThreshold():
925                          *
926                          * java.lang.IllegalArgumentException: Invalid threshold: 48332800 > max (47251456).
927                          *
928                          * and we'll catch Failure here as a result (it'll be thrown by
929                          * Monitor.setLongAttribute).
930                          *
931                          * We don't know the max value at the time of the failed call, and it
932                          * might have changed since the call once more. So there is no point
933                          * trying to detect whether the IllegalArgumentException had been
934                          * justified, we cannot know it at this point.
935                          *
936                          * The best we can do is log the fact and continue.
937                          */
938                         displayInfo("setUsageThresholdOnServer() failed with " + e + ", ignoring... ",
939                                 pools[i],
940                                 "current usage after the call to setUsageThresholdOnServer(): ", getUsageOnServer(pools[i]),
941                                 "threshold: ", newT);
942                         continue;
943                     }
944                     displayInfo("Usage threshold is set", null, "pool: ", pools[i], "usage:", getUsageOnServer(pools[i]));
945                     if (getUsageThreshold(pools[i]) != newT) {
946                         complain("Cannot reset usage threshold from " + oldT + " to "
947                                 + newT + " in pool " + pools[i].toString());
948                         passed = false;
949                     }
950                 } // for i
951                 break;
952 
953             default:
954                 throw new TestBug("Unknown testMode " + mode);
955         }
956     } // updateUsageThresholds()
957 
958     // Sets new collection usage threasholds in all pools that match the tested
959     // memory and support low memory detetion. A new value will be greater than
960     // used value for the pool.
updateCollectionThresholds()961     private void updateCollectionThresholds() {
962         switch (mode) {
963             case DIRECTLY_MODE:
964             // we can use the same code here for direct and proxy modes
965             case PROXY_MODE:
966                 List poolsMBean = ManagementFactory.getMemoryPoolMXBeans();
967 
968                 for (int i = 0; i < poolsMBean.size(); i++) {
969                     MemoryPoolMXBean pool = (MemoryPoolMXBean) poolsMBean.get(i);
970                     if (!pool.isCollectionUsageThresholdSupported()) {
971                         continue;
972                     }
973 
974                     MemoryType mt = pool.getType();
975                     if ((!mt.equals(MemoryType.HEAP)
976                             || !memory.equals(HEAP_TYPE))
977                             && (!mt.equals(MemoryType.NON_HEAP)
978                             || !memory.equals(NONHEAP_TYPE))
979                             && !memory.equals(MIXED_TYPE)) {
980                         continue;
981                     }
982 
983                     // Yes! We got the pool that
984                     // 1. supports collection threshold
985                     // 2. has type that match tested type
986                     // So, update the pool with new threshold
987                     long oldT = pool.getCollectionUsageThreshold();
988                     MemoryUsage usage = pool.getUsage();
989                     long newT = newThreshold(usage, oldT, pool.getName());
990 
991                     try {
992                         pool.setCollectionUsageThreshold(newT);
993                     } catch (IllegalArgumentException e) {
994 
995                         /*
996                          * Max value might have changed since the call to newThreshold()
997                          * above. If it has fallen below the value of newT, which is certainly
998                          * possible, an exception like this one will be thrown from
999                          * sun.management.MemoryPoolImpl.setCollectionUsageThreshold():
1000                          *
1001                          * java.lang.IllegalArgumentException: Invalid threshold: 48332800 > max (47251456).
1002                          *
1003                          * We don't know the max value at the time of the failed call, and it
1004                          * might have changed since the call once more. So there is no point
1005                          * trying to detect whether the IllegalArgumentException had been
1006                          * justified, we cannot know it at this point.
1007                          *
1008                          * The best we can do is log the fact and continue.
1009                          */
1010                         displayInfo("setCollectionUsageThreshold() failed with " + e + ", ignoring... ",
1011                                 pool,
1012                                 "current usage after the call to setCollectionUsageThreshold(): ", getUsage(pool),
1013                                 "threshold: ", newT);
1014                         continue;
1015                     }
1016                     displayInfo("Collection threshold is set", pool, "usage: ", getUsage(pool), "threshold: ", newT);
1017                     if (pool.getCollectionUsageThreshold() != newT) {
1018                         complain("Cannot reset collection threshold from " + oldT
1019                                 + " to " + newT + " in pool " + pool.getName() + " "
1020                                 + pool.getCollectionUsageThreshold());
1021                         passed = false;
1022                     }
1023                 } // for i
1024                 break;
1025 
1026             case SERVER_MODE:
1027                 ObjectName[] pools = getMemoryPoolMXBeansOnServer();
1028 
1029                 for (int i = 0; i < pools.length; i++) {
1030                     if (!isCollectionThresholdSupportedOnServer(pools[i])) {
1031                         continue;
1032                     }
1033 
1034                     MemoryType mt = getType(pools[i]);
1035                     if ((!mt.equals(MemoryType.HEAP)
1036                             || !memory.equals(HEAP_TYPE))
1037                             && (!mt.equals(MemoryType.NON_HEAP)
1038                             || !memory.equals(NONHEAP_TYPE))
1039                             && !memory.equals(MIXED_TYPE)) {
1040                         continue;
1041                     }
1042 
1043                     // Yes! We got the pool that
1044                     // 1. supports usage threshold
1045                     // 2. has type that match tested type
1046                     // So, update the pool with new threshold
1047                     long oldT = getCollectionThresholdOnServer(pools[i]);
1048                     long newT = newThreshold(getUsageOnServer(pools[i]), oldT,
1049                             pools[i].toString());
1050                     try {
1051                         setCollectionThresholdOnServer(pools[i], newT);
1052                     } catch (Failure e) {
1053                         /*
1054                          * Max value might have changed since the call to newThreshold()
1055                          * above. If it has fallen below the value of newT, which is certainly
1056                          * possible, an exception like this one will be thrown from
1057                          * sun.management.MemoryPoolImpl.setCollectionUsageThreshold():
1058                          *
1059                          * java.lang.IllegalArgumentException: Invalid threshold: 48332800 > max (47251456).
1060                          *
1061                          * and we'll catch Failure here as a result (it'll be thrown by
1062                          * Monitor.setLongAttribute).
1063                          *
1064                          * We don't know the max value at the time of the failed call, and it
1065                          * might have changed since the call once more. So there is no point
1066                          * trying to detect whether the IllegalArgumentException had been
1067                          * justified, we cannot know it at this point.
1068                          *
1069                          * The best we can do is log the fact and continue.
1070                          */
1071                         displayInfo("setCollectionThresholdOnServer() failed with " + e + ", ignoring... ",
1072                                 pools[i],
1073                                 "current usage after the call to setCollectionThresholdOnServer(): ", getUsageOnServer(pools[i]),
1074                                 "threshold: ", newT);
1075                         continue;
1076                     }
1077                     displayInfo("Collection threshold is set", pools[i], "usage: ", getUsageOnServer(pools[i]), "threshold: ", newT);
1078                     if (getCollectionThresholdOnServer(pools[i]) != newT) {
1079                         complain("Cannot reset collaction threshold from " + oldT
1080                                 + " to " + newT + " in pool " + pools[i].toString());
1081                         passed = false;
1082                     }
1083                 } // for i
1084                 break;
1085 
1086             default:
1087                 throw new TestBug("Unknown testMode " + mode);
1088         }
1089     } // updateCollectionThresholds()
1090 
1091     // Calculates a new value of threshold based on MemoryUsage and old value of
1092     // the threshold. New one will be not less than previous one.
newThreshold(MemoryUsage mu, long oldT, String poolName)1093     private long newThreshold(MemoryUsage mu, long oldT, String poolName) {
1094         long newT = mu.getCommitted() / 2 + mu.getUsed() / 2;
1095         long max = mu.getMax();
1096 
1097         if (newT < oldT) {
1098             newT = mu.getCommitted() / 2 + oldT / 2;
1099         }
1100         if ((max > -1) && (newT > max)) {
1101             newT = max;
1102         }
1103         displayInfo("Changing threshold", poolName, null, null, "new threshold: ", newT);
1104         return newT;
1105     }
1106 
1107     // **********************************************************************
1108     //
1109     // Methods to work with MBean server in SERVER_MODE
1110     //
1111     // **********************************************************************
1112     // Returns usage threshold value of the pool MBean that is accessed via
1113     // MBeanServer
getUsageThresholdOnServer(ObjectName pool)1114     private long getUsageThresholdOnServer(ObjectName pool) {
1115         return getLongAttribute(pool, UT);
1116     }
1117 
1118     // Returns collection threshold value of the pool MBean that is accessed via
1119     // MBeanServer
getCollectionThresholdOnServer(ObjectName pool)1120     private long getCollectionThresholdOnServer(ObjectName pool) {
1121         return getLongAttribute(pool, CT);
1122     }
1123 
1124     // Sets new usage threshold value for the pool MBean that is accessed via
1125     // MBeanServer
setUsageThresholdOnServer(ObjectName pool, long value)1126     private void setUsageThresholdOnServer(ObjectName pool, long value) {
1127         setLongAttribute(pool, UT, value);
1128     }
1129 
1130     // Sets new collection threshold value for the pool MBean that is accessed
1131     // via MBeanServer
setCollectionThresholdOnServer(ObjectName pool, long value)1132     private void setCollectionThresholdOnServer(ObjectName pool, long value) {
1133         setLongAttribute(pool, CT, value);
1134     }
1135 
1136     // Returns MemoryType of the pool MBean that is accessed via MBeanServer.
getType(ObjectName pool)1137     private MemoryType getType(ObjectName pool) {
1138         try {
1139             Object value = getMBeanServer().getAttribute(pool, POOL_TYPE);
1140             if (value instanceof MemoryType) {
1141                 return (MemoryType) value;
1142             } else if (value instanceof String) {
1143                 String name = (String) value;
1144                 return MemoryType.valueOf(name);
1145             } else {
1146                 return null;
1147             }
1148         } catch (Exception e) {
1149             e.printStackTrace(logger.getOutStream());
1150             throw new Failure(e);
1151         }
1152     }
1153 
1154     // Returns MemoryUsage of the pool MBean that is accessed via MBeanServer
getUsageOnServer(ObjectName pool)1155     private MemoryUsage getUsageOnServer(ObjectName pool) {
1156         return getMemoryUsageAttribute(pool, POOL_U);
1157     }
1158 
1159     // Returns collection usage of the pool MBean that is accessed via
1160     // MBeanServer
getCollectionUsageOnServer(ObjectName pool)1161     private MemoryUsage getCollectionUsageOnServer(ObjectName pool) {
1162         return getMemoryUsageAttribute(pool, POOL_CU);
1163     }
1164 
1165     // Returns if usage threshold is supported in the pool
isUsageThresholdSupportedOnServer(ObjectName pool)1166     private boolean isUsageThresholdSupportedOnServer(ObjectName pool) {
1167         return getBooleanAttribute(pool, UT_SUPPORT);
1168     }
1169 
1170     // Returns if collection threshold is supported in the pool
isCollectionThresholdSupportedOnServer(ObjectName pool)1171     private boolean isCollectionThresholdSupportedOnServer(ObjectName pool) {
1172         return getBooleanAttribute(pool, CT_SUPPORT);
1173     }
1174 
1175     // Returns if usage threshold is exceeded in the pool
isUsageThresholdExceededOnServer(ObjectName pool)1176     private boolean isUsageThresholdExceededOnServer(ObjectName pool) {
1177         return getBooleanAttribute(pool, UT_EXCEEDED);
1178     }
1179 
1180     // Returns if collection threshold is exceeded in the pool
isCollectionThresholdExceededOnServer(ObjectName pool)1181     private boolean isCollectionThresholdExceededOnServer(ObjectName pool) {
1182         return getBooleanAttribute(pool, CT_EXCEEDED);
1183     }
1184 
1185     // Returns the usage threshold count of the pool
getUsageThresholdCountOnServer(ObjectName pool)1186     private long getUsageThresholdCountOnServer(ObjectName pool) {
1187         return getLongAttribute(pool, UT_COUNT);
1188     }
1189 
1190     // Returns the collection threshold count of the pool.
getCollectionThresholdCountOnServer(ObjectName pool)1191     private long getCollectionThresholdCountOnServer(ObjectName pool) {
1192         return getLongAttribute(pool, CT_COUNT);
1193     }
1194     private final StringBuffer buffer = new StringBuffer(1000);
1195 
1196     /**
1197      * Display information about execution ignoring OOM.
1198      */
displayInfo(String message, Object pool, String message1, Object n1, String message2, long n2)1199     private void displayInfo(String message, Object pool, String message1, Object n1, String message2, long n2) {
1200         try {
1201             buffer.delete(0, buffer.length());
1202             buffer.append(message);
1203             if (pool != null) {
1204                 buffer.append(", pool: ");
1205                 buffer.append(pool.toString());
1206             }
1207             buffer.append(", ");
1208             buffer.append(message1);
1209             buffer.append(n1);
1210             if (message2 != null) {
1211                 buffer.append(", ");
1212                 buffer.append(message2);
1213                 buffer.append(n2);
1214             }
1215             display(buffer.toString());
1216         } catch (OutOfMemoryError e) {
1217             // Ignore.
1218         }
1219     }
1220 
1221     /**
1222      * Display information about execution ignoring OOM.
1223      */
displayInfo(String message, MemoryPoolMXBean pool, String message1, Object n1, String message2, Object n2)1224     private void displayInfo(String message, MemoryPoolMXBean pool, String message1, Object n1, String message2, Object n2) {
1225         try {
1226             buffer.delete(0, buffer.length());
1227             buffer.append(message);
1228             if (pool != null) {
1229                 buffer.append(", pool: ");
1230                 buffer.append(pool.getName());
1231             }
1232             buffer.append(", ");
1233             buffer.append(message1);
1234             buffer.append(n1);
1235             if (message2 != null) {
1236                 buffer.append(", ");
1237                 buffer.append(message2);
1238                 buffer.append(n2);
1239             }
1240             display(buffer.toString());
1241         } catch (OutOfMemoryError e) {
1242             // Ignore.
1243         }
1244     }
1245 
1246     // Returns all MemoryPoolMXBeans that are registered on the MBeanServer
getMemoryPoolMXBeansOnServer()1247     private ObjectName[] getMemoryPoolMXBeansOnServer() {
1248 
1249         // Get all registered MBeans on the server
1250         ObjectName filterName = null;
1251         try {
1252             filterName = new ObjectName(
1253                  ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",*");
1254 
1255             Set<ObjectName> filteredSet = getMBeanServer().queryNames(filterName, null);
1256             return filteredSet.toArray(new ObjectName[0]);
1257         } catch(Exception e) {
1258             return new ObjectName[0];
1259         }
1260 
1261     } // getMemoryPoolMXBeansOnServer()
1262 
1263     // **********************************************************************
1264     //
1265     // Class to implement polling mechanism of monitoring
1266     //
1267     // **********************************************************************
1268     class Polling extends Thread {
1269 
1270         final static long WAIT_TIME = 100; // Milliseconds
1271         Object object = new Object();
1272         long[] thresholdCounts;
1273         boolean goOn = true;
1274 
run()1275         public void run() {
1276             try {
1277                 if (isUsageThreshold) {
1278                     pollUsageThresholds();
1279                 } else {
1280                     pollCollectionThresholds();
1281                 }
1282             } catch (Failure e) {
1283                 complain("Unexpected " + e + " in Polling thread");
1284                 e.printStackTrace(logger.getOutStream());
1285                 passed = false;
1286             }
1287         } // run()
1288 
pollUsageThresholds()1289         private void pollUsageThresholds() {
1290             switch (mode) {
1291                 case DIRECTLY_MODE:
1292                 // we can use the same code here for direct and proxy modes
1293                 case PROXY_MODE:
1294                     List poolsMBean = ManagementFactory.getMemoryPoolMXBeans();
1295 
1296                     // Create an array to store all threshold values
1297                     thresholdCounts = new long[poolsMBean.size()];
1298                     for (int i = 0; i < thresholdCounts.length; i++) {
1299                         thresholdCounts[i] = 0;
1300                     }
1301 
1302                     while (goOn) {
1303                         synchronized (object) {
1304                             try {
1305                                 object.wait(WAIT_TIME);
1306                             } catch (InterruptedException e) {
1307 
1308                                 // Stop the thread
1309                                 return;
1310                             }
1311                         } // synchronized
1312 
1313                         for (int i = 0; i < poolsMBean.size(); i++) {
1314                             MemoryPoolMXBean pool = (MemoryPoolMXBean) poolsMBean.get(i);
1315                             MemoryType mt = pool.getType();
1316 
1317                             if (!pool.isUsageThresholdSupported()) {
1318                                 continue;
1319                             }
1320 
1321                             if ((!mt.equals(MemoryType.HEAP)
1322                                     || !memory.equals(HEAP_TYPE))
1323                                     && (!mt.equals(MemoryType.NON_HEAP)
1324                                     || !memory.equals(NONHEAP_TYPE))
1325                                     && !memory.equals(MIXED_TYPE)) {
1326                                 continue;
1327                             }
1328 
1329                             boolean exceeded;
1330 
1331                             // The exception is not documented, but it may be
1332                             // erroneously thrown
1333                             try {
1334                                 exceeded = pool.isUsageThresholdExceeded();
1335                             } catch (IllegalArgumentException e) {
1336                                 complain("Unexpected exception while retrieving "
1337                                         + "isUsageThresholdExceeded() for pool "
1338                                         + pool.getName());
1339                                 e.printStackTrace(logger.getOutStream());
1340                                 passed = false;
1341                                 continue;
1342                             }
1343 
1344                             if (!exceeded
1345                                     || pool.getUsageThresholdCount() == thresholdCounts[i]) {
1346                                 continue;
1347                             }
1348 
1349                             // Yes! We got the pool that
1350                             // 1. supports usage threshold
1351                             // 2. has type that match tested type
1352                             // 3. its threshold is exceeded
1353                             // So, update all thresholds
1354                             long c = pool.getUsageThresholdCount();
1355                             if (c <= thresholdCounts[i]) {
1356                                 complain("Usage threshold count is not greater "
1357                                         + "than previous one: " + c + " < "
1358                                         + thresholdCounts[i] + " in pool "
1359                                         + pool.getName());
1360                                 passed = false;
1361                             }
1362                             thresholdCounts[i] = c;
1363                             displayInfo("Crossing is noticed", pool, "usage: ", pool.getUsage(), "count: ", c);
1364                             updateThresholds();
1365                         } // for i
1366                     } // while
1367                     break;
1368 
1369                 case SERVER_MODE:
1370                     ObjectName[] pools = getMemoryPoolMXBeansOnServer();
1371 
1372                     // Create an array to store all threshold values
1373                     thresholdCounts = new long[pools.length];
1374                     for (int i = 0; i < thresholdCounts.length; i++) {
1375                         thresholdCounts[i] = 0;
1376                     }
1377 
1378                     while (goOn) {
1379                         synchronized (object) {
1380                             try {
1381                                 object.wait(WAIT_TIME);
1382                             } catch (InterruptedException e) {
1383 
1384                                 // Stop the thread
1385                                 return;
1386                             }
1387                         } // synchronized
1388 
1389                         for (int i = 0; i < pools.length; i++) {
1390                             MemoryType mt = getType(pools[i]);
1391 
1392                             if (!isUsageThresholdSupportedOnServer(pools[i])) {
1393                                 continue;
1394                             }
1395 
1396                             if ((!mt.equals(MemoryType.HEAP)
1397                                     || !memory.equals(HEAP_TYPE))
1398                                     && (!mt.equals(MemoryType.NON_HEAP)
1399                                     || !memory.equals(NONHEAP_TYPE))
1400                                     && !memory.equals(MIXED_TYPE)) {
1401                                 continue;
1402                             }
1403 
1404                             boolean exceeded;
1405 
1406                             // The exception is not documented, but it may be
1407                             // erroneously thrown
1408                             try {
1409                                 exceeded = isUsageThresholdExceededOnServer(pools[i]);
1410                             } catch (Failure e) {
1411                                 complain("Unexpected exception while retrieving "
1412                                         + "isUsageThresholdExceeded() for pool "
1413                                         + pools[i].toString());
1414                                 e.printStackTrace(logger.getOutStream());
1415                                 passed = false;
1416                                 continue;
1417                             }
1418 
1419                             if (!exceeded
1420                                     || getUsageThresholdCount(pools[i]) == thresholdCounts[i]) {
1421                                 continue;
1422                             }
1423 
1424                             // Yes! We got the pool that
1425                             // 1. supports usage threshold
1426                             // 2. has type that match tested type
1427                             // 3. its threshold is exceeded
1428                             // So, update all thresholds
1429                             long c = getUsageThresholdCount(pools[i]);
1430                             if (c <= thresholdCounts[i]) {
1431                                 complain("Usage threshold count is not greater "
1432                                         + "than previous one: " + c + " < "
1433                                         + thresholdCounts[i] + " in pool "
1434                                         + pools[i].toString());
1435                                 passed = false;
1436                             }
1437                             thresholdCounts[i] = c;
1438                             displayInfo("Crossing is noticed", null, "pool: ", pools[i], "usage: ", getUsageOnServer(pools[i]));
1439                             updateThresholds();
1440                         } // for i
1441                     } // while
1442                     break;
1443 
1444                 default:
1445                     throw new TestBug("Unknown testMode " + mode);
1446             } // switch
1447         } // pollUsageThresholds()
1448 
pollCollectionThresholds()1449         private void pollCollectionThresholds() {
1450             switch (mode) {
1451                 case DIRECTLY_MODE:
1452                 // we can use the same code here for direct and proxy modes
1453                 case PROXY_MODE:
1454                     List poolsMBean = ManagementFactory.getMemoryPoolMXBeans();
1455 
1456                     // Create an array to store all threshold values
1457                     thresholdCounts = new long[poolsMBean.size()];
1458                     for (int i = 0; i < thresholdCounts.length; i++) {
1459                         thresholdCounts[i] = 0;
1460                     }
1461 
1462                     while (goOn) {
1463                         synchronized (object) {
1464                             try {
1465                                 object.wait(WAIT_TIME);
1466                             } catch (InterruptedException e) {
1467 
1468                                 // Stop the thread
1469                                 return;
1470                             }
1471                         } // synchronized
1472 
1473                         for (int i = 0; i < poolsMBean.size(); i++) {
1474                             MemoryPoolMXBean pool = (MemoryPoolMXBean) poolsMBean.get(i);
1475                             MemoryType mt = pool.getType();
1476 
1477                             if (!pool.isCollectionUsageThresholdSupported()) {
1478                                 continue;
1479                             }
1480 
1481                             if ((!mt.equals(MemoryType.HEAP)
1482                                     || !memory.equals(HEAP_TYPE))
1483                                     && (!mt.equals(MemoryType.NON_HEAP)
1484                                     || !memory.equals(NONHEAP_TYPE))
1485                                     && !memory.equals(MIXED_TYPE)) {
1486                                 continue;
1487                             }
1488 
1489                             boolean exceeded;
1490 
1491                             // The exception is not documented, but it may be
1492                             // erroneously thrown
1493                             try {
1494                                 exceeded = pool.isCollectionUsageThresholdExceeded();
1495                             } catch (IllegalArgumentException e) {
1496                                 complain("Unexpected exception while retrieving "
1497                                         + "isCollectionUsageThresholdExceeded()"
1498                                         + " for pool " + pool.getName());
1499                                 e.printStackTrace(logger.getOutStream());
1500                                 passed = false;
1501                                 continue;
1502                             }
1503 
1504                             if (!exceeded
1505                                     || pool.getCollectionUsageThresholdCount()
1506                                     == thresholdCounts[i]) {
1507                                 continue;
1508                             }
1509 
1510                             // Yes! We got thet pool that
1511                             // 1. supports collection usage threshold
1512                             // 2. has type that match tested type
1513                             // 3. its threshold is exceeded
1514                             // So, update all thresholds
1515                             long c = pool.getCollectionUsageThresholdCount();
1516                             if (c <= thresholdCounts[i]) {
1517                                 complain("Collection usage threshold count is "
1518                                         + "not greater than previous one: " + c
1519                                         + " < " + thresholdCounts[i] + " in pool "
1520                                         + pool.getName());
1521                                 passed = false;
1522                             }
1523                             thresholdCounts[i] = c;
1524                             displayInfo("Crossing is noticed", pool, "usage: ", pool.getUsage(), "count: ", c);
1525                             updateThresholds();
1526                         } // for i
1527                     } // while
1528                     break;
1529 
1530                 case SERVER_MODE:
1531                     ObjectName[] pools = getMemoryPoolMXBeansOnServer();
1532 
1533                     // Create an array to store all threshold values
1534                     thresholdCounts = new long[pools.length];
1535                     for (int i = 0; i < thresholdCounts.length; i++) {
1536                         thresholdCounts[i] = 0;
1537                     }
1538 
1539                     while (goOn) {
1540                         synchronized (object) {
1541                             try {
1542                                 object.wait(WAIT_TIME);
1543                             } catch (InterruptedException e) {
1544 
1545                                 // Stop the thread
1546                                 return;
1547                             }
1548                         } // synchronized
1549 
1550                         for (int i = 0; i < pools.length; i++) {
1551                             MemoryType mt = getType(pools[i]);
1552 
1553                             if (!isCollectionThresholdSupportedOnServer(pools[i])) {
1554                                 continue;
1555                             }
1556 
1557                             if ((!mt.equals(MemoryType.HEAP)
1558                                     || !memory.equals(HEAP_TYPE))
1559                                     && (!mt.equals(MemoryType.NON_HEAP)
1560                                     || !memory.equals(NONHEAP_TYPE))
1561                                     && !memory.equals(MIXED_TYPE)) {
1562                                 continue;
1563                             }
1564 
1565                             boolean exceeded;
1566 
1567                             // The exception is not documented, but it may be
1568                             // erroneously thrown
1569                             try {
1570                                 exceeded = isCollectionThresholdExceededOnServer(pools[i]);
1571                             } catch (Failure e) {
1572                                 complain("Unexpected exception while retrieving "
1573                                         + "isCollectionUsageThresholdExceeded() "
1574                                         + "for pool " + pools[i].toString());
1575                                 e.printStackTrace(logger.getOutStream());
1576                                 passed = false;
1577                                 continue;
1578                             }
1579 
1580                             if (!exceeded
1581                                     || getCollectionThresholdCountOnServer(pools[i])
1582                                     == thresholdCounts[i]) {
1583                                 continue;
1584                             }
1585 
1586                             // Yes! We got thet pool that
1587                             // 1. supports collection usage threshold
1588                             // 2. has type that match tested type
1589                             // 3. its threshold is exceeded
1590                             // So, update all thresholds
1591                             long c = getCollectionThresholdCountOnServer(pools[i]);
1592                             if (c <= thresholdCounts[i]) {
1593                                 complain("Collection usage threshold count is "
1594                                         + "not greater than previous one: " + c
1595                                         + " < " + thresholdCounts[i] + " in pool "
1596                                         + pools[i].toString());
1597                                 passed = false;
1598                             }
1599                             thresholdCounts[i] = c;
1600                             displayInfo("Crossing is noticed", pools[i], "usage: ", getUsageOnServer(pools[i]), "count: ", c);
1601                             updateThresholds();
1602                         } // for i
1603                     } // while
1604                     break;
1605 
1606                 default:
1607                     throw new TestBug("Unknown testMode " + mode);
1608             } // switch
1609         } // pollCollectionThresholds()
1610     } // class Polling
1611 } // MemoryMonitor
1612