package com.pblabs.profiler;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.CharacterCodingException;
import org.apache.mina.common.IoSession;
import org.apache.mina.handler.StreamIoHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProfilerServerHandler extends StreamIoHandler{
public static int MAX_INT = Integer.MAX_VALUE-1;
public static String SAMPLE_DONE = "SAMPLE-DONE";
protected void processStreamIo(IoSession session, InputStream in, OutputStream out)
{
new Worker(in, out, session).start();
}
public class Worker extends Thread {
public FlashProfilerDataWindow dataWindow;
public int memoryUsed;
public ExecutionSample sampleRoot = new ExecutionSample();
public Logger log;
public int expectedSamples = 0;
public int samplesOnClient = 0;
public int receivedSamples = 0;
private NetStringCache netStringCache = new NetStringCache();
private DataInputStream messageBytes = null;
private DataOutputStream commandBytes = null;
public Worker(InputStream in, OutputStream out, IoSession session) {
setDaemon(true);
messageBytes = new DataInputStream(new BufferedInputStream(in));
commandBytes = new DataOutputStream(out);
log = LoggerFactory.getLogger("Profiler Session " + session.getRemoteAddress().toString());
log.info("Got connection!");
// Set up the window.
dataWindow = new FlashProfilerDataWindow(this);
}
public void logAndSetStatus(String msg)
{
log.info(msg);
// Refresh UI.
final String statusMsg = msg;
FlashProfiler.display.asyncExec(new Runnable()
{
public void run()
{
dataWindow.setStatus(statusMsg);
}
});
}
public void sendStart() throws IOException
{
logAndSetStatus("Sending sampling start.");
commandBytes.writeShort(0x4204);
commandBytes.flush();
}
public void sendPause() throws IOException
{
logAndSetStatus("Sending sampling stop.");
commandBytes.writeShort(0x4208);
commandBytes.flush();
}
public void reset()
{
synchronized (sampleRoot) {
dataWindow.rebuildTree();
sampleRoot = new ExecutionSample();
dataWindow.rebuildTreeView(sampleRoot);
}
}
public void run()
{
try
{
// Send a sampling start.
/*
log.info("Sending sampling start.");
commandBytes.writeShort(0x4204);
commandBytes.flush();
*/
/*
// Sleep for ten seconds...
sleep(60*1000);
// Send a sampling stop.
log.info("Sending sampling pause.");
commandBytes.writeShort(0x4206);
commandBytes.flush();
// Sleep for a touch.
sleep(1000);
// And request a dump.
log.info("Sending sampling dump request.");
commandBytes.writeShort(0x420a);
commandBytes.flush();*/
}
catch(Exception e)
{
log.error(e.toString());
return;
}
// Parse messages.
while(true)
{
messageBytes.mark(2048);
try
{
parseMessage(messageBytes);
}
catch(EOFException e)
{
e.printStackTrace();
log.error("Ran off end of stream; terminating.");
break;
}
catch(Exception e)
{
try
{
log.error("Resetting due to :" + e.toString());
messageBytes.reset();
}
catch(IOException e2)
{
log.error("Failed to reset stream due to " + e2.toString());
break;
}
}
}
}
/**
* Return a BitStream for the sample if the complete sample
* is there. Otherwise, reset the stream and return null.
*
* @param messageBytes
* @return
* @throws IOException
*/
private BitStream getSampleBitStream(DataInputStream messageBytes) throws IOException
{
long incomingSampleSize = 0xFFFFFFFFL & messageBytes.readInt();
// Make sure we have the whole sample
if (messageBytes.available() < incomingSampleSize)
{
//log.info("Not enough bytes for message");
messageBytes.reset();
return null;
}
byte[] bytes = new byte[(int)incomingSampleSize];
messageBytes.read(bytes,0,(int)incomingSampleSize);
BitStream bitStream = new BitStream((int)incomingSampleSize, bytes);
bitStream.setStringCache(netStringCache);
return bitStream;
}
public void parseMessage(DataInputStream messageBytes) throws CharacterCodingException, IOException, Exception
{
messageBytes.mark(10);
// Get the message type.
int type = messageBytes.readUnsignedShort();
BitStream bitStream = null;
switch(type)
{
case 0x4201: // HELLO
long seconds = messageBytes.readInt();
int remainder = messageBytes.readUnsignedShort();
long timer = messageBytes.readInt();
log.info("Got hello world with seconds=" + seconds + ", remainder=" + remainder + ",timer=" + timer);
break;
case 0x4203: // STATS
long timer1 = messageBytes.readInt();
long memory = messageBytes.readInt();
log.info("Get stats with timer=" + timer1 + ", memory=" + memory);
break;
case 0x4205: // sampling start ack.
logAndSetStatus("Sampling started.");
break;
case 0x4207: // sampling pause ack.
logAndSetStatus("Sampling paused.");
break;
case 0x4209: // sampling stop ack.
logAndSetStatus("Sampling stopped.");
break;
case 0x420b: // Results from sampler.
long numIncoming = messageBytes.readInt();
expectedSamples += numIncoming;
dataWindow.setStatus("Getting " + numIncoming + " more samples, expecting " + expectedSamples + " more.");
break;
case 0x4210: // new object sample.
bitStream = getSampleBitStream(messageBytes);
if (bitStream==null)
break;
receivedSamples++;
samplesOnClient = bitStream.readRangedInt(0, Integer.MAX_VALUE-1);
bitStream.readRangedInt(0,MAX_INT);
bitStream.readRangedInt(0,MAX_INT);
String allocationType = bitStream.readCachedString();
SampleStack ss = new SampleStack();
ss.read(bitStream);
ss.allocType = allocationType;
// Accumulate the data.
synchronized(sampleRoot)
{
sampleRoot.insert(0, 1, 0, ss);
}
String check = bitStream.readCachedString();
// log.info(check);
if (check==null || !check.equals(SAMPLE_DONE)) {
log.error("Missing message SAMPLE-DONE");
}
break;
case 0x4211: // delete object sample.
bitStream = getSampleBitStream(messageBytes);
if (bitStream==null)
break;
receivedSamples++;
samplesOnClient = bitStream.readRangedInt(0,MAX_INT);
bitStream.readRangedInt(0,MAX_INT);
bitStream.readRangedInt(0,MAX_INT);
bitStream.readRangedInt(0,MAX_INT);
SampleStack ss1 = new SampleStack();
ss1.read(bitStream);
if (!bitStream.readCachedString().equals(SAMPLE_DONE))
throw new Exception("Bad sample!");
break;
case 0x4212: // execution sample.
bitStream = getSampleBitStream(messageBytes);
if (bitStream==null)
break;
receivedSamples++;
samplesOnClient = bitStream.readRangedInt(0,MAX_INT);
int time = bitStream.readRangedInt(0,MAX_INT);
SampleStack ss2 = new SampleStack();
ss2.read(bitStream);
if (!bitStream.readCachedString().equals(SAMPLE_DONE))
throw new Exception("Bad sample!");
// Accumulate the data.
synchronized(sampleRoot)
{
sampleRoot.insert(time, 0, 0, ss2);
}
break;
}
if(receivedSamples > 0 && receivedSamples % 100 == 0)
{
receivedSamples++;
// Refresh UI.
FlashProfiler.display.asyncExec(new Runnable()
{
public void run()
{
dataWindow.rebuildTreeView(sampleRoot);
// Note process
dataWindow.setStatus("Got " + receivedSamples + " so far. " + samplesOnClient + " left on client.");
}
});
}
}
}
}