karouani / javasimon

Automatically exported from code.google.com/p/javasimon
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

CacheMonitorSource HashMap infinite loop #115

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?

import java.util.concurrent.atomic.AtomicInteger;

import org.javasimon.SimonManager;
import org.javasimon.Split;
import org.javasimon.Stopwatch;
import org.javasimon.source.AbstractStopwatchSource;
import org.javasimon.source.CacheMonitorSource;
import org.javasimon.source.StopwatchTemplate;

public class SimonPerfTest extends Thread {

    public static class BadHashString {
        public BadHashString() {
        }

        @Override
        public int hashCode() {
            return 0;
        }
    }

    private static BadHashString[] acKeys;

    private static AtomicInteger m_nRunningThreads = new AtomicInteger( 0 );

    public static void main(String[] args) {
        acKeys = new BadHashString[1000];
        for (int i = 0; i < acKeys.length; i++) {
            acKeys[i] = new BadHashString();
        }

        AbstractStopwatchSource<BadHashString> cSource = new AbstractStopwatchSource<BadHashString>(SimonManager.manager()) {
            @Override
            protected String getMonitorName(BadHashString a_cLocation) {
                return a_cLocation.toString();
            }
        };
        CacheMonitorSource<BadHashString, Stopwatch, BadHashString> cCache = new CacheMonitorSource<BadHashString, Stopwatch, BadHashString>(cSource) {
            @Override
            protected BadHashString getLocationKey(BadHashString a_cLocation) {
                return a_cLocation;
            }
        };
        StopwatchTemplate<BadHashString> cST = new StopwatchTemplate<BadHashString>( cCache );

        for( int i = 0 ; i < 10 ; i++ ) {
            new SimonPerfTest( cST ).start();
        }       
    }

    private int m_nIndex = 0;
    private StopwatchTemplate<BadHashString> m_cTemplate;

    public SimonPerfTest(StopwatchTemplate<BadHashString> a_cST) {
        m_cTemplate = a_cST;
    }

    @Override
    public void run() {
        System.out.println("Start " + m_nRunningThreads.incrementAndGet());
        while(m_nIndex < acKeys.length) {
            BadHashString cNext = acKeys[m_nIndex++];
            Split cSplit = m_cTemplate.start( cNext );

            m_cTemplate.stop(cSplit);
        }
        System.out.println("End (Remaining: " + m_nRunningThreads.decrementAndGet() + ")");
    }

}

What is the expected output? What do you see instead?
Start 1
Start 2
Start 3
Start 4
Start 5
Start 6
Start 7
Start 8
Start 9
Start 10
End (Remaining: 9)
End (Remaining: 8)
End (Remaining: 7)
End (Remaining: 6)
End (Remaining: 5)
End (Remaining: 4)
End (Remaining: 3)
End (Remaining: 2)
End (Remaining: 1)
End (Remaining: 0)

I see:
Start 1
Start 2
Start 3
Start 4
Start 5
Start 6
Start 7
Start 8
Start 9
Start 10

... in 50% of the times (no end)

What version of the product are you using? On what operating system?
Java simon 3.3

Please provide any additional information below.
When running the provided test it doesn't fail everytime, but about 50% of the 
times it does on my machine.

This is the problem: HashMap (Have a look a the thread dump via java visual vm) 
CacheMonitorSource.monitorInformations HashMap is not threadsafe and causes 
infinite loop on high performance.
http://mailinator.blogspot.dk/2009/06/beautiful-race-condition.html

This is the thread dump from one of the threads in the test:

"Thread-0" - Thread t@8
   java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.getEntry(HashMap.java:469)
    at java.util.HashMap.get(HashMap.java:421)
    at org.javasimon.source.CacheMonitorSource.getMonitorInformation(CacheMonitorSource.java:90)
    at org.javasimon.source.CacheMonitorSource.isMonitored(CacheMonitorSource.java:116)
    at org.javasimon.source.StopwatchTemplate.start(StopwatchTemplate.java:33)
    at com.toh.serverframework.util.SimonPerfTest.run(SimonPerfTest.java:60)

   Locked ownable synchronizers:
    - None

Original issue reported on code.google.com by alland...@gmail.com on 10 Jan 2014 at 1:13

GoogleCodeExporter commented 8 years ago

Original comment by virgo47 on 10 Jan 2014 at 1:30

GoogleCodeExporter commented 8 years ago
Thank you very much for your report and provided test case. I simplified it for 
3.4 where I indeed reproduced the problem as well. I changed the hash map to 
ConcurrentHashMap and I was not able to reproduce it anymore.

Changed test case for Java Simon 3.4.0:
package org.javasimon;

import java.util.concurrent.atomic.AtomicInteger;

import org.javasimon.source.AbstractStopwatchSource;
import org.javasimon.source.CachedMonitorSource;

public class SimonPerfTest extends Thread {

    private CachedMonitorSource<BadHashString, Stopwatch, BadHashString> cCache;

    public static class BadHashString {
        public BadHashString() {
        }

        @Override
        public int hashCode() {
            return 0;
        }
    }

    private static BadHashString[] acKeys;

    private static AtomicInteger m_nRunningThreads = new AtomicInteger(0);

    public static void main(String[] args) {
        acKeys = new BadHashString[1000];
        for (int i = 0; i < acKeys.length; i++) {
            acKeys[i] = new BadHashString();
        }

        AbstractStopwatchSource<BadHashString> cSource = new AbstractStopwatchSource<BadHashString>(SimonManager.manager()) {
            @Override
            protected String getMonitorName(BadHashString a_cLocation) {
                return a_cLocation.toString();
            }
        };
        CachedMonitorSource<BadHashString, Stopwatch, BadHashString> cCache = new CachedMonitorSource<BadHashString, Stopwatch, BadHashString>(cSource) {
            @Override
            protected BadHashString getLocationKey(BadHashString a_cLocation) {
                return a_cLocation;
            }
        };

        for (int i = 0; i < 10; i++) {
            new SimonPerfTest(cCache).start();
        }
    }

    private int m_nIndex = 0;

    public SimonPerfTest(CachedMonitorSource<BadHashString, Stopwatch, BadHashString> cCache) {
        this.cCache = cCache;
    }

    @Override
    public void run() {
        System.out.println("Start " + m_nRunningThreads.incrementAndGet());
        while (m_nIndex < acKeys.length) {
            BadHashString cNext = acKeys[m_nIndex++];

            Split cSplit = cCache.getMonitor(cNext).start();
            cSplit.stop();
        }
        System.out.println("End (Remaining: " + m_nRunningThreads.decrementAndGet() + ")");
    }
}

Original comment by virgo47 on 10 Jan 2014 at 2:43

GoogleCodeExporter commented 8 years ago
Thanks. Looking forward to a new release. 

Original comment by alland...@gmail.com on 11 Jan 2014 at 6:53