|  | 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(); | 
|  | } | 
|  | } | 
|  | } |