001 /******************************************************************************* 002 * Copyright (c) 2009 Progress Software, Inc. 003 * Copyright (c) 2004, 2006 IBM Corporation and others. 004 * 005 * All rights reserved. This program and the accompanying materials 006 * are made available under the terms of the Eclipse Public License v1.0 007 * which accompanies this distribution, and is available at 008 * http://www.eclipse.org/legal/epl-v10.html 009 *******************************************************************************/ 010 package org.fusesource.hawtjni.runtime; 011 012 import java.io.PrintStream; 013 import java.util.ArrayList; 014 import java.util.Arrays; 015 import java.util.Collection; 016 import java.util.Collections; 017 import java.util.HashMap; 018 import java.util.Map.Entry; 019 020 /** 021 * Instructions on how to use the NativeStats tool with a standalone SWT 022 * example: 023 * <ol> 024 * <li> Compile the native libraries defining the NATIVE_STATS flag.</li> 025 * <li> Add the following code around the sections of 026 * interest to dump the native calls done in that section. 027 * <code><pre> 028 * StatsInterface si = MyFooStatsInterface.INSTANCE; 029 * NativeStats stats = new NativeStats(si); 030 * ... // your code 031 * stats.diff().dump(System.out); 032 * </pre></code> 033 * </li> 034 * <li> Or add the following code at a given point to dump a snapshot of 035 * the native calls done until that point. 036 * <code><pre> 037 * stats.snapshot().dump(System.out); 038 * </pre></code> 039 * </li> 040 * </ol> 041 * 042 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 043 */ 044 public class NativeStats { 045 046 public interface StatsInterface { 047 String getNativeClass(); 048 int functionCount(); 049 String functionName(int ordinal); 050 int functionCounter(int ordinal); 051 } 052 053 public static class NativeFunction implements Comparable<NativeFunction> { 054 private final int ordinal; 055 private final String name; 056 private int counter; 057 058 public NativeFunction(int ordinal, String name, int callCount) { 059 this.ordinal = ordinal; 060 this.name = name; 061 this.counter = callCount; 062 } 063 void subtract(NativeFunction func) { 064 this.counter -= func.counter; 065 } 066 067 public int getCounter() { 068 return counter; 069 } 070 public void setCounter(int counter) { 071 this.counter = counter; 072 } 073 074 public String getName() { 075 return name; 076 } 077 078 public int getOrdinal() { 079 return ordinal; 080 } 081 082 public int compareTo(NativeFunction func) { 083 return func.counter - counter; 084 } 085 086 public void reset() { 087 counter=0; 088 } 089 090 public NativeFunction copy() { 091 return new NativeFunction(ordinal, name, counter); 092 } 093 } 094 095 private final HashMap<StatsInterface, ArrayList<NativeFunction>> snapshot; 096 097 public NativeStats(StatsInterface... classes) { 098 this(Arrays.asList(classes)); 099 } 100 101 public NativeStats(Collection<StatsInterface> classes) { 102 this(snapshot(classes)); 103 } 104 105 private NativeStats(HashMap<StatsInterface, ArrayList<NativeFunction>> snapshot) { 106 this.snapshot = snapshot; 107 } 108 109 public void reset() { 110 for (ArrayList<NativeFunction> functions : snapshot.values()) { 111 for (NativeFunction function : functions) { 112 function.reset(); 113 } 114 } 115 } 116 117 public void update() { 118 for (Entry<StatsInterface, ArrayList<NativeFunction>> entry : snapshot.entrySet()) { 119 StatsInterface si = entry.getKey(); 120 for (NativeFunction function : entry.getValue()) { 121 function.setCounter( si.functionCounter(function.getOrdinal()) ); 122 } 123 } 124 } 125 126 public NativeStats snapshot() { 127 NativeStats copy = copy(); 128 copy.update(); 129 return copy; 130 } 131 132 public NativeStats copy() { 133 HashMap<StatsInterface, ArrayList<NativeFunction>> rc = new HashMap<StatsInterface, ArrayList<NativeFunction>>(snapshot.size()*2); 134 for (Entry<StatsInterface, ArrayList<NativeFunction>> entry : snapshot.entrySet()) { 135 ArrayList<NativeFunction> list = new ArrayList<NativeFunction>(entry.getValue().size()); 136 for (NativeFunction function : entry.getValue()) { 137 list.add(function.copy()); 138 } 139 rc.put(entry.getKey(), list); 140 } 141 return new NativeStats(rc); 142 } 143 144 public NativeStats diff() { 145 HashMap<StatsInterface, ArrayList<NativeFunction>> rc = new HashMap<StatsInterface, ArrayList<NativeFunction>>(snapshot.size()*2); 146 for (Entry<StatsInterface, ArrayList<NativeFunction>> entry : snapshot.entrySet()) { 147 StatsInterface si = entry.getKey(); 148 ArrayList<NativeFunction> list = new ArrayList<NativeFunction>(entry.getValue().size()); 149 for (NativeFunction original : entry.getValue()) { 150 NativeFunction copy = original.copy(); 151 copy.setCounter( si.functionCounter(copy.getOrdinal()) ); 152 copy.subtract(original); 153 list.add(copy); 154 } 155 rc.put(si, list); 156 } 157 return new NativeStats(rc); 158 } 159 160 /** 161 * Dumps the stats to the print stream in a JSON format. 162 * @param ps 163 */ 164 public void dump(PrintStream ps) { 165 boolean firstSI=true; 166 for (Entry<StatsInterface, ArrayList<NativeFunction>> entry : snapshot.entrySet()) { 167 StatsInterface si = entry.getKey(); 168 ArrayList<NativeFunction> funcs = entry.getValue(); 169 170 int total = 0; 171 for (NativeFunction func : funcs) { 172 total += func.getCounter(); 173 } 174 175 if( !firstSI ) { 176 ps.print(", "); 177 } 178 firstSI=false; 179 ps.print("["); 180 if( total>0 ) { 181 ps.println("{ "); 182 ps.println(" \"class\": \""+si.getNativeClass()+"\","); 183 ps.println(" \"total\": "+total+", "); 184 ps.print(" \"functions\": {"); 185 boolean firstFunc=true; 186 for (NativeFunction func : funcs) { 187 if (func.getCounter() > 0) { 188 if( !firstFunc ) { 189 ps.print(","); 190 } 191 firstFunc=false; 192 ps.println(); 193 ps.print(" \""+func.getName()+"\": "+func.getCounter()); 194 } 195 } 196 ps.println(); 197 ps.println(" }"); 198 ps.print("}"); 199 } 200 ps.print("]"); 201 } 202 } 203 204 static private HashMap<StatsInterface, ArrayList<NativeFunction>> snapshot(Collection<StatsInterface> classes) { 205 HashMap<StatsInterface, ArrayList<NativeFunction>> rc = new HashMap<StatsInterface, ArrayList<NativeFunction>>(); 206 for (StatsInterface sc : classes) { 207 int count = sc.functionCount(); 208 ArrayList<NativeFunction> functions = new ArrayList<NativeFunction>(count); 209 for (int i = 0; i < count; i++) { 210 String name = (String) sc.functionName(i); 211 functions.add(new NativeFunction(i, name, 0)); 212 } 213 Collections.sort(functions); 214 rc.put(sc, functions); 215 } 216 return rc; 217 } 218 219 220 }