1 cananian 1.1.2.1 // CounterFactory.java, created Wed Feb 21 14:35:40 2001 by cananian 2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Analysis.Counters; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.ClassFile.HClass; 7 cananian 1.1.2.1 import harpoon.ClassFile.HClassMutator; 8 cananian 1.1.2.3 import harpoon.ClassFile.HCodeFactory; 9 cananian 1.1.2.1 import harpoon.ClassFile.HField; 10 cananian 1.1.2.1 import harpoon.ClassFile.HFieldMutator; 11 cananian 1.1.2.3 import harpoon.ClassFile.HMethod; 12 cananian 1.1.2.1 import harpoon.ClassFile.Linker; 13 cananian 1.1.2.4 import harpoon.IR.Quads.CJMP; 14 cananian 1.1.2.1 import harpoon.IR.Quads.CONST; 15 cananian 1.1.2.1 import harpoon.IR.Quads.Edge; 16 cananian 1.1.2.1 import harpoon.IR.Quads.GET; 17 cananian 1.1.2.1 import harpoon.IR.Quads.MONITORENTER; 18 cananian 1.1.2.1 import harpoon.IR.Quads.MONITOREXIT; 19 cananian 1.1.2.1 import harpoon.IR.Quads.OPER; 20 cananian 1.1.2.4 import harpoon.IR.Quads.PHI; 21 cananian 1.1.2.1 import harpoon.IR.Quads.Qop; 22 cananian 1.1.2.1 import harpoon.IR.Quads.Quad; 23 cananian 1.1.2.1 import harpoon.IR.Quads.QuadFactory; 24 cananian 1.1.2.1 import harpoon.IR.Quads.SET; 25 cananian 1.1.2.1 import harpoon.Temp.Temp; 26 cananian 1.1.2.1 import harpoon.Util.Util; 27 cananian 1.1.2.1 28 cananian 1.1.2.1 import java.lang.reflect.Modifier; 29 cananian 1.1.2.3 import java.util.Iterator; 30 cananian 1.1.2.1 /** 31 cananian 1.1.2.1 * <code>CounterFactory</code> is a state-less instrumentation package, 32 cananian 1.1.2.1 * with the goal of making it as easy as possible to add counters 33 cananian 1.1.2.1 * and timers to executable code. It comes in several parts: we have 34 cananian 1.1.2.1 * a set of routines to splice in counter/time calls into Quad forms, 35 cananian 1.1.2.3 * and we have a post-processing <code>HCodeFactory</code> available 36 cananian 1.1.2.3 * from the <code>codeFactory()</code> method that will create the 37 cananian 1.1.2.3 * appropriate epilog code to report the counter values at 38 cananian 1.1.2.3 * program's end. 39 cananian 1.1.2.1 * <p> 40 cananian 1.1.2.1 * Counters are disabled by default. All counters can be enabled by 41 cananian 1.1.2.1 * setting the property <code>harpoon.counters.enabled.all</code> to 42 cananian 1.1.2.1 * <code>"true"</code> and particular counters can be enabled by 43 cananian 1.1.2.1 * setting the property <code>harpoon.counters.enabled.{counter-name}</code> 44 cananian 1.1.2.1 * to <code>"true"</code>. Particular counters can be disabled by 45 cananian 1.1.2.1 * setting the property <code>harpoon.counters.disabled.{counter-name}</code> 46 cananian 1.1.2.1 * to <code>"true"</code> and all counters can be disabled by setting 47 cananian 1.1.2.1 * the property <code>harpoon.counters.disabled.all</code> to 48 cananian 1.1.2.1 * <code>"true"</code>. 49 cananian 1.1.2.1 * <p> 50 cananian 1.1.2.1 * Counters can also be grouped into classes by naming them with 51 cananian 1.1.2.1 * dot-separated strings. For example, counters named 'foo.bar' 52 cananian 1.1.2.1 * and 'foo.baz' are both enabled by setting 53 cananian 1.1.2.1 * <code>harpoon.counters.enabled.foo</code> to <code>"true"</code>; 54 cananian 1.1.2.1 * the counters' actual name on output will be "foo_bar" and "foo_baz". 55 cananian 1.1.2.1 * 56 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 57 cananian 1.4 * @version $Id: CounterFactory.java,v 1.4 2002/04/10 02:58:58 cananian Exp $ 58 cananian 1.1.2.1 */ 59 cananian 1.1.2.1 public final class CounterFactory { 60 cananian 1.1.2.1 /** default status for all counters. */ 61 cananian 1.1.2.1 private static boolean ENABLED = false; 62 cananian 1.1.2.1 // don't allow object creation: all methods here are static. 63 cananian 1.1.2.1 private CounterFactory() { } 64 cananian 1.1.2.6 /** Returns the enabled/disabled status of the given 65 cananian 1.1.2.6 * <code>counter_name</code>. This can be used so that 66 cananian 1.1.2.6 * counter-support code may be added only when the counter 67 cananian 1.1.2.6 * it supports is actually enabled. */ 68 cananian 1.1.2.6 public static boolean isEnabled(String counter_name) { 69 cananian 1.1.2.1 if (Boolean.getBoolean("harpoon.counters.enabled.all")) 70 cananian 1.1.2.1 return true; 71 cananian 1.1.2.1 if (Boolean.getBoolean("harpoon.counters.disabled.all")) 72 cananian 1.1.2.1 return false; 73 cananian 1.1.2.1 if (Boolean.getBoolean("harpoon.counters.enabled."+counter_name)) 74 cananian 1.1.2.1 return true; 75 cananian 1.1.2.1 if (Boolean.getBoolean("harpoon.counters.disabled."+counter_name)) 76 cananian 1.1.2.1 return false; 77 cananian 1.1.2.1 // allow 'package' enable/disable by recursing to check package status 78 cananian 1.1.2.1 int idx = counter_name.lastIndexOf('.'); 79 cananian 1.1.2.1 if (idx>=0) return isEnabled(counter_name.substring(0, idx)); 80 cananian 1.1.2.1 // okay, can't find any guidance at all. Use "default". 81 cananian 1.1.2.1 return ENABLED; 82 cananian 1.1.2.1 } 83 cananian 1.1.2.10 public static boolean inCounters(Edge e) { 84 cananian 1.1.2.10 Quad q = (Quad) e.from(); 85 cananian 1.1.2.10 HMethod hm = q.getFactory().getMethod(); 86 cananian 1.1.2.10 return hm.getDeclaringClass().getName().equals 87 cananian 1.1.2.10 ("harpoon.Runtime.Counters"); 88 cananian 1.1.2.10 } 89 cananian 1.1.2.1 90 cananian 1.1.2.3 /** <code>HCodeFactory</code> that will add calls to the counter-printing 91 cananian 1.1.2.3 * epilog at the end of the given main method and before calls to 92 cananian 1.1.2.3 * <code>Runtime.exit()</code>. */ 93 cananian 1.1.2.3 public static HCodeFactory codeFactory(HCodeFactory parent, 94 cananian 1.1.2.3 Linker linker, HMethod main) { 95 cananian 1.1.2.3 // check whether *any* counters are enabled. 96 cananian 1.1.2.3 boolean enabled = ENABLED; 97 cananian 1.1.2.3 Iterator it=System.getProperties().keySet().iterator(); 98 cananian 1.1.2.3 while (it.hasNext()) 99 cananian 1.1.2.3 if (((String)it.next()).startsWith("harpoon.counters.enabled.")) 100 cananian 1.1.2.3 enabled = true; 101 cananian 1.1.2.3 if (Boolean.getBoolean("harpoon.counters.disabled.all")) 102 cananian 1.1.2.3 enabled = false; 103 cananian 1.1.2.3 if (Boolean.getBoolean("harpoon.counters.enabled.all")) 104 cananian 1.1.2.3 enabled = true; 105 cananian 1.1.2.3 // if nothing is enabled, don't bother splicing in our code factory. 106 cananian 1.1.2.3 if (!enabled) return parent; 107 cananian 1.1.2.3 // else do it! 108 cananian 1.1.2.9 parent = new RuntimeMethodCloner(parent, linker).codeFactory(); 109 cananian 1.1.2.3 return new EpilogMutator(parent, linker, main).codeFactory(); 110 cananian 1.1.2.3 } 111 cananian 1.1.2.3 112 cananian 1.1.2.1 /** Increment the named counter by 1 on the given edge. */ 113 cananian 1.1.2.1 public static Edge spliceIncrement(QuadFactory qf, 114 cananian 1.1.2.1 Edge e, String counter_name) { 115 cananian 1.1.2.1 return spliceIncrement(qf, e, counter_name, 1); 116 cananian 1.1.2.1 } 117 cananian 1.1.2.1 /** Increment the named counter by <code>value</code> on the given edge. */ 118 cananian 1.1.2.1 public static Edge spliceIncrement(QuadFactory qf, 119 cananian 1.1.2.1 Edge e, String counter_name, 120 cananian 1.1.2.1 long value) { 121 cananian 1.1.2.1 if (!isEnabled(counter_name)) return e; 122 cananian 1.1.2.10 if (inCounters(e)) return e; 123 cananian 1.1.2.1 Temp t = new Temp(qf.tempFactory()); 124 cananian 1.1.2.1 return spliceIncrement(qf, 125 cananian 1.1.2.1 addAt(e, new CONST(qf, null, t, new Long(value), 126 cananian 1.1.2.1 HClass.Long)), 127 cananian 1.1.2.5 counter_name, t, true); 128 cananian 1.1.2.1 } 129 cananian 1.1.2.1 /** Increment the named counter by the amount in the <code>Temp</code> 130 cananian 1.1.2.5 * <code>Tvalue</code> on the given edge. If <code>isLong</code> 131 cananian 1.1.2.5 * is <code>true</code>, then <code>Tvalue</code> should have type 132 cananian 1.1.2.5 * <code>long</code>; else it should have type <code>int</code>. */ 133 cananian 1.1.2.1 public static Edge spliceIncrement(QuadFactory qf, 134 cananian 1.1.2.1 Edge e, String counter_name, 135 cananian 1.1.2.5 Temp Tvalue, boolean isLong) { 136 cananian 1.1.2.7 Quad CJMP1, CJMP2, PHI1, PHI2; 137 cananian 1.1.2.1 if (!isEnabled(counter_name)) return e; 138 cananian 1.1.2.10 if (inCounters(e)) return e; 139 cananian 1.1.2.5 if (!isLong) { 140 cananian 1.1.2.5 Temp t = new Temp(qf.tempFactory()); 141 cananian 1.1.2.5 e = addAt(e, new OPER(qf, null, Qop.I2L, t, new Temp[]{ Tvalue })); 142 cananian 1.1.2.5 Tvalue = t; 143 cananian 1.1.2.5 } 144 cananian 1.1.2.1 HField HFcounter = getCounterField(qf.getLinker(), counter_name); 145 cananian 1.1.2.3 HField HFlockobj = getLockField(qf.getLinker(), counter_name); 146 cananian 1.1.2.1 // first fetch the lock 147 cananian 1.1.2.1 Temp Tlck = new Temp(qf.tempFactory()); 148 cananian 1.1.2.1 e = addAt(e, new GET(qf, null, Tlck, HFlockobj, null)); 149 cananian 1.1.2.7 // if package not initialized, then we're still single-threaded. 150 cananian 1.1.2.7 // (i.e., we can safely skip the monitorenter) 151 cananian 1.1.2.4 Temp Tnul = new Temp(qf.tempFactory()); 152 cananian 1.1.2.4 e = addAt(e, new CONST(qf, null, Tnul, null, HClass.Void)); 153 cananian 1.1.2.4 Temp Tcmp = new Temp(qf.tempFactory()); 154 cananian 1.1.2.4 e = addAt(e, new OPER(qf, null, Qop.ACMPEQ, Tcmp, 155 cananian 1.1.2.4 new Temp[] { Tlck, Tnul })); 156 cananian 1.1.2.7 e = addAt(e, CJMP1=new CJMP(qf, null, Tcmp, new Temp[0])); 157 cananian 1.1.2.7 // lock if we can. 158 cananian 1.1.2.1 e = addAt(e, new MONITORENTER(qf, null, Tlck)); 159 cananian 1.1.2.7 e = addAt(e, PHI1=new PHI(qf, null, new Temp[0], 2)); 160 cananian 1.1.2.1 // then fetch the old counter value 161 cananian 1.1.2.1 Temp Tcnt = new Temp(qf.tempFactory()); 162 cananian 1.1.2.1 e = addAt(e, new GET(qf, null, Tcnt, HFcounter, null)); 163 cananian 1.1.2.1 // increment it, consistent with SSx forms. 164 cananian 1.1.2.1 Temp Tcnt2 = new Temp(qf.tempFactory()); 165 cananian 1.1.2.1 e = addAt(e, new OPER(qf, null, Qop.LADD, Tcnt2, 166 cananian 1.1.2.1 new Temp[] { Tcnt, Tvalue})); 167 cananian 1.1.2.1 // and store it back. 168 cananian 1.1.2.1 e = addAt(e, new SET(qf, null, HFcounter, null, Tcnt2)); 169 cananian 1.1.2.7 // now release the lock (if we need to) 170 cananian 1.1.2.7 e = addAt(e, CJMP2=new CJMP(qf, null, Tcmp, new Temp[0])); 171 cananian 1.1.2.1 e = addAt(e, new MONITOREXIT(qf, null, Tlck)); 172 cananian 1.1.2.4 // merge from bypass. 173 cananian 1.1.2.7 e = addAt(e, PHI2=new PHI(qf, null, new Temp[0], 2)); 174 cananian 1.1.2.7 Quad.addEdge(CJMP1, 1, PHI1, 1); 175 cananian 1.1.2.7 Quad.addEdge(CJMP2, 1, PHI2, 1); 176 cananian 1.1.2.1 // done! 177 cananian 1.1.2.1 return e; 178 cananian 1.1.2.1 } 179 cananian 1.1.2.1 180 cananian 1.1.2.1 // get counter and lock field, creating it if necessary. 181 cananian 1.1.2.1 static HField getCounterField(Linker l, String counter_name) { 182 cananian 1.1.2.1 return getField(l, "COUNTER_"+counter_name, "J"); 183 cananian 1.1.2.1 } 184 cananian 1.1.2.1 static HField getLockField(Linker l, String counter_name) { 185 cananian 1.1.2.1 return getField(l, "LOCK_"+counter_name, "Ljava/lang/Object;"); 186 cananian 1.1.2.1 } 187 cananian 1.1.2.1 private static HField getField(Linker l, String name, String descriptor) { 188 cananian 1.1.2.1 HClass hc = l.forName("harpoon.Runtime.Counters"); 189 cananian 1.1.2.1 name = name.replace('.','_'); // allow '.' in name, but strip. 190 cananian 1.1.2.7 name = name.replace('-','_'); // likewise for '-' 191 cananian 1.1.2.1 try { 192 cananian 1.1.2.1 HField hf = hc.getDeclaredField(name); 193 cananian 1.3.2.1 assert hf.getDescriptor().equals(descriptor); 194 cananian 1.3.2.1 assert hf.isStatic(); 195 cananian 1.1.2.1 return hf; 196 cananian 1.1.2.1 } catch (NoSuchFieldError e) { 197 cananian 1.1.2.1 // okay, have to create this field ourselves. 198 cananian 1.1.2.1 HField hf = hc.getMutator().addDeclaredField(name, descriptor); 199 cananian 1.1.2.1 // make public and static 200 cananian 1.1.2.1 hf.getMutator().setModifiers(Modifier.PUBLIC | Modifier.STATIC); 201 cananian 1.1.2.1 return hf; 202 cananian 1.1.2.1 } 203 cananian 1.1.2.1 } 204 cananian 1.1.2.1 205 cananian 1.1.2.1 // private helper functions. 206 cananian 1.1.2.1 private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); } 207 cananian 1.1.2.1 private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) { 208 cananian 1.1.2.1 Quad frm = (Quad) e.from(); int frm_succ = e.which_succ(); 209 cananian 1.1.2.1 Quad to = (Quad) e.to(); int to_pred = e.which_pred(); 210 cananian 1.1.2.1 Quad.addEdge(frm, frm_succ, q, which_pred); 211 cananian 1.1.2.1 Quad.addEdge(q, which_succ, to, to_pred); 212 cananian 1.1.2.1 return to.prevEdge(to_pred); 213 cananian 1.1.2.1 } 214 cananian 1.2 }