Author: ieb
Date: Wed Feb 27 10:38:06 2013
New Revision: 1450722

URL: http://svn.apache.org/r1450722
Log:
Better measurement of thread blockings. Running more threads than cpus was 
misleading.
Current implementation causes threads to block about 0.5% of the time when 
running flat out.

Modified:
    
sling/whiteboard/ieb/log/src/test/java/org/apache/sling/commons/log/internal/monitor/CounterTest.java

Modified: 
sling/whiteboard/ieb/log/src/test/java/org/apache/sling/commons/log/internal/monitor/CounterTest.java
URL: 
http://svn.apache.org/viewvc/sling/whiteboard/ieb/log/src/test/java/org/apache/sling/commons/log/internal/monitor/CounterTest.java?rev=1450722&r1=1450721&r2=1450722&view=diff
==============================================================================
--- 
sling/whiteboard/ieb/log/src/test/java/org/apache/sling/commons/log/internal/monitor/CounterTest.java
 (original)
+++ 
sling/whiteboard/ieb/log/src/test/java/org/apache/sling/commons/log/internal/monitor/CounterTest.java
 Wed Feb 27 10:38:06 2013
@@ -17,18 +17,41 @@
  */
 package org.apache.sling.commons.log.internal.monitor;
 
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.text.MessageFormat;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.openmbean.CompositeData;
+
 import junit.framework.Assert;
 
+import 
org.apache.sling.commons.log.internal.Activator.DummyLogManagerConfiguration;
 import org.junit.Test;
