niedziela, 20 marca 2011

AIR based flash profiler - preview - 1 - socket protocol and memory samples

Well, since the only decent flash memory profiler available I know is in FlashBuilder (or FlexBuilder whatever) and I loved Clement Wong post about flex profiler I started to write one this weekend.

Well since AIR 2.0 have inside socket server I don't now need the java code until will I face some performance issues. To make profiler, first I needed the socket server and socket client to implement. The common known issue is the Socket class flush() in flashplayer. Since I have to send large portions of data I need some protocol to create, why ?
Well socket is pure communication layer without any more then bytearray support and like Steven Sacks wrote you need to handle socket connection by yourself.
So I created protocol, it's simple and stupid based on states.
each state has it's value and name and the names and values are as this:
 
package pl.vane.profiler.business.socket.states
{
public class SocketStateName
{
public static const START:String = "START";
public static const COMPLETE:String = "COMPLETE";
public static const DATA:String = "DATA";
public static const CLOSE:String = "CLOSE";
public static const ERROR_DATA:String = "ERROR_DATA";

public static const CONNECTED:String = "CONNECTED";
public static const DISCONNECTED:String = "DISCONNECTED";
}
}

package pl.vane.profiler.business.socket.states
{
public class SocketStateValue
{
public static const START:int = 1;
public static const COMPLETE:int = 2;
public static const DATA:int = 3;
public static const CLOSE:int = 4;
public static const ERROR_DATA:int = -1;

public static const CONNECTED:int = 101;
public static const DISCONNECTED:int = 102;
}
}

I am sending the values trough the socket from client to server and from server to client to determine communication layer.

So the basic usage is Start socket server in air application and listen for client
Both client and server has DISCONNECTED state at start.
When client connects server sends the START value as byte
And the client need to reply with the START also.
So now both client and server are connected so the handshake is made - pretty clear and nice.
Then the communication starts so I can send the DATA
So when I start sending the data I also send the size of it as uint
Also to prevent client from sending more data I change the client state to wait for COMPLETE message from server.
Since I don't know if it's all the data or only a part of it I check it and after all the data is received I inform client that everything goes fine. The only part I miss now Is the error handling layer to finish the both Server and Client side protocol. But I will try to implement it later. I wanted to make something visual fast ;)
So what to send from the client to server to measure. Well I started from analyze the good old Mr.doob stats class and then I created my own. I'm sending from client to server samples with memory and FPS so I can write some memory chart on server side. I will also plan to save memory samples to the array or since I have the SQLite engine in AIR I could save them there and then visualise the memory on some charts. It's pretty awesome when I think about it.
My VO's that I'm sending look like this:
 
package pl.vane.profiler.samples
{
import pl.vane.profiler.memory.MemoryUtils;

[RemoteClass("pl.vane.profiler.samples.MemorySample")]
public class MemorySample
{

public var freeMemory:Number;
public var privateMemory:Number;
public var totalMemory:Number;
public var fps:FPSSample;

function MemorySample(freeMemory:Number = NaN, privateMemory:Number = NaN, totalMemory:Number = NaN):void
{
this.freeMemory = freeMemory;
this.privateMemory = privateMemory;
this.totalMemory = totalMemory;
}

public function toString():String
{
return "free:"+MemoryUtils.bytesToMegabyte(freeMemory)+
", private:"+MemoryUtils.bytesToMegabyte(privateMemory)+
", total:"+MemoryUtils.bytesToMegabyte(totalMemory);
}
}
}

package pl.vane.profiler.samples
{

[RemoteClass("pl.vane.profiler.samples.FPSSample")]
public class FPSSample
{
public var frameRate:int;
public var stageFrameRate:int;
public function FPSSample(framerate:int, stageFrameRate:int)
{
this.frameRate = framerate;
this.stageFrameRate = stageFrameRate;
}

public function toString():String
{
return "framerate:"+frameRate+", stageFramerate:"+stageFrameRate;
}
}
}

Well when the data was send, there was my BIG BIG surprise that my server side AIR application doesn't recognize the classes but treat them like objects. So I can readObject from server side but I cannot cast that object as my library Class. Well I tried registerClassAlias and [RemoteClass] tag but nothing happend so I get stuck with objects. Well that sucks, but not as much to leave the project, and maybe I'm missing some tiny rule I didn't put to my code. Well nevermind.
So now what to do ? I will try implement flash.sampler.* api now and try to describeType all the application that I want to profile. Well it can take some time since I have permanent work from Monday to Friday.
But hopefully it will be more posts and more data to analyze. I'm also looking for some Ideas worth implementing in the profiler. Feel free to write some in comments.
I plan write about sampler api and how to get data you want.
Will try also publish the profiler as soon as it will be finished or will have some decent features like flashbuilder profiler.
Happy Codding.

screen of my profiler project, that is lame now ;) The top flash instance is simple flash client and the bottom is server that has client and server chart.
profiler preview