package edu.brown.profilers; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import edu.brown.utils.EventObservable; import edu.brown.utils.EventObserver; public abstract class AbstractProfiler { /** * Lazily construct this cache list of ProfileMeasurements only * when somebody asks for it. We will construct the lists in a thread-safe manner */ private ProfileMeasurement[] pm_cache = null; /** * Return a list of all of the ProfileMeasurement handles for this profiler * @return */ public final ProfileMeasurement[] getProfileMeasurements() { if (pm_cache == null) { synchronized (this) { if (pm_cache == null) { final List<ProfileMeasurement> temp = new ArrayList<ProfileMeasurement>(); for (Field f : this.getClass().getDeclaredFields()) { int modifiers = f.getModifiers(); if (Modifier.isTransient(modifiers) == false && Modifier.isPrivate(modifiers) == false && Modifier.isStatic(modifiers) == false) { Object obj = null; try { obj = f.get(this); } catch (Exception ex) { throw new RuntimeException("Failed to get value for field '" + f.getName() + "'", ex); } if (obj instanceof ProfileMeasurement) temp.add((ProfileMeasurement)obj); } } // FOR pm_cache = temp.toArray(new ProfileMeasurement[temp.size()]); } } // SYNCH } return (pm_cache); } public final ProfileMeasurement getProfileMeasurement(String name) { for (ProfileMeasurement pm : this.getProfileMeasurements()) { if (pm.getName().equals(name)) { return (pm); } } // FOR return (null); } /** * Reset this AbstractProfiler's internal data when an update arrives * for the given EventObservable * @param e */ public <T> void resetOnEventObservable(EventObservable<T> e) { e.addObserver(new EventObserver<T>() { @Override public void update(EventObservable<T> o, T arg) { AbstractProfiler.this.reset(); } }); } public void copy(AbstractProfiler other) { ProfileMeasurement pms0[] = this.getProfileMeasurements(); ProfileMeasurement pms1[] = other.getProfileMeasurements(); assert(pms0.length == pms1.length); for (int i = 0; i < pms0.length; i++) { pms0[i].appendTime(pms1[i]); assert(pms0[i].getName().equals(pms1[i])); } // FOR } /** * Reset all of the ProfileMeasurements within this profiler */ public void reset() { for (ProfileMeasurement pm : this.getProfileMeasurements()) { pm.reset(); } // FOR } /** * Returns a tuple of the values for this profiler * There will be two entries in the tuple for each ProfileMeasurement: * (1) The total think time in nanoseconds * (2) The number of invocations */ public long[] getTuple() { ProfileMeasurement pms[] = this.getProfileMeasurements(); long tuple[] = new long[pms.length*2]; this.populateTuple(tuple, 0, this.getProfileMeasurements()); return (tuple); } protected final void populateTuple(long tuple[], int offset, ProfileMeasurement pms[]) { for (ProfileMeasurement pm : pms) { tuple[offset++] = pm.getTotalThinkTime(); if (offset == 1) assert(tuple[0] > 0) : "Missing data " + pm.debug(); tuple[offset++] = pm.getInvocations(); } // FOR } public Map<String, Object> debugMap() { Map<String, Object> m = new LinkedHashMap<String, Object>(); // HEADER m.put(this.getClass().getSimpleName(), null); // FIELDS for (ProfileMeasurement pm : this.getProfileMeasurements()) { String label = pm.getName(); String debug = pm.debug().replace(label, ""); m.put(label, debug); } // FOR return (m); } }