ProfilerIf pluggable delegate api.

Quartz <[email protected]> Fri, 1 Aug 2003 15:44:43 -0700 (PDT)
Newsgroups gmane.comp.java.seda.user
Message-ID <[email protected]>
Hi,

Thought you might like a live profiler UI.
Siply update your sandStormProfiler (or merge changes).

I simply forward some call to the plugged implementation.
the config section look like this:

<profile>
  enable true
  #if class not present will default to printwriter
  class tests.basic.ProfilerDelegateUI
  
  <delegatevar>
    #number of point to keep per graph
    buffersize 400
    
    #number of columns in the ui
    columns 3

    #item name profiling filters: list of regex seperated by spaces
    #acceptregex (.*)(StageName)(.*)
    rejectregex ^(TPController)(.+)
    
    #color regexes: list of "regex hexcolor" pairs separated by spaces
    bgcolors ^(ThreadPool)(.+) 000040 (.+)(queueLength)(.*) 400000
    #fgcolors ^(ThreadPool)(.+) 0000ff (.+)(queueLength)(.*) ff0000
    #tcolors ^(ThreadPool)(.+) 0000ff (.+)(queueLength)(.*) ff0000
  </delegatevar>
</profile>


__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com
seda_profilerUI_snapshot.jpg (image/jpeg, 101.9 KB) - not displayed
ProfilerDelegateUI.java (text/plain, 8.1 KB)
/*
 * Created on Jul 31, 2003
 *
 * To change this generated comment go to 
 * Window>Preferences>Java>Code Generation>Code Template
 */
package tests.basic;

import java.awt.*;
import java.awt.event.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Pattern;

import seda.sandStorm.api.ManagerIF;
import seda.sandStorm.internal.sandStormProfiler;
import seda.sandStorm.main.SandstormConfig;

/**
 * @author ddeschenes
 */
public class ProfilerDelegateUI implements sandStormProfiler.IProfilerDelegate {
	
	LinkedHashMap items = new LinkedHashMap(); //string to list of Long
	
	HashSet includeNamePatterns = new HashSet();
	HashSet excludeNamePatterns = new HashSet();
	HashMap bgColors = new HashMap();
	HashMap fgColors = new HashMap();
	HashMap tColors = new HashMap();
	
	private int defaultsize = 600;
	ProfilerUI ui;

	public void init(ManagerIF mgr, final int sampledelay) {
		
		defaultsize = mgr.getConfig().getInt("global.profile.delegatevar.buffersize", 600);
		int col = mgr.getConfig().getInt("global.profile.delegatevar.columns", 3);
		
		readFilters(mgr.getConfig());
		readColors(mgr.getConfig().getStringList("global.profile.delegatevar.bgcolors"), bgColors);
		readColors(mgr.getConfig().getStringList("global.profile.delegatevar.fgcolors"), fgColors);
		readColors(mgr.getConfig().getStringList("global.profile.delegatevar.tcolors"), tColors);
		
		ui = new ProfilerUI(this, col);
		ui.setSize(600, 400);
		ui.setLocation(300,300);
		ui.setVisible(true);
		
		Thread t = new Thread("ProfilerUI-Repainter("+sampledelay+")") {
			public void run() {
				while(true) {
					ui.repaint();
					try {sleep(sampledelay);}
					catch(InterruptedException e) { break;}
				}
				System.out.println(getName()+": exiting");
			}
		};
		
		t.start();
	}
	
	private void readFilters(SandstormConfig cfg) {
		
		String[] ar = cfg.getStringList("global.profile.delegatevar.acceptregex");
		for(int i=0; ar!=null && i<ar.length; i++){
			Pattern p = null;
			try {p = Pattern.compile(ar[i]);} catch(Exception e) {e.printStackTrace();}
			if(p!=null)
				includeNamePatterns.add(p);
		}
		
		String[] rr = cfg.getStringList("global.profile.delegatevar.rejectregex");
		for(int i=0; rr!=null && i<rr.length; i++){
			Pattern p = null;
			try {p = Pattern.compile(rr[i]);} catch(Exception e) {e.printStackTrace();}
			if(p!=null)
				excludeNamePatterns.add(p);
		}
	}
	
