// $Header: /p/sss/cvs/OpenVM/src/s3/core/services/events/ProfilingEventManagerImpl.java,v 1.4 2004/10/13 17:11:16 pizlofj Exp $

package s3.core.services.events;

import ovm.core.services.events.*;
import ovm.core.execution.Native;
import ovm.core.execution.NativeInterface;
import s3.util.PragmaNoPollcheck;
import s3.util.PragmaAtomic;

public class ProfilingEventManagerImpl
    extends EventManagerImpl {

    static final class NativeHelper implements NativeInterface {
	static native void dumpProfileHisto(byte[] name,
					    int nameSize,
					    long[] histo,
					    int histoSize,
					    long overflow);
    }

    private final static EventManager instance=
	new ProfilingEventManagerImpl();
    public static EventManager getInstance() {
	return instance;
    }

    public static final int HISTO_SIZE=1000;
    public static final long GRANULARITY=1000;

    long[] totalLatencyHisto=new long[HISTO_SIZE];
    long totalLatencyOverflow;

    long[][] processorLatencyHisto=new long[PROCESSORS_ARRAY_STEP][];
    long[] processorLatencyOverflow=new long[PROCESSORS_ARRAY_STEP];

    public void aboutToShutdown() {
	super.aboutToShutdown();
	String totalName="evman_profile.total";
	NativeHelper.dumpProfileHisto(totalName.getBytes(),
				      totalName.length(),
				      totalLatencyHisto,
				      HISTO_SIZE,
				      totalLatencyOverflow);
	for (int i=0;
	     i<numProcessors;
	     ++i) {
	    String shortName=
		"evman_profile."+
		processors[i].eventProcessorShortName();
	    NativeHelper.dumpProfileHisto(shortName.getBytes(),
					  shortName.length(),
					  processorLatencyHisto[i],
					  HISTO_SIZE,
					  processorLatencyOverflow[i]);
	}
    }

    protected static long currentTime() {
	return Native.getCurrentTime()/GRANULARITY;
    }

    protected void callEventProcessor(int i)
	throws PragmaNoPollcheck {
	// the lack of a try-finally is intentional.  I don't want
	// to record stuff in the histo if we're propagating exceptions,
	// since an exception means that something got seriously messed
	// up!
	long before=currentTime();
	super.callEventProcessor(i);
	long latency=currentTime()-before;
	if (latency>=HISTO_SIZE) {
	    processorLatencyOverflow[i]++;
	} else {
	    processorLatencyHisto[i][(int)latency]++;
	}
    }

    public void processEvents() throws PragmaNoPollcheck {
	// the lack of a try-finally is intentional.  I don't want
	// to record stuff in the histo if we're propagating exceptions,
	// since an exception means that something got seriously messed
	// up!
	long before=currentTime();
	super.processEvents();
	long latency=currentTime()-before;
	if (latency>=HISTO_SIZE) {
	    totalLatencyOverflow++;
	} else {
	    totalLatencyHisto[(int)latency]++;
	}
    }

    protected int addEventProcessorImpl(EventProcessor handler)
	throws PragmaAtomic {
	int index=super.addEventProcessorImpl(handler);
	if (processors.length>processorLatencyHisto.length) {
	    long[][] newArrayArray=
		new long[processors.length][];
	    System.arraycopy(processorLatencyHisto,0,
			     newArrayArray,0,
			     processorLatencyHisto.length);
	    processorLatencyHisto=newArrayArray;

	    long[] newArray=
		new long[processors.length];
	    System.arraycopy(processorLatencyOverflow,0,
			     newArray,0,
			     processorLatencyOverflow.length);
	    processorLatencyOverflow=newArray;
	}
	processorLatencyHisto[index]=new long[HISTO_SIZE];
	return index;
    }

    protected void removeEventProcessorHook(int i)
	throws PragmaAtomic {
	processorLatencyHisto[i]=processorLatencyHisto[numProcessors-1];
	processorLatencyOverflow[i]=processorLatencyOverflow[numProcessors-1];
	processorLatencyHisto[numProcessors-1]=null;
	processorLatencyOverflow[numProcessors-1]=0;
    }
}


