alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ListenerScaleTest.java)

This example Java source code file (ListenerScaleTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

exception, extra_mbeans, jmxconnector, jmxconnectorserver, jmxserviceurl, management, notificationbroadcastersupport, notificationlistener, notifs_to_time, objectname, runtimeexception, semaphore, sender, sendermbean, threading, threads, warmup_with_one_mbean

The ListenerScaleTest.java Java example source code

/*
 * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 6338874
 * @summary Check that notification dispatch is not linear in number of MBeans.
 * @author Eamonn McManus
 */

/*
 * The notification dispatch logic in the connector server used to be
 * linear in the number of listeners there were on any MBean.  For
 * example, if there were 1000 MBeans, each with one listener, then
 * every time a notification was sent it would be compared against
 * every one of the 1000 MBeans, even though its source ObjectName was
 * known and could not possibly match the name of 999 of the MBeans.
 * This test checks that we no longer have linear behaviour.  We do
 * this by registering just one MBean and measuring the time it takes
 * to send and receive a certain number of notifications from that
 * MBean.  Then we register many other MBeans, each with a listener,
 * and we make the same measurement as before.  The presence of the
 * extra MBeans with their listeners should not impact the dispatch
 * time significantly.  If it does, the test fails.
 *
 * As usual with timing-sensitive tests, we could potentially get
 * sporadic failures.  We fail if the ratio of the time with many
 * MBeans to the time with just one MBean is more than 500.  With the
 * fix in place, it is usually less than 1, presumably because some
 * code was being interpreted during the first measurement but had
 * been compiled by the second.
 */

import java.util.concurrent.Semaphore;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class ListenerScaleTest {
    private static final int WARMUP_WITH_ONE_MBEAN = 1000;
    private static final int NOTIFS_TO_TIME = 100;
    private static final int EXTRA_MBEANS = 20000;

    private static final ObjectName testObjectName;
    static {
        try {
            testObjectName = new ObjectName("test:type=Sender,number=-1");
        } catch (MalformedObjectNameException e) {
            throw new RuntimeException(e);
        }
    }

    private static volatile int nnotifs;
    private static volatile long startTime;
    private static volatile long elapsed;
    private static final Semaphore sema = new Semaphore(0);

    private static final NotificationListener timingListener =
        new NotificationListener() {
            public void handleNotification(Notification n, Object h) {
                if (++nnotifs == NOTIFS_TO_TIME) {
                    elapsed = System.nanoTime() - startTime;
                    sema.release();
                }
            }
        };

    private static final long timeNotif(MBeanServer mbs) {
        try {
            startTime = System.nanoTime();
            nnotifs = 0;
            mbs.invoke(testObjectName, "send", null, null);
            sema.acquire();
            return elapsed;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static interface SenderMBean {
        public void send();
    }

    public static class Sender extends NotificationBroadcasterSupport
            implements SenderMBean {
        public void send() {
            for (int i = 0; i < NOTIFS_TO_TIME; i++)
                sendNotification(new Notification("type", this, 1L));
        }
    }

    private static final NotificationListener nullListener =
        new NotificationListener() {
            public void handleNotification(Notification n, Object h) {}
        };

    public static void main(String[] args) throws Exception {
        MBeanServer mbs = MBeanServerFactory.newMBeanServer();
        Sender sender = new Sender();
        mbs.registerMBean(sender, testObjectName);
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
        JMXConnectorServer cs =
            JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
        cs.start();
        JMXServiceURL addr = cs.getAddress();
        JMXConnector cc = JMXConnectorFactory.connect(addr);
        try {
            test(mbs, cs, cc);
        } finally {
            cc.close();
            cs.stop();
        }
    }

    private static void test(MBeanServer mbs, JMXConnectorServer cs,
                             JMXConnector cc) throws Exception {
        MBeanServerConnection mbsc = cc.getMBeanServerConnection();
        mbsc.addNotificationListener(testObjectName, timingListener, null, null);
        long singleMBeanTime = 0;
        for (int i = 0; i < WARMUP_WITH_ONE_MBEAN; i++)
            singleMBeanTime = timeNotif(mbs);
        if (singleMBeanTime == 0)
            singleMBeanTime = 1;
        System.out.println("Time with a single MBean: " + singleMBeanTime + "ns");
        System.out.println("Now registering " + EXTRA_MBEANS + " MBeans");
        for (int i = 0; i < EXTRA_MBEANS; i++) {
            ObjectName on = new ObjectName("test:type=Sender,number=" + i);
            mbs.registerMBean(new Sender(), on);
            if (i % 1000 == 999) {
                System.out.print("..." + (i+1));
                System.out.flush();
            }
        }
        System.out.println();
        System.out.println("Now registering " + EXTRA_MBEANS + " listeners");
        for (int i = 0; i < EXTRA_MBEANS; i++) {
            ObjectName on = new ObjectName("test:type=Sender,number=" + i);
            mbsc.addNotificationListener(on, nullListener, null, null);
            if (i % 1000 == 999) {
                System.out.print("..." + (i+1));
                System.out.flush();
            }
        }
        System.out.println();
        System.out.println("Timing a notification send now");
        long manyMBeansTime = timeNotif(mbs);
        System.out.println("Time with many MBeans: " + manyMBeansTime + "ns");
        double ratio = (double) manyMBeansTime / singleMBeanTime;
        if (ratio > 500.0)
            throw new Exception("Failed: ratio=" + ratio);
        System.out.println("Test passed: ratio=" + ratio);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ListenerScaleTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.