	private void readColors(String[] regex_color_pairs, Map map) {
		for(int i=0; regex_color_pairs!=null && (i+1)<regex_color_pairs.length; i+=2){
			Pattern p = null;
			try {p = Pattern.compile(regex_color_pairs[i]);} catch(Exception e) {e.printStackTrace();}
			if(p!=null)
				map.put(p, new Color(Integer.parseInt(regex_color_pairs[i+1], 16)));
		}
	}		
	
	private Color findColor(String name, Map map, Color def) {
		for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
			Map.Entry e = (Map.Entry)it.next();
			Pattern p = (Pattern)e.getKey();
			if(p.matcher(name).matches()) {
				return (Color)e.getValue();
			}
		}
		
		return def;
	}
	
	private boolean accept(String name) {

		//System.out.println("########## ProfilerDelegateUI.add(\""+name+"\")");
		
		if(includeNamePatterns.size()>0) {
			for (Iterator it = includeNamePatterns.iterator(); it.hasNext();) {
				Pattern p = (Pattern)it.next();
				if(p.matcher(name).matches())
					return true;
			}
		}
		
		if(excludeNamePatterns.size()>0) {
			for (Iterator it = excludeNamePatterns.iterator(); it.hasNext();) {
				Pattern p = (Pattern)it.next();
				if(p.matcher(name).matches())
					return false;
			}
		}
		
		return true;
	}
	
	public void add(String name) {
		if(!accept(name))
			return;

		Curve c = new Curve(defaultsize);
		c.bgcolor = findColor(name, bgColors, Color.BLACK);
		c.fgcolor = findColor(name, fgColors, Color.GREEN);
		c.tcolor  = findColor(name, tColors, Color.LIGHT_GRAY);
		items.put(name, c);
	}

	public void remove(String name) {
		items.remove(name);
	}

	public void update(String name, long value) {
		Curve c = (Curve)items.get(name);
		if (c != null)
			c.add(value);
	}

	public void destroy() {
		if (ui != null)
			ui.dispose();
		items.clear();
	}
	
	//---------------

	static class Curve {
		long[] values;
		int count = 0;
		int nextpos = 0;
		
		Color bgcolor = Color.BLACK;
		Color fgcolor = Color.GREEN;
		Color tcolor  = Color.WHITE;
		
		Curve(int size) {
			values = new long[size];
		}
		
		synchronized void add(long l) {
			values[nextpos] = l;
			nextpos = (nextpos + 1) % values.length;
			count++;
			if (count > values.length)
				count = values.length;
		}
		
		synchronized long[] getValues() {
			long[] la = new long[count];
			if(nextpos==count) {//wrapped
				System.arraycopy(values, 0, la, 0, count);
			} else if (nextpos<count){
				System.arraycopy(values, nextpos, la, 0, count-nextpos);
				System.arraycopy(values, 0, la, count-nextpos, nextpos);
			} else {
				throw new RuntimeException("nextpos ("+nextpos+") > count ("+count+")");
			}
			
			return la;
		}
		
		static long findMax(long[] la) {
			int n = la.length;
			long m = 0;
			for(int i=0; i<n; i++) {
				if(la[i]>m)
					m = la[i];
			}
			return m;
		}
	}


	static class ProfilerUI extends Frame {
		Graph graph;
		ProfilerDelegateUI pd;
		
		ProfilerUI(ProfilerDelegateUI _pd, int columns) {
			super("ProfilerUI");
			this.pd = _pd;
			
			setLayout(new BorderLayout());

			addWindowListener(new WindowAdapter() {
				public void windowClosing(WindowEvent e) {
					pd.destroy();
				}
			});

			graph = new Graph(pd, columns);
			graph.setFont(new Font("Dialog", Font.PLAIN, 10));
			this.add(graph, BorderLayout.CENTER);
		}

		public void doLayout() {
			Dimension d = getSize();
			Insets ins = getInsets();
			graph.setBounds(ins.left, ins.top, d.width - ins.left - ins.right, d.height - ins.top - ins.bottom);
		}
	}

	static class Graph extends Component {
		static Color fg = Color.white;
		static Color bg = Color.black;

		static final int TOP = 2;
		static final int BOTTOM = 2;
		static final int LEFT = 2;
		static final int RIGHT = 2;
		static final int GAP = 2;
		
		ProfilerDelegateUI pd;
		int columns;
		
		Graph(ProfilerDelegateUI pd, int columns) {
			this.pd = pd;
			this.columns = columns;
		}
		
		public void update(Graphics g) {
			paint(g);
		}

		public void paint(Graphics g) {
			Dimension d = getSize();
			g.setColor(bg);
			g.fillRect(0, 0, d.width, d.height);
			g.setColor(fg);
			g.drawRect(0, 0, d.width - 1, d.height - 1);
			
			try {
				paintSeries(g, LEFT, TOP, d.width - LEFT - RIGHT, d.height - TOP - BOTTOM, pd.items);
			} catch(Throwable t) {
				t.printStackTrace();
			}
			
			Toolkit.getDefaultToolkit().sync();
		}

		void paintSeries(Graphics g, int x, int y, int w, int h, Map items) {
			int n = items.size();
			if(n<=0)
				return;
			
			Map.Entry[] entries = (Map.Entry[])items.entrySet().toArray(new Map.Entry[n]);
			int rows = (n-1)/columns +1;
			int sh = h/rows;
			int sw = w/columns;
			for(int i=0; i<n; i++) {
				Curve c = (Curve)entries[i].getValue();
				paintOne(g, (String)entries[i].getKey(), c, x + sw*(i%columns) +2, y + sh*(i/columns) +2, sw-4, sh-4);
			}
		}
		
		static void paintOne(Graphics g, String name, Curve c, int x, int y, int w, int h) {
			g.setColor(c.bgcolor);
			g.fillRect(x, y, w, h);

			g.setColor(Color.DARK_GRAY);
			g.drawRect(x, y, w, h);
			
			String msg = name;
			
			if(c.count>0) {
				g.setColor(Color.GREEN);
				long[] values = c.getValues();
				long maxy = Curve.findMax(values);
				long amp = (maxy<=0 ? 1 : maxy);
				
				int sx1=0;
				int sy1=(int)(h*values[0]/amp);
				
				for(int i=0; i<values.length; i++) {
					long val = values[i];
					int sx2 = (int) (w*i/values.length);
					int sy2 = (int) (h*val/amp);
					g.drawLine(x+sx1, y+h-sy1, x+sx2, y+h-sy2);
					sx1 = sx2;
					sy1 = sy2;
				}
				
				msg += " = "+values[values.length-1]+" (max="+maxy+")";
			} else {
				msg += " (no result)";
			}
			
			FontMetrics fm = g.getFontMetrics();
			int sw = fm.stringWidth(msg);
			//int ma = fm.getMaxAscent();
			//int md = fm.getMaxDescent();
			g.setColor(Color.lightGray);
			g.drawString(msg, x+ (w-sw)/2, y + h/2);
		}
	}

}
sandStormProfiler.java (text/plain, 5 KB)
/* 
 * Copyright (c) 2001 by Matt Welsh and The Regents of the University of 
 * California. All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Author: Matt Welsh <[email protected]>
 * 
 */

