blob: d0c519e45cadc9ec2840d7d145b48bb1bbdd2ad4 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2006 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 6338874
27 * @summary Check that notification dispatch is not linear in number of MBeans.
28 * @author Eamonn McManus
29 */
30
31/*
32 * The notification dispatch logic in the connector server used to be
33 * linear in the number of listeners there were on any MBean. For
34 * example, if there were 1000 MBeans, each with one listener, then
35 * every time a notification was sent it would be compared against
36 * every one of the 1000 MBeans, even though its source ObjectName was
37 * known and could not possibly match the name of 999 of the MBeans.
38 * This test checks that we no longer have linear behaviour. We do
39 * this by registering just one MBean and measuring the time it takes
40 * to send and receive a certain number of notifications from that
41 * MBean. Then we register many other MBeans, each with a listener,
42 * and we make the same measurement as before. The presence of the
43 * extra MBeans with their listeners should not impact the dispatch
44 * time significantly. If it does, the test fails.
45 *
46 * As usual with timing-sensitive tests, we could potentially get
47 * sporadic failures. We fail if the ratio of the time with many
48 * MBeans to the time with just one MBean is more than 100. With the
49 * fix in place, it is usually less than 1, presumably because some
50 * code was being interpreted during the first measurement but had
51 * been compiled by the second.
52 */
53
54import java.lang.management.ManagementFactory;
55import javax.management.*;
56import javax.management.remote.*;
57import java.util.concurrent.*;
58
59public class ListenerScaleTest {
60 private static final int WARMUP_WITH_ONE_MBEAN = 1000;
61 private static final int NOTIFS_TO_TIME = 100;
62 private static final int EXTRA_MBEANS = 20000;
63
64 private static final MBeanServer mbs =
65 ManagementFactory.getPlatformMBeanServer();
66 private static final ObjectName testObjectName;
67 static {
68 try {
69 testObjectName = new ObjectName("test:type=Sender,number=-1");
70 } catch (MalformedObjectNameException e) {
71 throw new RuntimeException(e);
72 }
73 }
74
75 private static volatile int nnotifs;
76 private static volatile long startTime;
77 private static volatile long elapsed;
78 private static final Semaphore sema = new Semaphore(0);
79
80 private static final NotificationListener timingListener =
81 new NotificationListener() {
82 public void handleNotification(Notification n, Object h) {
83 if (++nnotifs == NOTIFS_TO_TIME) {
84 elapsed = System.nanoTime() - startTime;
85 sema.release();
86 }
87 }
88 };
89
90 private static final long timeNotif() {
91 try {
92 startTime = System.nanoTime();
93 nnotifs = 0;
94 mbs.invoke(testObjectName, "send", null, null);
95 sema.acquire();
96 return elapsed;
97 } catch (Exception e) {
98 throw new RuntimeException(e);
99 }
100 }
101
102 public static interface SenderMBean {
103 public void send();
104 }
105
106 public static class Sender extends NotificationBroadcasterSupport
107 implements SenderMBean {
108 public void send() {
109 for (int i = 0; i < NOTIFS_TO_TIME; i++)
110 sendNotification(new Notification("type", this, 1L));
111 }
112 }
113
114 private static final NotificationListener nullListener =
115 new NotificationListener() {
116 public void handleNotification(Notification n, Object h) {}
117 };
118
119 public static void main(String[] args) throws Exception {
120 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
121 Sender sender = new Sender();
122 mbs.registerMBean(sender, testObjectName);
123 JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
124 JMXConnectorServer cs =
125 JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
126 cs.start();
127 JMXServiceURL addr = cs.getAddress();
128 JMXConnector cc = JMXConnectorFactory.connect(addr);
129 try {
130 test(mbs, cs, cc);
131 } finally {
132 cc.close();
133 cs.stop();
134 }
135 }
136
137 private static void test(MBeanServer mbs, JMXConnectorServer cs,
138 JMXConnector cc) throws Exception {
139 MBeanServerConnection mbsc = cc.getMBeanServerConnection();
140 mbsc.addNotificationListener(testObjectName, timingListener, null, null);
141 long singleMBeanTime = 0;
142 for (int i = 0; i < WARMUP_WITH_ONE_MBEAN; i++)
143 singleMBeanTime = timeNotif();
144 if (singleMBeanTime == 0)
145 singleMBeanTime = 1;
146 System.out.println("Time with a single MBean: " + singleMBeanTime + "ns");
147 System.out.println("Now registering " + EXTRA_MBEANS + " MBeans");
148 for (int i = 0; i < EXTRA_MBEANS; i++) {
149 ObjectName on = new ObjectName("test:type=Sender,number=" + i);
150 mbs.registerMBean(new Sender(), on);
151 if (i % 1000 == 999) {
152 System.out.print("..." + (i+1));
153 System.out.flush();
154 }
155 }
156 System.out.println();
157 System.out.println("Now registering " + EXTRA_MBEANS + " listeners");
158 for (int i = 0; i < EXTRA_MBEANS; i++) {
159 ObjectName on = new ObjectName("test:type=Sender,number=" + i);
160 mbsc.addNotificationListener(on, nullListener, null, null);
161 if (i % 1000 == 999) {
162 System.out.print("..." + (i+1));
163 System.out.flush();
164 }
165 }
166 System.out.println();
167 System.out.println("Timing a notification send now");
168 long manyMBeansTime = timeNotif();
169 System.out.println("Time with many MBeans: " + manyMBeansTime + "ns");
170 double ratio = (double) manyMBeansTime / singleMBeanTime;
171 if (ratio > 100.0)
172 throw new Exception("Failed: ratio=" + ratio);
173 System.out.println("Test passed: ratio=" + ratio);
174 }
175}