Skip to content

Commit cd0ff71

Browse files
authored
Merge pull request #125 from Pradhyumna02/Downloads-Algorithm-Approach-1
Downloads algorithm approach 1
2 parents 3b33e4d + 110cacf commit cd0ff71

File tree

8 files changed

+4578
-25
lines changed

8 files changed

+4578
-25
lines changed

package-lock.json

Lines changed: 4286 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "speed-testjs",
3-
"version": "1.0.31",
3+
"version": "1.0.32-beta.0",
44
"description": "measure internet bandwidth",
55
"main": "index.js",
66
"author": "Maulan Byron",

public/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ <h1 class="logo"></h1>
8484
<script src="lib/uploadProbeTest.js"></script>
8585
<script src="lib/uploadHttpConcurrentProgress.js"></script>
8686
<script src="lib/statisticalCalculator.js"></script>
87+
<script src="lib/download/desktopTest/algoV1.js"></script>
88+
<script src="lib/utils.js"></script>
8789
<script src="uilib/echarts.min.js"></script>
8890
<script src="speed-testJS.js"></script>
8991
</body>
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* *
3+
* Copyright 2014 Comcast Cable Communications Management, LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
* /
17+
*/
18+
19+
(function() {
20+
'use strict';
21+
/**
22+
*
23+
* @param {*} urls - urls to run the download test.
24+
* @param {*} size - size required to run the test.
25+
* @param {*} threads - number of parallel http requests.
26+
* @param {*} duration - length of the test.
27+
* @param {*} intervalTimer - monitor interval to calculate download bandwidth.
28+
* @param {*} callbackProgress - progress event to track the test for every interval.
29+
* @param {*} callbackComplete - event that reports the end results.
30+
* @param {*} callbackError - event that reports the cause of any error.
31+
*/
32+
function algoV1(urls, size, threads, duration, intervalTimer,
33+
callbackProgress, callbackComplete, callbackError) {
34+
35+
this.urls = urls;
36+
this.size = size;
37+
this.threads = threads;
38+
this.duration = duration;
39+
this.intervalTimer = intervalTimer;
40+
this.callbackProgress = callbackProgress;
41+
this.callbackComplete = callbackComplete;
42+
this.callbackError = callbackError;
43+
}
44+
45+
algoV1.prototype.initiateTest = function() {
46+
this.activeTests = [];
47+
this.totalBytesTransferred = [];
48+
this.totalTime = [];
49+
this.prevBytesTransferred = [];
50+
this.prevTime = [];
51+
this.downloadResults = [];
52+
this.timedOutReqCount = 0;
53+
54+
// TODO items to be removed
55+
this.smaCount = 0;
56+
this.smaMean = 0;
57+
// Remove above items
58+
59+
this.reportUIValue = 4;
60+
this.desktopTest = true; // can be removed once this is the only algorithm we are using
61+
this.testId = null;
62+
63+
this.startTime = timer();
64+
this.startDownloadTest();
65+
this.intervalId = setInterval(this.monitor.bind(this), this.intervalTimer);
66+
}
67+
68+
69+
algoV1.prototype.startDownloadTest = function() {
70+
for (var i = 0; i < this.threads; i++) {
71+
this.testId = i;
72+
this.start();
73+
}
74+
}
75+
76+
algoV1.prototype.start = function() {
77+
this.createRequest();
78+
this.initializeBucketsForEachReq();
79+
}
80+
81+
algoV1.prototype.createRequest = function() {
82+
// Calling the xmlhttprequest to create the http connection.
83+
var request = new window.xmlHttpRequest('GET', this.urls[this.testId]+ this.size + '&r=' + Math.random(),
84+
this.duration, this.onTestComplete.bind(this), this.onTestProgress.bind(this),
85+
this.onTestAbort.bind(this), this.onTestTimeout.bind(this), this.onTestError.bind(this),
86+
null, this.desktopTest);
87+
request.start(0, this.testId);
88+
this.activeTests.push({
89+
xhr: request,
90+
});
91+
}
92+
93+
algoV1.prototype.initializeBucketsForEachReq = function() {
94+
// Setting timers and bytes download for each thread.
95+
this.totalBytesTransferred[this.testId] = 0;
96+
this.totalTime[this.testId] = 0;
97+
this.prevBytesTransferred[this.testId] = 0;
98+
this.prevTime[this.testId] = 0;
99+
}
100+
101+
algoV1.prototype.onTestComplete = function(event) {
102+
// FUTURE - Track the number of events get completed during the test
103+
// Once a request is finished/completed. We try to start a new request using the same Id,
104+
// maintaing the number of requests same all the time.
105+
this.testId = event.id;
106+
this.start();
107+
}
108+
109+
algoV1.prototype.onTestProgress = function(event) {
110+
this.totalBytesTransferred[event.id] += event.chunckLoaded;
111+
this.totalTime[event.id] = event.totalTime;
112+
}
113+
114+
algoV1.prototype.onTestAbort = function() {
115+
// TODO we can add get the bandwdith for last interval
116+
}
117+
118+
algoV1.prototype.onTestTimeout = function() {
119+
this.timedOutReqCount++;
120+
if (this.timedOutReqCount === this.threads) {
121+
this.stopTest();
122+
}
123+
}
124+
125+
algoV1.prototype.onTestError = function(event) {
126+
this.callbackError(event)
127+
}
128+
129+
algoV1.prototype.monitor = function() {
130+
if (testRunTime(this.startTime) > this.duration) {
131+
this.stopTest();
132+
return;
133+
}
134+
135+
this.calcIntervalSpeed();
136+
}
137+
138+
algoV1.prototype.calcIntervalSpeed = function() {
139+
this.curSpeed = 0
140+
for (var j = 0; j < this.threads; j++) {
141+
var bytesTransferred = this.totalBytesTransferred[j] - this.prevBytesTransferred[j];
142+
var time = this.totalTime[j] - this.prevTime[j];
143+
144+
if (bytesTransferred !== 0 || time !== 0) {
145+
var speed = calculateSpeedMbps(bytesTransferred, time);
146+
this.curSpeed += speed;
147+
this.prevBytesTransferred[j] = this.totalBytesTransferred[j];
148+
this.prevTime[j] = this.totalTime[j];
149+
}
150+
151+
}
152+
this.downloadResults.push(+this.curSpeed.toFixed(2));
153+
this.reportIntervalSpeed();
154+
}
155+
156+
algoV1.prototype.reportIntervalSpeed = function() {
157+
if (this.downloadResults.length < this.reportUIValue) {
158+
this.callbackProgress(this.curSpeed);
159+
return;
160+
}
161+
this.callbackProgress(simpleMovingAverage.call(this));
162+
}
163+
164+
algoV1.prototype.stopTest = function() {
165+
166+
if (this.intervalId) {
167+
clearInterval(this.intervalId);
168+
}
169+
170+
abortAllRequests.call(this);
171+
this.callbackComplete({
172+
"downloadSpeed": this.smaMean,
173+
"dataPoints": this.downloadResults
174+
});
175+
}
176+
177+
window.algoV1 = algoV1;
178+
179+
})();