+import org.osgi.service.cm.ManagedServiceFactory;
 import org.slf4j.Marker;
 import org.slf4j.MarkerFactory;
 
 public class CounterTest {
+    private long lastBlockedTime;
+    private long lastBlockedCount;
+    private long lastCheck;
+
     /**
-     * Give a very rough idea of performance single threaded.
-     * NB: This is a totally unscientific benchmark.
+     * Give a very rough idea of performance single threaded. NB: This is a
+     * totally unscientific benchmark.
      */
     @Test
     public void testCounter() {
@@ -36,80 +59,137 @@ public class CounterTest {
         Counter counter = Counter.getInstance();
         int loops = 100000;
         int counters = 100;
-        long ncounts = loops*counters;
-        // attemt to warm up hotspot by causing the code to be executed > 10k 
times.
-        for ( int j = 0; j < loops+1; j++ ) {
-            for ( int i = 0; i < counters+1; i++) {
-                counter.increment(m, "cou\"nter"+i);
+        long ncounts = loops * counters;
+        // attemt to warm up hotspot by causing the code to be executed > 10k
+        // times.
+        for (int j = 0; j < loops + 1; j++) {
+            for (int i = 0; i < counters + 1; i++) {
+                counter.increment(m, "cou\"nter" + i);
             }
         }
 
         long l = System.nanoTime();
-        for ( int j = 0; j < loops; j++ ) {
-            for ( int i = 0; i < counters; i++) {
-                counter.increment(m, "cou\"nter"+i);
+        for (int j = 0; j < loops; j++) {
+            for (int i = 0; i < counters; i++) {
+                counter.increment(m, "cou\"nter" + i);
             }
         }
         l = System.nanoTime() - l;
-        System.err.println("Time Taken for 1 count operation is 
"+(l/ncounts)+" nanoseconds");
+        System.err.println("Time Taken for 1 count operation is "
+                + (l / ncounts) + " nanoseconds");
         String json = counter.toJson();
         Assert.assertNotNull(json);
     }
-    
+
     @Test
-    public void testCounterMultiThreaded() throws InterruptedException {
-        for (int i = 1; i < 32; i++ ) {
-            doMulti(i, 10000, 100, Runtime.getRuntime().availableProcessors());
-        }
+    public void testCounterMultiThreaded() throws InterruptedException,
+            MalformedObjectNameException, InstanceNotFoundException,
+            NullPointerException, ReflectionException, MBeanException,
+            InvalidAttributeValueException, AttributeNotFoundException {
+        doMulti(Runtime.getRuntime().availableProcessors(), 10000000, 100, 
Runtime.getRuntime().availableProcessors());
     }
-    
-    public long doMulti(int threads, final int loops, final int counters, int 
cores) throws InterruptedException {
+
+    public void doMulti(int threads, final int loops, final int counters,
+            int cores) throws InterruptedException,
+            MalformedObjectNameException, InstanceNotFoundException,
+            NullPointerException, ReflectionException, MBeanException,
+            InvalidAttributeValueException, AttributeNotFoundException {
         final Marker m = MarkerFactory.getMarker("count");
         final Counter counter = Counter.getInstance();
-        // attemt to warm up hotspot by causing the code to be executed > 10k 
times.
-        for ( int j = 0; j < loops+1; j++ ) {
-            for ( int i = 0; i < counters+1; i++) {
-                counter.increment(m, "cou\"nter"+i);
+        // attemt to warm up hotspot by causing the code to be executed > 10k
+        // times.
+        for (int j = 0; j < 10000 + 1; j++) {
+            for (int i = 0; i < counters + 1; i++) {
+                counter.increment(m, "cou\"nter" + i);
             }
         }
-        final int ncounts = loops*counters;
-        final int tcounts = ncounts*threads;
+        final int ncounts = loops * counters;
+        final int tcounts = ncounts * threads;
         Thread[] t = new Thread[threads];
         final long[] l = new long[threads];
-        for ( int i = 0; i < threads; i++ ) {
+        final AtomicInteger running = new AtomicInteger();
+        for (int i = 0; i < threads; i++) {
             final int threadn = i;
             t[i] = new Thread() {
                 public void run() {
+                    running.incrementAndGet();
                     l[threadn] = System.nanoTime();
-                    for ( int j = 0; j < loops; j++ ) {
-                        for ( int i = 0; i < counters; i++) {
-                            counter.increment(m, "cou\"nter"+i);
+                    for (int j = 0; j < loops; j++) {
+                        for (int i = 0; i < counters; i++) {
+                            counter.increment(m, "cou\"nter" + i);
                         }
                     }
                     l[threadn] = System.nanoTime() - l[threadn];
+                    running.decrementAndGet();
                 };
             };
         }
-       for ( int i = 0; i < t.length; i++) {
-           t[i].start();
-       }
-       for ( int i = 0; i < t.length; i++) {
-           t[i].join();
-       }
-       // work out the total time over all threads.
-       long overall = 0L;
-       for ( int i = 0; i < t.length; i++) {       
-           overall += l[i];
-       }
-       // work out how long it should have taken if we had as many cores as 
threads.
-       // this number should remain constant if no threads block other threads 
and both cores on the box are
-       // fully utilized.
-       long adjusted = overall/tcounts;
-       if ( threads > cores ) {
-           adjusted = (cores*100*(adjusted))/(100*threads);
-       }
-       System.err.println("Time Taken for 1 count operation over "+t.length+" 
threads is "+(overall/tcounts)+" ns "+adjusted+" ns adjusted for CPUs");
-       return adjusted;
         
+        MBeanServer mbeanServer = resetThreadMontoring(); 
+        dumpThreadWaits(mbeanServer);
+        for (int i = 0; i < t.length; i++) {
+            t[i].start();
+        }
+
+        while (running.get() > 0) {
+            dumpThreadWaits(mbeanServer);
+            Thread.sleep(10000);
+        }
+
+        for (int i = 0; i < t.length; i++) {
+            t[i].join();
+        }
+        // work out the total time over all threads.
+        long overall = 0L;
+        for (int i = 0; i < t.length; i++) {
+            overall += l[i];
+        }
+        // work out how long it should have taken if we had as many cores as
+        // threads.
+        // this number should remain constant if no threads block other threads
+        // and both cores on the box are
+        // fully utilized.
+        System.err.println("Time Taken for 1 count operation over " + t.length
+                + " threads is " + (overall / tcounts) + " ns ");
+
+    }
+
+    private MBeanServer resetThreadMontoring() throws 
InstanceNotFoundException, InvalidAttributeValueException, 
AttributeNotFoundException, MalformedObjectNameException, ReflectionException, 
MBeanException, NullPointerException {
+        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
+        mbeanServer.setAttribute(new ObjectName("java.lang:type=Threading"),
+                new Attribute("ThreadContentionMonitoringEnabled", false));
+        mbeanServer.setAttribute(new ObjectName("java.lang:type=Threading"),
+                new Attribute("ThreadContentionMonitoringEnabled", true));
+        lastBlockedTime = 0;
+        lastBlockedCount = 0;
+        lastCheck = System.currentTimeMillis();
+        return mbeanServer;
+    }
+
+    private void dumpThreadWaits(MBeanServer mbeanServer)
+            throws MalformedObjectNameException, NullPointerException,
+            InstanceNotFoundException, ReflectionException, MBeanException {
+        CompositeData[] threads = (CompositeData[]) mbeanServer.invoke(
+                new ObjectName("java.lang:type=Threading"), "dumpAllThreads",
+                new Object[] { new Boolean(true), new Boolean(true) },
+                new String[] { "boolean", "boolean" });
+        long blockedTime = 0L;
+        long blockedCount = 0L;
+        for (CompositeData cd : threads) {
+            ThreadInfo ti = ThreadInfo.from(cd);
+            if (Thread.currentThread().getId() != ti.getThreadId()) {
+                blockedTime += ti.getBlockedTime();
+                blockedCount += ti.getBlockedCount();
+            }
+        }
+        long deltaTime = blockedTime - lastBlockedTime;
+        long deltaCount = blockedCount - lastBlockedCount;
+        long deltaRealTime = System.currentTimeMillis() - lastCheck;
+        
+        lastBlockedTime = blockedTime;
+        lastBlockedCount = blockedCount;
+        lastCheck = System.currentTimeMillis();
+        System.err.println(MessageFormat.format("Total Blocked time over all 
threads {0,number} ms  in {1,number} ms threads blocked for  {2,number,#.###}% 
of the time or on average {3,number,#.##} ms 
",deltaTime,deltaRealTime,((double)deltaTime*100)/((double)deltaRealTime),((deltaCount==0)?0:((double)deltaTime)/((double)deltaCount))));
+
     }
 }


Reply via email to