blob: 8b1db26f7749cdb927fd4ebb52d40a994a79b7a5 [file] [log] [blame]
Paul Greyson17f84472013-04-12 14:39:21 -07001var enableIPerfLog = false;
2
Paul Greysoneeb69962013-04-12 15:53:29 -07003function iperfLog(message, flow) {
Paul Greyson17f84472013-04-12 14:39:21 -07004 if (enableIPerfLog) {
Paul Greysoneeb69962013-04-12 15:53:29 -07005 console.log('flow: ' + flow.flowId + '===>' + message);
Paul Greyson17f84472013-04-12 14:39:21 -07006 }
7}
8
9function hasIPerf(flow) {
10 return flow && flow.iperfFetchTimeout;
11}
12
13function clearIPerf(flow) {
Paul Greysoneeb69962013-04-12 15:53:29 -070014 iperfLog('clearing iperf interval for: ' + flow.flowId, flow);
Paul Greyson17f84472013-04-12 14:39:21 -070015 clearTimeout(flow.iperfFetchTimeout);
16 delete flow.iperfFetchTimeout;
17 clearInterval(flow.iperfDisplayInterval);
18 delete flow.iperfDisplayInterval;
Paul Greysoneeb69962013-04-12 15:53:29 -070019 clearTimeout(flow.animationTimeout);
20 delete flow.animationTimeout;
21 stopFlowAnimation(flow);
22 delete flow.iperfData.timestamp;
23
Paul Greyson17f84472013-04-12 14:39:21 -070024 delete flow.iperfData;
25}
26
27function startIPerfForFlow(flow) {
28 var duration = 10000; // seconds
29 var interval = 100; // ms. this is defined by the server
30 var updateRate = 3000; // ms
31 var pointsToDisplay = 1000;
32
33 function makeGraph(iperfData) {
34 var d = 'M0,0';
35
36 var now = flow.iperfData.startTime + (Date.now() - flow.iperfData.localNow)/1000;
37
38 if (iperfData.samples && iperfData.samples.length) {
39
40 var lastX;
41 var i = iperfData.samples.length - 1;
42 while (i) {
43 var sample = iperfData.samples[i];
44
45 var x = (1000 - (now - sample.time)*10);
46 // workaround for discontinuity in iperf data
47 if (x < 0) {
48 i -= 1;
49 continue;
50 }
51
52 var y = 28 * sample.value/1000000;
53 if (y > 28) {
54 y = 28;
55 }
56 if (i == iperfData.samples.length - 1) {
57 d = 'M' + x + ',30';
58 }
59
60 // handle gaps
61 // 1.5 for rounding error
62 if (lastX && lastX - x > 1.5) {
63 d += 'L' + lastX + ',30';
64 d += 'M' + x + ',30'
65 }
66 lastX = x;
67
68 d += 'L' + x + ',' + (30-y);
69
70 i -= 1;
71 }
72 d += 'L' + lastX + ',30';
73 }
74 return d;
75 }
76
77 if (flow.flowId) {
Paul Greysoneeb69962013-04-12 15:53:29 -070078 iperfLog('starting iperf', flow);
Paul Greyson17f84472013-04-12 14:39:21 -070079 startIPerf(flow, duration, updateRate/interval);
80 flow.iperfDisplayInterval = setInterval(function () {
81 if (flow.iperfData) {
82 var iperfPath = d3.select(document.getElementById(makeSelectedFlowKey(flow))).select('path');
Paul Greysoneeb69962013-04-12 15:53:29 -070083 flow.iperfData.samples.sort(function (a, b) {
84 return a.time - b.time;
85 });
Paul Greyson17f84472013-04-12 14:39:21 -070086 iperfPath.attr('d', makeGraph(flow.iperfData));
87 }
88
89
90 }, interval);
91
92 var animationTimeout;
93 flow.iperfData = {
94 samples: []
95 }
96
Paul Greysoneeb69962013-04-12 15:53:29 -070097 function resetFlowAnimationTimeout() {
98 clearTimeout(flow.animationTimeout);
99 // kill the animation if iperfdata stops flowing
100 flow.animationTimeout = setTimeout(function () {
101 stopFlowAnimation(flow);
102 }, updateRate*1.5);
103 }
104
Paul Greyson17f84472013-04-12 14:39:21 -0700105 var lastTime;
106 function fetchData() {
Paul Greysoneeb69962013-04-12 15:53:29 -0700107 iperfLog('Requesting iperf data', flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700108 var fetchTime = Date.now();
109 getIPerfData(flow, function (data) {
110 var requestTime = Date.now() - fetchTime;
111 var requestTimeMessage = 'iperf request completed in: ' + requestTime + 'ms';
112 if (requestTime > 1000) {
113 requestTimeMessage = requestTimeMessage.toUpperCase();
114 }
Paul Greysoneeb69962013-04-12 15:53:29 -0700115 iperfLog(requestTimeMessage, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700116
117 if (!flow.iperfData) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700118 iperfLog('iperf session closed', flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700119 return;
120 }
121
122 try {
123 var iperfData = JSON.parse(data);
124
Paul Greysoneeb69962013-04-12 15:53:29 -0700125// iperfLog(iperfData.timestamp, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700126
127 // if the data is fresh
128 if (!(flow.iperfData.timestamp && iperfData.timestamp != flow.iperfData.timestamp)) {
129 if (!flow.iperfData.timestamp) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700130 iperfLog('received first iperf buffer', flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700131 } else {
Paul Greysoneeb69962013-04-12 15:53:29 -0700132 iperfLog('received duplicate iperf buffer with timestamp: ' + iperfData.timestamp, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700133 }
134 } else {
Paul Greysoneeb69962013-04-12 15:53:29 -0700135 iperfLog('received new iperf buffer with timstamp: ' + iperfData.timestamp, flow);
136 startFlowAnimation(flow);
137 resetFlowAnimationTimeout();
Paul Greyson17f84472013-04-12 14:39:21 -0700138
139 var endTime = Math.floor(iperfData['end-time']*10)/10;
140
141 var startTime = endTime - (iperfData.samples.length * interval/1000);
142 // set now on the first buffer
143 if (!flow.iperfData.startTime) {
144 flow.iperfData.startTime = startTime;
145 flow.iperfData.localNow = Date.now();
146 }
147
Paul Greysoneeb69962013-04-12 15:53:29 -0700148 iperfLog('iperf buffer start time: ' + startTime, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700149 if (lastTime && (startTime - lastTime) > updateRate/1000) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700150 iperfLog('iperf buffer gap: ' + (startTime - lastTime), flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700151 }
152 lastTime = startTime;
153
154 // clear out the old data
155 while (flow.iperfData.samples.length > pointsToDisplay + iperfData.samples.length) {
156 flow.iperfData.samples.shift();
157 }
158
159 // if the client gets too out of sync, resynchronize
160 var clientNow = flow.iperfData.startTime + (Date.now() - flow.iperfData.localNow)/1000;
161 if (Math.abs(clientNow - startTime) > (updateRate/1000) * 2) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700162 iperfLog('resynchronizing now: ' + clientNow + ' => ' + startTime, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700163 flow.iperfData.startTime = startTime;
164 flow.iperfData.localNow = Date.now();
165 }
166
167 var time = startTime;
168 iperfData.samples.forEach(function (s) {
169 var sample = {
170 time: time,
171 value: s
172 };
173 flow.iperfData.samples.push(sample);
174 time += interval/1000;
175 });
176 }
177 flow.iperfData.timestamp = iperfData.timestamp;
178 } catch (e) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700179 iperfLog('bad iperf data: ' + data, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700180 }
181 flow.iperfFetchTimeout = setTimeout(fetchData, updateRate*.25); // over sample to avoid gaps
Paul Greysoneeb69962013-04-12 15:53:29 -0700182// iperfLog(data, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700183 });
184 }
185 fetchData();
186
187 }
188}