01: // $Id: Profiler.java 11 2007-08-19 20:05:36Z jcamaia $
02:
03: package net.sf.persist.tests.performance;
04:
05: import javassist.CannotCompileException;
06: import javassist.ClassPool;
07: import javassist.CtClass;
08: import javassist.CtMethod;
09: import javassist.CtNewMethod;
10: import javassist.Loader;
11: import javassist.NotFoundException;
12: import javassist.Translator;
13:
14: /**
15: * Poor man's profiler. Instruments the Persist class with Jamon monitors that allow for a report generation.
16: */
17: public class Profiler {
18:
19: public static void main(String[] args) throws Throwable {
20:
21: // add translator to class loader
22: Translator t = new JamonTranslator();
23: ClassPool pool = ClassPool.getDefault();
24: Loader cl = new Loader();
25: cl.addTranslator(pool, t);
26:
27: // execute main class using the class loader
28: // let it receive args[] as if it was invoked directly
29: String[] argsShifted = new String[args.length - 1];
30: System.arraycopy(args, 1, argsShifted, 0, args.length - 1);
31: cl.run(args[0], argsShifted);
32: }
33:
34: }
35:
36: /**
37: * Translator that adds Jamon monitors around every method of the Persist and TableMapping classes
38: */
39: class JamonTranslator implements Translator {
40:
41: public void start(ClassPool pool) throws NotFoundException,
42: CannotCompileException {
43: // do nothing
44: }
45:
46: public void onLoad(ClassPool pool, String classname)
47: throws NotFoundException, CannotCompileException {
48:
49: if (classname.equals("net.sf.persist.Persist")) /* || classname.endsWith("net.sf.persist.TableMapping")) */{
50:
51: CtClass cc = pool.get(classname);
52: for (CtMethod method : cc.getDeclaredMethods()) {
53: addJamonMonitor(cc, method);
54: }
55:
56: }
57: }
58:
59: private static void addJamonMonitor(CtClass cls, CtMethod method)
60: throws NotFoundException, CannotCompileException {
61:
62: // see http://www.ibm.com/developerworks/java/library/j-dyn0916.html
63:
64: // rename old method to synthetic name, then duplicate the method with original name for use as interceptor
65: String oname = method.getName();
66: String nname = oname + "$impl";
67: method.setName(nname);
68: CtMethod mnew = CtNewMethod.copy(method, oname, cls, null);
69:
70: // start the body text generation by saving the jamon monitor to a local variable, then call the timed method;
71: // the actual code generated needs to depend on whether the timed method returns a value
72: String type = method.getReturnType().getName();
73: StringBuffer body = new StringBuffer();
74: body
75: .append("{\ncom.jamonapi.Monitor mon = com.jamonapi.MonitorFactory.start(\""
76: + cls.getSimpleName() + "." + oname + "\");\n");
77: if (!"void".equals(type)) {
78: body.append(type + " result = ");
79: }
80: body.append(nname + "($$);\n");
81:
82: // finish body text generation stopping jamon monitor, and return saved value (if not void)
83: body.append("mon.stop();\n");
84: if (!"void".equals(type)) {
85: body.append("return result;\n");
86: }
87: body.append("}");
88:
89: // replace the body of the interceptor method with generated code block and add it to class
90: mnew.setBody(body.toString());
91: cls.addMethod(mnew);
92:
93: // print the generated code block just to show what was done
94: //System.out.println(body.toString());
95: }
96:
97: }
|