00001 package org.hfbk.vis.visnode;
00002
00003 import java.util.Map;
00004
00005 import org.dronus.gl.GLFont;
00006 import org.dronus.gl.GLSphereRenderer;
00007 import org.dronus.gl.GLTextPanel;
00008 import org.dronus.gl.GLUtil;
00009 import org.dronus.graph.Edge;
00010 import org.dronus.graph.Graph;
00011 import org.dronus.graph.Node;
00012 import org.hfbk.util.Counter;
00013 import org.hfbk.util.Sleeper;
00014 import org.lwjgl.opengl.GL11;
00015 import org.lwjgl.util.vector.Vector3f;
00016
00029 public class VisProfiler extends VisSet {
00030
00032
00033 final int DELAY=1000;
00034
00036 Graph profile=new Graph();
00037
00039 Counter<Integer> callCounter=new Counter<Integer>();
00040
00041
00042 boolean dirty=true;
00043
00045 class VisCallBall extends VisNodeDraggable {
00046 int dl;
00047 GLTextPanel helpText;
00048 Node node;
00049 boolean isTriggered=true;
00050
00051 VisCallBall(Node n, Vector3f position) {
00052 super(n, position);
00053 this.node=n;
00054 w=h=radius=1.6f;
00055 helpText=new GLTextPanel(n.text,0,0);
00056 }
00057
00058 void renderSelf() {
00059 Integer count=callCounter.get(node.id);
00060 if (count!=null){
00061 radius=.3f+10*(float)Math.sqrt(count/(float)callCounter.total);
00062 w=h=2*radius;
00063 }
00064 if (isHoovered || isTriggered)
00065 GL11.glColor3f(1,1,1);
00066 else if (node.type.equals("Thread"))
00067 GL11.glColor3f(1,1,.4f);
00068 else if (node.type.equals("Call")){
00069 boolean isOur=node.text.startsWith("org.dronus")||node.text.startsWith("org.hfbk");
00070 GL11.glColor4f(1,0,0,(isOur ? 1 : .5f ));
00071 }
00072
00073 GLSphereRenderer.renderSphere(radius);
00074
00075
00076 if (isHoovered) {
00077 GL11.glTranslatef(radius,radius,0);
00078 GLUtil.billboardCylinder();
00079 GL11.glScalef(1,2,1);
00080 GLFont.getDefault().render();
00081 helpText.render();
00082 GL11.glDisable(GL11.GL_TEXTURE_2D);
00083 }
00084
00085 isTriggered=false;
00086 }
00087 }
00088
00090 VisNode create(Node node, Vector3f pos) {
00091 return new VisCallBall(node, pos);
00092 }
00093
00095 public VisProfiler(Node dummy, Vector3f position) {
00096 super(null, position);
00097
00098 profile.addNode(new Node("0","Vis/Client","Set"));
00099
00100 Thread profiler=new Thread(){
00101 public void run() {
00102 setName("VisProfiler");
00103 while(true){
00104 synchronized(VisProfiler.this){ profile(); };
00105 Sleeper.sleep(DELAY);
00106 }
00107 }
00108 };
00109 profiler.start();
00110 }
00111
00116 void profile(){
00117 Node rootset=profile.getRoot();
00118
00119
00120 for(Map.Entry<Thread,StackTraceElement[]> trace : Thread.getAllStackTraces().entrySet()){
00121
00122 String threadName=trace.getKey().getName();
00123 int threadId=threadName.hashCode();
00124 Node threadNode=profile.findNode(threadId);
00125 if(threadNode==null) {
00126 threadNode=new Node(threadId, threadName, "Thread");
00127 profile.addNode(threadNode);
00128 profile.addEdge(new Edge(threadNode,rootset, null, "in"));
00129 }
00130 StackTraceElement[] stes=trace.getValue();
00131
00132
00133 for (int i=0; i<stes.length/2; i++){
00134 StackTraceElement tmp=stes[i];
00135 stes[i]=stes[stes.length-i-1];
00136 stes[stes.length-i-1]=tmp;
00137 }
00138
00139
00140 Node last=null;
00141 for (StackTraceElement ste: stes){
00142
00143 int id=threadId^ste.getClassName().hashCode()^ste.getMethodName().hashCode();
00144
00145 callCounter.add(id);
00146
00147 Node n=profile.findNode(id);
00148
00149 if (n==null){
00150 n=new Node(id, ste.getClassName()+"."+ste.getMethodName(),"Call");
00151 profile.addNode(n);
00152 dirty=true;
00153 }
00154 profile.addEdge(new Edge(n,rootset, null, "in"));
00155
00156 if (last!=null)
00157 profile.addEdge(new Edge(last,n, null, ""));
00158 else
00159 profile.addEdge(new Edge(n,threadNode, null, "in"));
00160 last=n;
00161 }
00162
00163
00164 VisNode vn=nodes.get(last);
00165 if (vn instanceof VisCallBall)
00166 ((VisCallBall)vn).isTriggered=true;
00167 }
00168 }
00169
00170 void renderSelf() {
00171 super.renderSelf();
00172
00173
00174 if (dirty) synchronized(this){
00175 Node root=profile.getRoot();
00176 update(root);
00177
00178 dirty=false;
00179 }
00180 }
00181 }