Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

move the bw plugin back into boomerang.js

  • Loading branch information...
commit 32b615369a94124c763481a0901d31c844688dc8 1 parent 6a47a60
Philip Tellis authored February 20, 2011

Showing 2 changed files with 432 additions and 437 deletions. Show diff stats Hide diff stats

  1. 432  boomerang.js
  2. 437  bw.js
432  boomerang.js
@@ -722,5 +722,437 @@ BOOMR.plugins.RT = {
722 722
 // End of RT plugin
723 723
 
724 724
 
  725
+// This is the Bandwidth & Latency plugin abbreviated to BW
  726
+// the parameter is the window
  727
+(function(w) {
  728
+
  729
+BOOMR = BOOMR || {};
  730
+BOOMR.plugins = BOOMR.plugins || {};
  731
+
  732
+// We choose image sizes so that we can narrow down on a bandwidth range as
  733
+// soon as possible the sizes chosen correspond to bandwidth values of
  734
+// 14-64kbps, 64-256kbps, 256-1024kbps, 1-2Mbps, 2-8Mbps, 8-30Mbps & 30Mbps+
  735
+// Anything below 14kbps will probably timeout before the test completes
  736
+// Anything over 60Mbps will probably be unreliable since latency will make up
  737
+// the largest part of download time. If you want to extend this further to
  738
+// cover 100Mbps & 1Gbps networks, use image sizes of 19,200,000 & 153,600,000
  739
+// bytes respectively
  740
+// See https://spreadsheets.google.com/ccc?key=0AplxPyCzmQi6dDRBN2JEd190N1hhV1N5cHQtUVdBMUE&hl=en_GB
  741
+// for a spreadsheet with the details
  742
+var images=[
  743
+	{ name: "image-0.png", size: 11483, timeout: 1400 }, 
  744
+	{ name: "image-1.png", size: 40658, timeout: 1200 }, 
  745
+	{ name: "image-2.png", size: 164897, timeout: 1300 }, 
  746
+	{ name: "image-3.png", size: 381756, timeout: 1500 }, 
  747
+	{ name: "image-4.png", size: 1234664, timeout: 1200 }, 
  748
+	{ name: "image-5.png", size: 4509613, timeout: 1200 }, 
  749
+	{ name: "image-6.png", size: 9084559, timeout: 1200 }
  750
+], limage = { name: "image-l.gif", size: 35, timeout: 1000 };
  751
+
  752
+// private object
  753
+var impl = {
  754
+	// properties
  755
+	base_url: 'images/',
  756
+	timeout: 15000,
  757
+	user_ip: '',
  758
+	cookie_exp: 7*86400,
  759
+	cookie: 'BA',
  760
+
  761
+	latency_runs: 10,
  762
+	nruns: 4,
  763
+
  764
+	// results
  765
+	latency: null,
  766
+	bw: null,
  767
+
  768
+	// state
  769
+	aborted: false,
  770
+	running: false,
  771
+
  772
+	complete: false,
  773
+
  774
+	// methods
  775
+
  776
+	// numeric comparator.  Returns negative number if a < b, positive if a > b and 0 if they're equal
  777
+	// used to sort an array numerically
  778
+	ncmp: function(a, b) { return (a-b); },
  779
+	
  780
+	// Calculate the interquartile range of an array of data points
  781
+	iqr: function(a)
  782
+	{
  783
+		var l = a.length-1, q1, q3, fw, b = [], i;
  784
+
  785
+		q1 = (a[Math.floor(l*0.25)] + a[Math.ceil(l*0.25)])/2;
  786
+		q3 = (a[Math.floor(l*0.75)] + a[Math.ceil(l*0.75)])/2;
  787
+	
  788
+		fw = (q3-q1)*1.5;
  789
+	
  790
+		l++;
  791
+	
  792
+		for(i=0; i<l && a[i] < q3+fw; i++) {
  793
+			if(a[i] > q1-fw) {
  794
+				b.push(a[i]);
  795
+			}
  796
+		}
  797
+	
  798
+		return b;
  799
+	},
  800
+	
  801
+	calc_latency: function(latencies)
  802
+	{
  803
+		var	i, n,
  804
+			sum=0, sumsq=0,
  805
+			amean, median,
  806
+			std_dev, std_err,
  807
+			lat_filtered;
  808
+	
  809
+		// We first do IQR filtering and use the resulting data set
  810
+		// for all calculations
  811
+		lat_filtered = this.iqr(latencies.sort(this.ncmp));
  812
+		n = lat_filtered.length;
  813
+	
  814
+		BOOMR.debug(lat_filtered, "bw");
  815
+	
  816
+		// First we get the arithmetic mean, standard deviation and standard error
  817
+		// We ignore the first since it paid the price of DNS lookup, TCP connect
  818
+		// and slow start
  819
+		for(i=1; i<n; i++) {
  820
+			sum += lat_filtered[i];
  821
+			sumsq += lat_filtered[i] * lat_filtered[i];
  822
+		}
  823
+	
  824
+		n--;	// Since we started the loop with 1 and not 0
  825
+	
  826
+		amean = Math.round(sum / n);
  827
+	
  828
+		std_dev = Math.sqrt( sumsq/n - sum*sum/(n*n));
  829
+	
  830
+		// See http://en.wikipedia.org/wiki/1.96 and http://en.wikipedia.org/wiki/Standard_error_%28statistics%29
  831
+		std_err = (1.96 * std_dev/Math.sqrt(n)).toFixed(2);
  832
+	
  833
+		std_dev = std_dev.toFixed(2);
  834
+	
  835
+	
  836
+		n = lat_filtered.length-1;
  837
+	
  838
+		median = Math.round(
  839
+				(lat_filtered[Math.floor(n/2)] + lat_filtered[Math.ceil(n/2)]) / 2
  840
+			);
  841
+	
  842
+		return { mean: amean, median: median, stddev: std_dev, stderr: std_err };
  843
+	},
  844
+	
  845
+	calc_bw: function(latencies, size)
  846
+	{
  847
+		var	i, n=0,
  848
+			bandwidths=[], bandwidths_corrected=[],
  849
+			sum=0, sumsq=0, sum_corrected=0, sumsq_corrected=0,
  850
+			amean, std_dev, std_err, median,
  851
+			amean_corrected, std_dev_corrected, std_err_corrected, median_corrected,
  852
+			bw, bw_c;
  853
+	
  854
+		for(i=0; i<latencies.length; i++) {
  855
+			// multiply by 1000 since t is in milliseconds and not seconds
  856
+			bw = size*1000/latencies[i];
  857
+			bandwidths.push(bw);
  858
+	
  859
+			bw_c = size*1000/(latencies[i] - this.latency.mean);
  860
+			bandwidths_corrected.push(bw_c);
  861
+		}
  862
+	
  863
+		BOOMR.debug('got ' + i + ' readings', "bw");
  864
+	
  865
+		BOOMR.debug('bandwidths: ' + bandwidths, "bw");
  866
+		BOOMR.debug('corrected: ' + bandwidths_corrected, "bw");
  867
+	
  868
+		// First do IQR filtering since we use the median here
  869
+		// and should use the stddev after filtering.
  870
+		if(bandwidths.length > 3) {
  871
+			bandwidths = this.iqr(bandwidths.sort(this.ncmp));
  872
+			bandwidths_corrected = this.iqr(bandwidths_corrected.sort(this.ncmp));
  873
+		} else {
  874
+			bandwidths = bandwidths.sort(this.ncmp);
  875
+			bandwidths_corrected = bandwidths_corrected.sort(this.ncmp);
  876
+		}
  877
+	
  878
+		BOOMR.debug('after iqr: ' + bandwidths, "bw");
  879
+		BOOMR.debug('corrected: ' + bandwidths_corrected, "bw");
  880
+	
  881
+		// Now get the mean & median.
  882
+		// Also get corrected values that eliminate latency
  883
+		n = Math.max(bandwidths.length, bandwidths_corrected.length);
  884
+		for(i=0; i<n; i++) {
  885
+			if(i<bandwidths.length) {
  886
+				sum += bandwidths[i];
  887
+				sumsq += Math.pow(bandwidths[i], 2);
  888
+			}
  889
+			if(i<bandwidths_corrected.length) {
  890
+				sum_corrected += bandwidths_corrected[i];
  891
+				sumsq_corrected += Math.pow(bandwidths_corrected[i], 2);
  892
+			}
  893
+		}
  894
+	
  895
+		n = bandwidths.length;
  896
+		amean = Math.round(sum/n);
  897
+		std_dev = Math.sqrt(sumsq/n - Math.pow(sum/n, 2));
  898
+		std_err = Math.round(1.96 * std_dev/Math.sqrt(n));
  899
+		std_dev = Math.round(std_dev);
  900
+	
  901
+		n = bandwidths.length-1;
  902
+		median = Math.round(
  903
+				(bandwidths[Math.floor(n/2)] + bandwidths[Math.ceil(n/2)]) / 2
  904
+			);
  905
+	
  906
+		n = bandwidths_corrected.length;
  907
+		amean_corrected = Math.round(sum_corrected/n);
  908
+		std_dev_corrected = Math.sqrt(sumsq_corrected/n - Math.pow(sum_corrected/n, 2));
  909
+		std_err_corrected = (1.96 * std_dev_corrected/Math.sqrt(n)).toFixed(2);
  910
+		std_dev_corrected = std_dev_corrected.toFixed(2);
  911
+	
  912
+		n = bandwidths_corrected.length-1;
  913
+		median_corrected = Math.round(
  914
+					(
  915
+						bandwidths_corrected[Math.floor(n/2)]
  916
+						+ bandwidths_corrected[Math.ceil(n/2)]
  917
+					) / 2
  918
+				);
  919
+	
  920
+		BOOMR.debug('amean: ' + amean + ', median: ' + median, "bw");
  921
+		BOOMR.debug('corrected amean: ' + amean_corrected + ', '
  922
+				+ 'median: ' + median_corrected, "bw");
  923
+	
  924
+		return {
  925
+			mean: amean,
  926
+			stddev: std_dev,
  927
+			stderr: std_err,
  928
+			median: median,
  929
+			mean_corrected: amean_corrected,
  930
+			stddev_corrected: std_dev_corrected,
  931
+			stderr_corrected: std_err_corrected,
  932
+			median_corrected: median_corrected
  933
+		};
  934
+	},
  935
+	
  936
+	finish: function()
  937
+	{
  938
+		var	o = {
  939
+				bw:		this.bw.median_corrected,
  940
+				bw_err:		parseFloat(this.bw.stderr_corrected, 10),
  941
+				lat:		this.latency.mean,
  942
+				lat_err:	parseFloat(this.latency.stderr, 10),
  943
+				bw_time:	Math.round(new Date().getTime()/1000)
  944
+			};
  945
+	
  946
+		BOOMR.addVar(o);
  947
+	
  948
+		// If we have an IP address we can make the BA cookie persistent for a while
  949
+		// because we'll recalculate it if necessary (when the user's IP changes).
  950
+		if(!isNaN(o.bw)) {
  951
+			BOOMR.utils.setCookie(this.cookie,
  952
+						{
  953
+							ba: Math.round(o.bw),
  954
+							be: o.bw_err,
  955
+							l:  o.lat,
  956
+							le: o.lat_err,
  957
+							ip: this.user_ip,
  958
+							t:  o.bw_time
  959
+						},
  960
+						(this.user_ip ? this.cookie_exp : 0),
  961
+						"/",
  962
+						null
  963
+				);
  964
+		}
  965
+	
  966
+		this.complete = true;
  967
+		BOOMR.sendBeacon();
  968
+		this.running = false;
  969
+	},
  970
+	
  971
+	test_latency: function(t, o)
  972
+	{
  973
+		if(!o) {
  974
+			o = { ctr: 0, state: [] };
  975
+		}
  976
+
  977
+		if(t && !t.timeout && t.success) {
  978
+			o.state.push(t.end - t.start);
  979
+		}
  980
+
  981
+		if(!this.aborted && o.ctr < this.latency_runs) {
  982
+			o.ctr++;
  983
+			BOOMR.utils.loadImage(
  984
+					this.base_url + limage.name,
  985
+					limage.timeout,
  986
+					this.test_latency, this, o
  987
+			);
  988
+		}
  989
+		else {
  990
+			this.latency = this.calc_latency(o.state);
  991
+			this.iterate();
  992
+		}
  993
+	},
  994
+
  995
+	test_bandwidth: function(t, o)
  996
+	{
  997
+		if(!o) {
  998
+			o = { i: 0, state: [], ctr: 0 };
  999
+		}
  1000
+
  1001
+		if(t) {
  1002
+			// terminate on failure
  1003
+			if(t.success === false) {
  1004
+				BOOMR.warn("error fetching bandwidth image", "bw");
  1005
+				this.bw = this.calc_bw(o.state, images[o.i].size);
  1006
+				return;
  1007
+			}
  1008
+			// if not timed out, we go to the next image
  1009
+			if(o.ctr===0 && !t.timeout && o.i < images.length-1) {
  1010
+				o.i++;
  1011
+			}
  1012
+			// at this point it either timed out or we're at the last image
  1013
+			else {
  1014
+				o.state.push(t.end - t.start);
  1015
+				o.ctr++;
  1016
+			}
  1017
+		}
  1018
+
  1019
+		// first run through each image until the first that timesout
  1020
+		if(!this.aborted && o.ctr < this.nruns) {
  1021
+			BOOMR.utils.loadImage(
  1022
+					this.base_url + images[o.i].name,
  1023
+					images[o.i].timeout,
  1024
+					this.test_bandwidth, this, o,
  1025
+					false, true
  1026
+			);
  1027
+		}
  1028
+		else {
  1029
+			this.bw = this.calc_bw(o.state, images[o.i].size);
  1030
+			this.iterate();
  1031
+		}
  1032
+	},
  1033
+
  1034
+	iterate: function()
  1035
+	{
  1036
+		var which;
  1037
+
  1038
+		if(!this.iteration_state) {
  1039
+			this.iteration_state = arguments;
  1040
+		}
  1041
+
  1042
+		if(this.aborted) {
  1043
+			return false;
  1044
+		}
  1045
+	
  1046
+		if(this.iteration_state.length === 0) {
  1047
+			this.iteration_state = null;
  1048
+			return this.finish();
  1049
+		}
  1050
+
  1051
+		which = Array.prototype.shift.call(this.iteration_state);
  1052
+
  1053
+		this["test_" + which].call(this);
  1054
+	},
  1055
+
  1056
+	setVarsFromCookie: function(cookies) {
  1057
+		var ba = parseInt(cookies.ba, 10),
  1058
+		    bw_e = parseFloat(cookies.be, 10),
  1059
+		    lat = parseInt(cookies.l, 10) || 0,
  1060
+		    lat_e = parseFloat(cookies.le, 10) || 0,
  1061
+		    c_sn = cookies.ip.replace(/\.\d+$/, '0'),	// Note this is IPv4 only
  1062
+		    t = parseInt(cookies.t, 10),
  1063
+		    p_sn = this.user_ip.replace(/\.\d+$/, '0'),
  1064
+
  1065
+		// We use the subnet instead of the IP address because some people
  1066
+		// on DHCP with the same ISP may get different IPs on the same subnet
  1067
+		// every time they log in.  The back end should really be doing this
  1068
+
  1069
+		    t_now = Math.round((new Date().getTime())/1000);	// seconds
  1070
+
  1071
+		// If the subnet changes or the cookie is more than 7 days old,
  1072
+		// then we recheck the bandwidth, else we just use what's in the cookie
  1073
+		if(c_sn === p_sn && t >= t_now - this.cookie_exp) {
  1074
+			this.complete = true;
  1075
+			BOOMR.addVar({
  1076
+				'bw': ba,
  1077
+				'lat': lat,
  1078
+				'bw_err': bw_e,
  1079
+				'lat_err': lat_e
  1080
+			});
  1081
+
  1082
+			return true;
  1083
+		}
  1084
+
  1085
+		return false;
  1086
+	}
  1087
+
  1088
+};
  1089
+	
  1090
+BOOMR.plugins.BW = {
  1091
+	init: function(config) {
  1092
+		var cookies;
  1093
+
  1094
+		BOOMR.utils.pluginConfig(impl, config, "BW",
  1095
+						["base_url", "timeout", "nruns", "cookie", "cookie_exp"]);
  1096
+
  1097
+		if(config && config.user_ip) {
  1098
+			impl.user_ip = config.user_ip;
  1099
+		}
  1100
+
  1101
+		impl.latency = null;
  1102
+		impl.bw = null;
  1103
+		impl.complete = false;
  1104
+		impl.aborted = false;
  1105
+
  1106
+		BOOMR.removeVar('ba', 'ba_err', 'lat', 'lat_err');
  1107
+
  1108
+		cookies = BOOMR.utils.getSubCookies(BOOMR.utils.getCookie(impl.cookie));
  1109
+
  1110
+		if(!cookies || !cookies.ba || !impl.setVarsFromCookie(cookies)) {
  1111
+			BOOMR.subscribe("page_ready", this.run, null, this);
  1112
+		}
  1113
+
  1114
+		return this;
  1115
+	},
  1116
+
  1117
+	run: function() {
  1118
+		if(impl.running || impl.complete) {
  1119
+			return this;
  1120
+		}
  1121
+
  1122
+		if(w.location.protocol === 'https:') {
  1123
+			// we don't run the test for https because SSL stuff will mess up b/w
  1124
+			// calculations we could run the test itself over HTTP, but then IE
  1125
+			// will complain about insecure resources, so the best is to just bail
  1126
+			// and hope that the user gets the cookie from some other page
  1127
+
  1128
+			BOOMR.info("HTTPS detected, skipping bandwidth test", "bw");
  1129
+			impl.complete = true;
  1130
+			return this;
  1131
+		}
  1132
+
  1133
+		impl.running = true;
  1134
+
  1135
+		setTimeout(this.abort, impl.timeout);
  1136
+
  1137
+		impl.iterate('latency', 'bandwidth');
  1138
+
  1139
+		return this;
  1140
+	},
  1141
+
  1142
+	abort: function() {
  1143
+		if(impl.running) {
  1144
+			impl.aborted = true;
  1145
+		}
  1146
+
  1147
+		return this;
  1148
+	},
  1149
+
  1150
+	is_complete: function() { return impl.complete; }
  1151
+};
  1152
+
  1153
+}(window));
  1154
+// End of BW plugin
  1155
+
  1156
+
725 1157
 
726 1158
 /*jslint onevar: true, undef: true, newcap: true, nomen: true, bitwise: true, devel: true, browser: true, continue: true, maxerr: 50, indent: 4 */
437  bw.js
... ...
@@ -1,437 +0,0 @@
1  
-/**
2  
-\file bw.js
3  
-Plugin to measure network throughput and latency.
4  
-*/
5  
-
6  
-// This is the Bandwidth & Latency plugin abbreviated to BW
7  
-// the parameter is the window
8  
-(function(w) {
9  
-
10  
-BOOMR = BOOMR || {};
11  
-BOOMR.plugins = BOOMR.plugins || {};
12  
-
13  
-// We choose image sizes so that we can narrow down on a bandwidth range as
14  
-// soon as possible the sizes chosen correspond to bandwidth values of
15  
-// 14-64kbps, 64-256kbps, 256-1024kbps, 1-2Mbps, 2-8Mbps, 8-30Mbps & 30Mbps+
16  
-// Anything below 14kbps will probably timeout before the test completes
17  
-// Anything over 60Mbps will probably be unreliable since latency will make up
18  
-// the largest part of download time. If you want to extend this further to
19  
-// cover 100Mbps & 1Gbps networks, use image sizes of 19,200,000 & 153,600,000
20  
-// bytes respectively
21  
-// See https://spreadsheets.google.com/ccc?key=0AplxPyCzmQi6dDRBN2JEd190N1hhV1N5cHQtUVdBMUE&hl=en_GB
22  
-// for a spreadsheet with the details
23  
-var images=[
24  
-	{ name: "image-0.png", size: 11483, timeout: 1400 }, 
25  
-	{ name: "image-1.png", size: 40658, timeout: 1200 }, 
26  
-	{ name: "image-2.png", size: 164897, timeout: 1300 }, 
27  
-	{ name: "image-3.png", size: 381756, timeout: 1500 }, 
28  
-	{ name: "image-4.png", size: 1234664, timeout: 1200 }, 
29  
-	{ name: "image-5.png", size: 4509613, timeout: 1200 }, 
30  
-	{ name: "image-6.png", size: 9084559, timeout: 1200 }
31  
-], limage = { name: "image-l.gif", size: 35, timeout: 1000 };
32  
-
33  
-// private object
34  
-var impl = {
35  
-	// properties
36  
-	base_url: 'images/',
37  
-	timeout: 15000,
38  
-	user_ip: '',
39  
-	cookie_exp: 7*86400,
40  
-	cookie: 'BA',
41  
-
42  
-	latency_runs: 10,
43  
-	nruns: 4,
44  
-
45  
-	// results
46  
-	latency: null,
47  
-	bw: null,
48  
-
49  
-	// state
50  
-	aborted: false,
51  
-	running: false,
52  
-
53  
-	complete: false,
54  
-
55  
-	// methods
56  
-
57  
-	// numeric comparator.  Returns negative number if a < b, positive if a > b and 0 if they're equal
58  
-	// used to sort an array numerically
59  
-	ncmp: function(a, b) { return (a-b); },
60  
-	
61  
-	// Calculate the interquartile range of an array of data points
62  
-	iqr: function(a)
63  
-	{
64  
-		var l = a.length-1, q1, q3, fw, b = [], i;
65  
-
66  
-		q1 = (a[Math.floor(l*0.25)] + a[Math.ceil(l*0.25)])/2;
67  
-		q3 = (a[Math.floor(l*0.75)] + a[Math.ceil(l*0.75)])/2;
68  
-	
69  
-		fw = (q3-q1)*1.5;
70  
-	
71  
-		l++;
72  
-	
73  
-		for(i=0; i<l && a[i] < q3+fw; i++) {
74  
-			if(a[i] > q1-fw) {
75  
-				b.push(a[i]);
76  
-			}
77  
-		}
78  
-	
79  
-		return b;
80  
-	},
81  
-	
82  
-	calc_latency: function(latencies)
83  
-	{
84  
-		var	i, n,
85  
-			sum=0, sumsq=0,
86  
-			amean, median,
87  
-			std_dev, std_err,
88  
-			lat_filtered;
89  
-	
90  
-		// We first do IQR filtering and use the resulting data set
91  
-		// for all calculations
92  
-		lat_filtered = this.iqr(latencies.sort(this.ncmp));
93  
-		n = lat_filtered.length;
94  
-	
95  
-		BOOMR.debug(lat_filtered, "bw");
96  
-	
97  
-		// First we get the arithmetic mean, standard deviation and standard error
98  
-		// We ignore the first since it paid the price of DNS lookup, TCP connect
99  
-		// and slow start
100  
-		for(i=1; i<n; i++) {
101  
-			sum += lat_filtered[i];
102  
-			sumsq += lat_filtered[i] * lat_filtered[i];
103  
-		}
104  
-	
105  
-		n--;	// Since we started the loop with 1 and not 0
106  
-	
107  
-		amean = Math.round(sum / n);
108  
-	
109  
-		std_dev = Math.sqrt( sumsq/n - sum*sum/(n*n));
110  
-	
111  
-		// See http://en.wikipedia.org/wiki/1.96 and http://en.wikipedia.org/wiki/Standard_error_%28statistics%29
112  
-		std_err = (1.96 * std_dev/Math.sqrt(n)).toFixed(2);
113  
-	
114  
-		std_dev = std_dev.toFixed(2);
115  
-	
116  
-	
117  
-		n = lat_filtered.length-1;
118  
-	
119  
-		median = Math.round(
120  
-				(lat_filtered[Math.floor(n/2)] + lat_filtered[Math.ceil(n/2)]) / 2
121  
-			);
122  
-	
123  
-		return { mean: amean, median: median, stddev: std_dev, stderr: std_err };
124  
-	},
125  
-	
126  
-	calc_bw: function(latencies, size)
127  
-	{
128  
-		var	i, n=0,
129  
-			bandwidths=[], bandwidths_corrected=[],
130  
-			sum=0, sumsq=0, sum_corrected=0, sumsq_corrected=0,
131  
-			amean, std_dev, std_err, median,
132  
-			amean_corrected, std_dev_corrected, std_err_corrected, median_corrected,
133  
-			bw, bw_c;
134  
-	
135  
-		for(i=0; i<latencies.length; i++) {
136  
-			// multiply by 1000 since t is in milliseconds and not seconds
137  
-			bw = size*1000/latencies[i];
138  
-			bandwidths.push(bw);
139  
-	
140  
-			bw_c = size*1000/(latencies[i] - this.latency.mean);
141  
-			bandwidths_corrected.push(bw_c);
142  
-		}
143  
-	
144  
-		BOOMR.debug('got ' + i + ' readings', "bw");
145  
-	
146  
-		BOOMR.debug('bandwidths: ' + bandwidths, "bw");
147  
-		BOOMR.debug('corrected: ' + bandwidths_corrected, "bw");
148  
-	
149  
-		// First do IQR filtering since we use the median here
150  
-		// and should use the stddev after filtering.
151  
-		if(bandwidths.length > 3) {
152  
-			bandwidths = this.iqr(bandwidths.sort(this.ncmp));
153  
-			bandwidths_corrected = this.iqr(bandwidths_corrected.sort(this.ncmp));
154  
-		} else {
155  
-			bandwidths = bandwidths.sort(this.ncmp);
156  
-			bandwidths_corrected = bandwidths_corrected.sort(this.ncmp);
157  
-		}
158  
-	
159  
-		BOOMR.debug('after iqr: ' + bandwidths, "bw");
160  
-		BOOMR.debug('corrected: ' + bandwidths_corrected, "bw");
161  
-	
162  
-		// Now get the mean & median.
163  
-		// Also get corrected values that eliminate latency
164  
-		n = Math.max(bandwidths.length, bandwidths_corrected.length);
165  
-		for(i=0; i<n; i++) {
166  
-			if(i<bandwidths.length) {
167  
-				sum += bandwidths[i];
168  
-				sumsq += Math.pow(bandwidths[i], 2);
169  
-			}
170  
-			if(i<bandwidths_corrected.length) {
171  
-				sum_corrected += bandwidths_corrected[i];
172  
-				sumsq_corrected += Math.pow(bandwidths_corrected[i], 2);
173  
-			}
174  
-		}
175  
-	
176  
-		n = bandwidths.length;
177  
-		amean = Math.round(sum/n);
178  
-		std_dev = Math.sqrt(sumsq/n - Math.pow(sum/n, 2));
179  
-		std_err = Math.round(1.96 * std_dev/Math.sqrt(n));
180  
-		std_dev = Math.round(std_dev);
181  
-	
182  
-		n = bandwidths.length-1;
183  
-		median = Math.round(
184  
-				(bandwidths[Math.floor(n/2)] + bandwidths[Math.ceil(n/2)]) / 2
185  
-			);
186  
-	
187  
-		n = bandwidths_corrected.length;
188  
-		amean_corrected = Math.round(sum_corrected/n);
189  
-		std_dev_corrected = Math.sqrt(sumsq_corrected/n - Math.pow(sum_corrected/n, 2));
190  
-		std_err_corrected = (1.96 * std_dev_corrected/Math.sqrt(n)).toFixed(2);
191  
-		std_dev_corrected = std_dev_corrected.toFixed(2);
192  
-	
193  
-		n = bandwidths_corrected.length-1;
194  
-		median_corrected = Math.round(
195  
-					(
196  
-						bandwidths_corrected[Math.floor(n/2)]
197  
-						+ bandwidths_corrected[Math.ceil(n/2)]
198  
-					) / 2
199  
-				);
200  
-	
201  
-		BOOMR.debug('amean: ' + amean + ', median: ' + median, "bw");
202  
-		BOOMR.debug('corrected amean: ' + amean_corrected + ', '
203  
-				+ 'median: ' + median_corrected, "bw");
204  
-	
205  
-		return {
206  
-			mean: amean,
207  
-			stddev: std_dev,
208  
-			stderr: std_err,
209  
-			median: median,
210  
-			mean_corrected: amean_corrected,
211  
-			stddev_corrected: std_dev_corrected,
212  
-			stderr_corrected: std_err_corrected,
213  
-			median_corrected: median_corrected
214  
-		};
215  
-	},
216  
-	
217  
-	finish: function()
218  
-	{
219  
-		var	o = {
220  
-				bw:		this.bw.median_corrected,
221  
-				bw_err:		parseFloat(this.bw.stderr_corrected, 10),
222  
-				lat:		this.latency.mean,
223  
-				lat_err:	parseFloat(this.latency.stderr, 10),
224  
-				bw_time:	Math.round(new Date().getTime()/1000)
225  
-			};
226  
-	
227  
-		BOOMR.addVar(o);
228  
-	
229  
-		// If we have an IP address we can make the BA cookie persistent for a while
230  
-		// because we'll recalculate it if necessary (when the user's IP changes).
231  
-		if(!isNaN(o.bw)) {
232  
-			BOOMR.utils.setCookie(this.cookie,
233  
-						{
234  
-							ba: Math.round(o.bw),
235  
-							be: o.bw_err,
236  
-							l:  o.lat,
237  
-							le: o.lat_err,
238  
-							ip: this.user_ip,
239  
-							t:  o.bw_time
240  
-						},
241  
-						(this.user_ip ? this.cookie_exp : 0),
242  
-						"/",
243  
-						null
244  
-				);
245  
-		}
246  
-	
247  
-		this.complete = true;
248  
-		BOOMR.sendBeacon();
249  
-		this.running = false;
250  
-	},
251  
-	
252  
-	test_latency: function(t, o)
253  
-	{
254  
-		if(!o) {
255  
-			o = { ctr: 0, state: [] };
256  
-		}
257  
-
258  
-		if(t && !t.timeout && t.success) {
259  
-			o.state.push(t.end - t.start);
260  
-		}
261  
-
262  
-		if(!this.aborted && o.ctr < this.latency_runs) {
263  
-			o.ctr++;
264  
-			BOOMR.utils.loadImage(
265  
-					this.base_url + limage.name,
266  
-					limage.timeout,
267  
-					this.test_latency, this, o
268  
-			);
269  
-		}
270  
-		else {
271  
-			this.latency = this.calc_latency(o.state);
272  
-			this.iterate();
273  
-		}
274  
-	},
275  
-
276  
-	test_bandwidth: function(t, o)
277  
-	{
278  
-		if(!o) {
279  
-			o = { i: 0, state: [], ctr: 0 };
280  
-		}
281  
-
282  
-		if(t) {
283  
-			// terminate on failure
284  
-			if(t.success === false) {
285  
-				BOOMR.warn("error fetching bandwidth image", "bw");
286  
-				this.bw = this.calc_bw(o.state, images[o.i].size);
287  
-				return;
288  
-			}
289  
-			// if not timed out, we go to the next image
290  
-			if(o.ctr===0 && !t.timeout && o.i < images.length-1) {
291  
-				o.i++;
292  
-			}
293  
-			// at this point it either timed out or we're at the last image
294  
-			else {
295  
-				o.state.push(t.end - t.start);
296  
-				o.ctr++;
297  
-			}
298  
-		}
299  
-
300  
-		// first run through each image until the first that timesout
301  
-		if(!this.aborted && o.ctr < this.nruns) {
302  
-			BOOMR.utils.loadImage(
303  
-					this.base_url + images[o.i].name,
304  
-					images[o.i].timeout,
305  
-					this.test_bandwidth, this, o,
306  
-					false, true
307  
-			);
308  
-		}
309  
-		else {
310  
-			this.bw = this.calc_bw(o.state, images[o.i].size);
311  
-			this.iterate();
312  
-		}
313  
-	},
314  
-
315  
-	iterate: function()
316  
-	{
317  
-		var which;
318  
-
319  
-		if(!this.iteration_state) {
320  
-			this.iteration_state = arguments;
321  
-		}
322  
-
323  
-		if(this.aborted) {
324  
-			return false;
325  
-		}
326  
-	
327  
-		if(this.iteration_state.length === 0) {
328  
-			this.iteration_state = null;
329  
-			return this.finish();
330  
-		}
331  
-
332  
-		which = Array.prototype.shift.call(this.iteration_state);
333  
-
334  
-		this["test_" + which].call(this);
335  
-	},
336  
-
337  
-	setVarsFromCookie: function(cookies) {
338  
-		var ba = parseInt(cookies.ba, 10),
339  
-		    bw_e = parseFloat(cookies.be, 10),
340  
-		    lat = parseInt(cookies.l, 10) || 0,
341  
-		    lat_e = parseFloat(cookies.le, 10) || 0,
342  
-		    c_sn = cookies.ip.replace(/\.\d+$/, '0'),	// Note this is IPv4 only
343  
-		    t = parseInt(cookies.t, 10),
344  
-		    p_sn = this.user_ip.replace(/\.\d+$/, '0'),
345  
-
346  
-		// We use the subnet instead of the IP address because some people
347  
-		// on DHCP with the same ISP may get different IPs on the same subnet
348  
-		// every time they log in.  The back end should really be doing this
349  
-
350  
-		    t_now = Math.round((new Date().getTime())/1000);	// seconds
351  
-
352  
-		// If the subnet changes or the cookie is more than 7 days old,
353  
-		// then we recheck the bandwidth, else we just use what's in the cookie
354  
-		if(c_sn === p_sn && t >= t_now - this.cookie_exp) {
355  
-			this.complete = true;
356  
-			BOOMR.addVar({
357  
-				'bw': ba,
358  
-				'lat': lat,
359  
-				'bw_err': bw_e,
360  
-				'lat_err': lat_e
361  
-			});
362  
-
363  
-			return true;
364  
-		}
365  
-
366  
-		return false;
367  
-	}
368  
-
369  
-};
370  
-	
371  
-BOOMR.plugins.BW = {
372  
-	init: function(config) {
373  
-		var cookies;
374  
-
375  
-		BOOMR.utils.pluginConfig(impl, config, "BW",
376  
-						["base_url", "timeout", "nruns", "cookie", "cookie_exp"]);
377  
-
378  
-		if(config && config.user_ip) {
379  
-			impl.user_ip = config.user_ip;
380  
-		}
381  
-
382  
-		impl.latency = null;
383  
-		impl.bw = null;
384  
-		impl.complete = false;
385  
-		impl.aborted = false;
386  
-
387  
-		BOOMR.removeVar('ba', 'ba_err', 'lat', 'lat_err');
388  
-
389  
-		cookies = BOOMR.utils.getSubCookies(BOOMR.utils.getCookie(impl.cookie));
390  
-
391  
-		if(!cookies || !cookies.ba || !impl.setVarsFromCookie(cookies)) {
392  
-			BOOMR.subscribe("page_ready", this.run, null, this);
393  
-		}
394  
-
395  
-		return this;
396  
-	},
397  
-
398  
-	run: function() {
399  
-		if(impl.running || impl.complete) {
400  
-			return this;
401  
-		}
402  
-
403  
-		if(w.location.protocol === 'https:') {
404  
-			// we don't run the test for https because SSL stuff will mess up b/w
405  
-			// calculations we could run the test itself over HTTP, but then IE
406  
-			// will complain about insecure resources, so the best is to just bail
407  
-			// and hope that the user gets the cookie from some other page
408  
-
409  
-			BOOMR.info("HTTPS detected, skipping bandwidth test", "bw");
410  
-			impl.complete = true;
411  
-			return this;
412  
-		}
413  
-
414  
-		impl.running = true;
415  
-
416  
-		setTimeout(this.abort, impl.timeout);
417  
-
418  
-		impl.iterate('latency', 'bandwidth');
419  
-
420  
-		return this;
421  
-	},
422  
-
423  
-	abort: function() {
424  
-		if(impl.running) {
425  
-			impl.aborted = true;
426  
-		}
427  
-
428  
-		return this;
429  
-	},
430  
-
431  
-	is_complete: function() { return impl.complete; }
432  
-};
433  
-
434  
-}(window));
435  
-// End of BW plugin
436  
-
437  
-

0 notes on commit 32b6153

Please sign in to comment.
Something went wrong with that request. Please try again.