Question

I am trying to measure the performance of client side code. Meaning how much time end to end client side code takes and few other classes inside the client code. So I did my benchmarking around that.

Below is the simple program I am using currently. But there is a problem with that.

public class PerformanceTest {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(5);

        try {
            for (int i = 0; i < 10 * 5; i++) {
                executor.submit(new ThreadTask(i));
            }

            executor.shutdown();
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        } catch (InterruptedException e) {

        }
    }
}

Below is the class that implements Runnable interface

class ThreadTask implements Runnable {
    private int id;
    public static ConcurrentHashMap<Long, AtomicLong> millisecondsMap = new ConcurrentHashMap<Long, AtomicLong>();


    public ThreadTask(int id) {
        this.id = id;
    }

    @Override
    public void run() {


        long start = System.nanoTime();

        attributes = beClient.getAttributes(columnsList);

        long end = System.nanoTime() - start;

        final AtomicLong before = millisecondsMap.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            before.incrementAndGet(); //this is a blocking call in IBM JVM
        }
    }
}

Problem Statement:-

I am running IBM JVM in my machine. As I am working in a company where they use IBM JVM instead of SUN JVM so I cannot change the JVM part.

So in IBM JVM incrementAndGet() method looks like, it was very strange to me first of all

/**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final synchronized long incrementAndGet() {                          //IBM-perf_AtomicLong
   ++value;                                                                 //IBM-perf_AtomicLong
   return value;                                                            //IBM-perf_AtomicLong
}

So it's a blocking call as it is synchronized, meaning each thread will be waiting for each other. And now I am looking for Lock free solution for this to measure the performance of each method.

I know, there will be tiny latency here. But whatever methods performance I want to measure inside the client side code, I usually put the below line just above that method

long start = System.nanoTime();

And these two lines after the same method but with different ConcurrentHashMap

long end = System.nanoTime() - start;

final AtomicLong before = millisecondsMap.putIfAbsent(end / 1000000L, new AtomicLong(1L));
        if (before != null) {
            before.incrementAndGet();// this is a blocking call in IBM JVM
        }

So if I have same above code around 5-8 different methods in a different classes on the client side code. Then end to end performance measurement will be wrong as each thread will be waiting there to increment the value. So that is the reason I am looking for Lock free solution for this.

Is there any simple way to do this? Can anyone provide any example for this?

Thanks in advance.

Updated Code:-

public static ConcurrentHashMap<Long, Long> millisecondsMap = new ConcurrentHashMap<Long, Long>();

@Override
public void run() {


    long start = System.nanoTime();

    beAttributes = client.getAttributes(columnsList);

    long end = System.nanoTime() - start;

    long key = end / 1000000L;
    boolean done = false;

    while(!done) {
        long oldValue = millisecondsMap.get(key);
        done = millisecondsMap.replace(key, oldValue, oldValue + 1);
    }

}

Does this code is thread safe code as well? As it will be accessed by multiple threads as well.

Was it helpful?

Solution

Rather than use an AtomicLong, use the ConcurrentHashMap's replace(key, old value, new value) method to increment the value.

ConcurrentHashMap<Long, Long> millisecondsMap = new ConcurrentHashMap<>();
long key = end / 1000000L;
boolean done = false;
while(!done) {
    Long oldValue = millisecondsMap.putIfAbsent(key, 1L);
    if(oldValue != null) {
        done = millisecondsMap.replace(key, oldValue, oldValue + 1);
    } else {
        done = true;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top