package seda.sandStorm.internal;

import seda.sandStorm.api.*;
import seda.sandStorm.main.*;
import java.io.*;
import java.util.*;

/**
 * sandStormProfiler is an implementation of the ProfilerIF interface
 * for Sandstorm. It is implemented using a thread that periodically
 * samples the set of ProfilableIF's registered with it, and outputs
 * the profile to a file.
 *
 * @author Matt Welsh
 * @see ProfilerIF
 * @see ProfilableIF
 */
public class sandStormProfiler extends Thread implements sandStormConst, ProfilerIF {

	private int delay;
	private PrintWriter pw;
	private Vector profilables;
	private boolean started = false;
	private StageGraph graphProfiler;
	
	private IProfilerDelegate delegate;
	
	public interface IProfilerDelegate { //HACK: delegate interface
		void init(ManagerIF mgr, int sampledelay);
		void add(String name);
		void remove(String name);
		void update(String name, long value);
		void destroy();
	}

	sandStormProfiler(ManagerIF mgr) throws IOException {
		super("SandStorm Profiler");
		graphProfiler = new StageGraph(mgr);
		SandstormConfig config = mgr.getConfig();
		delay = config.getInt("global.profile.delay");
		
		//HACK: delegate interface
		boolean enable = config.getBoolean("global.profile.enable");
		if(enable) {
			String delegateClassname = config.getString("global.profile.class");
			if (delegateClassname == null) {
				String filename = config.getString("global.profile.filename");
				pw = new PrintWriter(new FileWriter(filename, true));
			} else {
				try {
					delegate = (IProfilerDelegate)Class.forName(delegateClassname).newInstance();
					delegate.init(mgr, delay);
					delegate.add("usedmem(kb)");
					delegate.add("freemem(kb)");
					delegate.add("totalmem(kb)");
				} catch(Exception e) {
					e.printStackTrace();
				}
			}
		}

		profilables = new Vector(1);
	}

