package objectcachetest;

import com.sun.grizzly.comet.CometContext;
import com.sun.grizzly.comet.CometTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *  -server -XX:+UseParallelOldGC -XX:+UseParallelGC -XX:+DisableExplicitGC  -Xms256m -Xmx256m -XX:MaxPermSize=64m -XX:NewRatio=2 -XX:LargePageSizeInBytes=2m -XX:+AggressiveOpts
 *
 * @author Gustav Trede 2008
 */
public class Main {

    protected ExecutorService threadPool;

    private final ConcurrentLinkedQueue cometTasksCache = new ConcurrentLinkedQueue();

    static Object dummy = null; // needed to prevent hotspot in 1.7 from being too clever

    public static void main(String[] args) throws InterruptedException {
        new Main();
    }

    public Main() throws InterruptedException {
        threadPool = new ThreadPoolExecutor(
                32,
                32,
                60L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(100,false));
        
        long t0 = System.currentTimeMillis();
        dotest(false);
        dotest(true);        
        System.err.println("completed in "+ (System.currentTimeMillis()-t0)/1000 +" seconds.");
        threadPool.shutdownNow();
    }

    private void dotest(boolean recycle) throws InterruptedException{
        startTestThreads(1,recycle);
        startTestThreads(4,recycle);
        startTestThreads(8,recycle);
        startTestThreads(32,recycle);
    }

    volatile long t1;

    private void startTestThreads(final int threadcount, final boolean recycle) throws InterruptedException{
        final CountDownLatch testfinished = new CountDownLatch(threadcount);
        final CountDownLatch starttest    = new CountDownLatch(threadcount);
        final int allocs = 15000000;
        for (int i=0;i<threadcount;i++){
            threadPool.execute(
            new Runnable(){
                @Override
                public void run(){
                    starttest.countDown();
                    try {
                        starttest.await();
                        t1 = System.nanoTime();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                        System.exit(-1);
                    }                    
                    if (recycle)
                        doitrecycle(allocs);
                    else
                        doitnew(allocs);                
                    testfinished.countDown();
                }
          });
        }
      testfinished.await();
      long t2 = System.nanoTime();
      System.err.println("recycled = "+recycle+"  allocator threads = "+threadcount+"   throughput = "+(((int)(allocs*10L*threadcount / ((t2 - t1)/1000d)))/10d) + " Million CometTasks/sec");
    }


    private void doitnew(int allocs){
        while(allocs-->0){
            dologic(new CometTask());
            //dologic(new CometContext("asd",-1));
        }
    }

    

    private void doitrecycle(int allocs){
        while(allocs-->0){
            CometTask ta = getCometTask();
            //CometContext ta = getCometContext();
            dologic(ta);
            ta.recycle();
            cometTasksCache.offer(ta);
        }
    }

    private void dologic(CometTask ta){
       for (int i=0;i<30;i++){ //lets do some work inbetween allocs. by changing the loop size we can notice on the throughput results that hotspot does not optimize away this loop, jdk 1.7 b41 -XX:+AggressiveOpts -server
            ta.setExpirationDelay(i);
            i = (int) ta.getExpirationDelay();
            ta.recycle();            
        }
        dummy = ta; // needed to prevent hotspot in 1.7 from being too clever, upto roughly 300% difference
    }



    private CometContext getCometContext(){
        CometContext a = (CometContext) cometTasksCache.poll();
        if (a == null){
            a = new CometContext("asd", 1);
        }
        return a;
   }

    private CometTask getCometTask(){
        CometTask cometTask = (CometTask) cometTasksCache.poll();
        if (cometTask == null){
            cometTask = new CometTask();
        }
        return cometTask;
   }


  
}