package kellegous.client; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; public class Dispatch implements EntryPoint { private static native Event createMockEvent() /*-{ return { type: "click" }; }-*/; private static double[] runTrial(int numberOfObservers, int numberOfIterations, int numberOfSamples) { final double[] results = new double[numberOfSamples]; final EventListener subject = Subject.create(numberOfObservers); final Event event = createMockEvent(); for (int j = 0; j < numberOfSamples; ++j) { final Duration d = new Duration(); for (int i = 0; i < numberOfIterations; ++i) { subject.onBrowserEvent(event); } results[j] = d.elapsedMillis(); } return results; } private static native void schedule(Command command) /*-{ $wnd.setTimeout(function() { command.@com.google.gwt.user.client.Command::execute()(); }, 0); }-*/; // t-distribution for p = 0.05 (used to compute 95% confidence intervals). // This table is based at df = 2. private final static double[] TDIST = new double[] { 4.3027, 3.1824, 2.7765, 2.5706, 2.4469, 2.3646, 2.3060, 2.2622, 2.2281, 2.2010, 2.1788, 2.1604, 2.1448, 2.1315, 2.1199, 2.1098, 2.1009, 2.0930, 2.0860, 2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, 2.0452, 2.0423, 2.0395, 2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, 2.0244, 2.0227, 2.0211, 2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, 2.0117, 2.0106, 2.0096, 2.0086, 2.0076, 2.0066, 2.0057, 2.0049, 2.0040, 2.0032, 2.0025, 2.0017, 2.0010, 2.0003, 1.9996, 1.9990, 1.9983, 1.9977, 1.9971, 1.9966, 1.9960, 1.9955, 1.9949, 1.9944, 1.9939, 1.9935, 1.9930, 1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905, 1.9901, 1.9897, 1.9893, 1.9890, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.9870, 1.9867, 1.9864, 1.9861, 1.9858, 1.9855, 1.9852, 1.9850, 1.9847, 1.9845, 1.9842, 1.9840}; private static double computeT(int df) { return TDIST[df - 2]; } private static double computeMean(double[] s) { double sum = 0.0; final int n = s.length; for (int i = 0; i < n; ++i) { sum += s[i]; } return sum / n; } private static double computeStandardError(double[] data, double mean) { final int n = data.length; double sum = 0.0; for (int i = 0; i < n; ++i) { final double d = data[i] - mean; sum += d * d; } return Math.sqrt(sum / n) / Math.sqrt(n); } private static class Stats { private final double mean, upper, lower; Stats(double[] data) { mean = computeMean(data); final double error = computeStandardError(data, mean); final double t = computeT(data.length - 1); upper = mean + t * error; lower = mean - t * error; } @Override public String toString() { return mean + ", " + lower + ", " + upper; } } public static class Runner { private int n; private final int max, numIterations, numSamples; private Stats[] results; Runner(int min, int max, int numIterations, int numSamples) { n = min; this.max = max; this.numIterations = numIterations; this.numSamples = numSamples; results = new Stats[max - min + 1]; } void finish() { final Document document = Document.get(); final DivElement root = document.createDivElement(); document.getBody().appendChild(root); for (int i = 0, n = results.length; i < n; ++i) { final DivElement div = document.createDivElement(); root.appendChild(div); div.setInnerText("" + results[i].toString()); } } void next() { schedule(new Command() { public void execute() { final double[] results = runTrial(n, numIterations, numSamples); Runner.this.results[n] = new Stats(results); if (++n <= max) { next(); } else { finish(); } } }); } void run() { next(); } } public void onModuleLoad() { // Don't run this in hosted mode. if (GWT.isScript()) { new Runner(0, 10, 10000, 20).run(); } } }