	/**
	 * Returns true if the profiler is enabled.
	 */
	public boolean enabled() {
		return started;
	}

	/**
	 * Add a class to this profiler.
	 */
	public void add(String name, ProfilableIF pr) {
		if (pr == null)
			return;
		if (pw == null && delegate==null)//HACK: delegate interface
			return;
		
		synchronized (profilables) {
			if(delegate==null) {//HACK: delegate interface
				pw.println("# Registered " + profilables.size() + " " + name);
			} else {
				delegate.add(name);
			}
			
			profilables.addElement(new profile(name, pr));
		}
	}

	public void run() {

		if (pw == null && delegate==null)//HACK: delegate interface
			return;
		
		started = true;
		
		if(pw!=null) {//HACK: delegate interface
			pw.println("##### Profile started at " + (new Date()).toString());
			pw.println("##### Sample delay " + delay + " msec");
		}
		
		Runtime r = Runtime.getRuntime();

		while (true) {

			long totalmem = r.totalMemory() / 1024;
			long freemem = r.freeMemory() / 1024;

			if(pw!=null)//HACK: delegate interface
				pw.print("totalmem(kb) " + totalmem + " freemem(kb) " + freemem + " ");
			else if(delegate!=null) {
				delegate.update("totalmem(kb)",totalmem);
				delegate.update("freemem(kb)",freemem);
				delegate.update("usedmem(kb)",(totalmem-freemem));
			}
				

			synchronized (profilables) {
				if (profilables.size() > 0) {
					for (int i = 0; i < profilables.size(); i++) {
						profile p = (profile)profilables.elementAt(i);
						if(pw!=null)//HACK: delegate interface
							pw.print("pr" + i + " " + p.pr.profileSize() + " ");
						else if(delegate!=null) {
							delegate.update(p.name, p.pr.profileSize());
						}
					}
				}
			}
			
			if(pw!=null) {//HACK: delegate interface
				pw.println("");
				pw.flush();
			}

			try {
				Thread.currentThread().sleep(delay);
			} catch (InterruptedException ie) {
				break;
			}
		} //while true
		
		started=false;
		delegate.destroy();//HACK: delegate interface
	}

	public StageGraph getGraphProfiler() {
		return graphProfiler;
	}

	class profile {
		String name;
		ProfilableIF pr;

		profile(String name, ProfilableIF pr) {
			this.name = name;
			this.pr = pr;
		}
	}

}