public/lib/downloadHttpConcurrentProgress.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
this.clientCallbackTimeout = callbackTimeout;
5656
this.clientCallbackError = callbackError;
5757
//start time of test suite
58-
this._beginTime = Date.now();
58+
this._beginTime = timer();
5959
//boolean on whether test suite is running or not
6060
this._running = true;
6161
//array holding results
@@ -80,7 +80,7 @@
8080
*/
8181
downloadHttpConcurrentProgress.prototype.onTestError = function (result) {
8282
if (this._running) {
83-
if ((Date.now() - this._beginTime) > this.testLength) {
83+
if ((timer() - this._beginTime) > this.testLength) {
8484
this.endTest();
8585
}
8686
else{
@@ -105,7 +105,7 @@
105105
*/
106106
downloadHttpConcurrentProgress.prototype.onTestTimeout = function () {
107107
if(this._running) {
108-
if ((Date.now() - this._beginTime) > this.testLength) {
108+
if ((timer() - this._beginTime) > this.testLength) {
109109
this.endTest();
110110
}
111111

@@ -141,7 +141,7 @@
141141
return;
142142
}
143143
//check for end of test
144-
if ((Date.now() - this._beginTime) > this.testLength) {
144+
if ((timer() - this._beginTime) > this.testLength) {
145145
this.endTest();
146146
}
147147
this.totalBytes = this.totalBytes + result.loaded;
@@ -204,7 +204,7 @@
204204

205205
if (this.results.length > 0) {
206206
for (var i = 0; i < this.results.length; i++) {
207-
if (this.results[i].timeStamp > (Date.now() - this.monitorInterval)) {
207+
if (this.results[i].timeStamp > (timer() - this.monitorInterval)) {
208208
intervalBandwidth = intervalBandwidth + parseFloat(this.results[i].bandwidth);
209209
totalLoaded = totalLoaded + this.results[i].chunckLoaded;
210210
totalTime = totalTime + this.results[i].totalTime;
@@ -235,7 +235,7 @@
235235

236236
}
237237
//check for end of test
238-
if ((Date.now() - this._beginTime) > this.testLength) {
238+
if ((timer() - this._beginTime) > this.testLength) {
239239
this.endTest();
240240
}
241241

public/lib/utils.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function testRunTime(startTime) {
2+
return timer() - startTime;
3+
}
4+
5+
function timer() {
6+
return window.performance.now();
7+
}
8+
9+
function simpleMovingAverage() {
10+
this.smaCount++;
11+
const differential = (this.curSpeed - this.smaMean) / this.smaCount
12+
const newMean = this.smaMean + differential;
13+
this.smaMean = newMean;
14+
return this.smaMean;
15+
}
16+
17+
function calculateSpeedMbps(bytes, milliSeconds) {
18+
return bytes / (125 * milliSeconds);
19+
}
20+
21+
function abortAllRequests() {
22+
for (var i = 0; i < this.activeTests.length; i++) {
23+
if (typeof(this.activeTests[i] !== 'undefined')) {
24+
this.activeTests[i].xhr._request.abort();
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)