blob: ee0e3058181ca0823a1e5deaf11450d713f4396d [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
Jonathan Hart19ca4332013-04-13 21:00:34 -070052 var y = 24 * sample.value/1000000;
53 if (y > 24) {
54 y = 24;
Paul Greyson17f84472013-04-12 14:39:21 -070055 }
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);
Paul Greyson60b4c0a2013-04-12 16:13:00 -070080
Paul Greyson17f84472013-04-12 14:39:21 -070081 flow.iperfDisplayInterval = setInterval(function () {
82 if (flow.iperfData) {
83 var iperfPath = d3.select(document.getElementById(makeSelectedFlowKey(flow))).select('path');
Paul Greysoneeb69962013-04-12 15:53:29 -070084 flow.iperfData.samples.sort(function (a, b) {
85 return a.time - b.time;
86 });
Paul Greyson17f84472013-04-12 14:39:21 -070087 iperfPath.attr('d', makeGraph(flow.iperfData));
88 }
89
90
91 }, interval);
92
93 var animationTimeout;
94 flow.iperfData = {
95 samples: []
96 }
97
Paul Greysoneeb69962013-04-12 15:53:29 -070098 function resetFlowAnimationTimeout() {
99 clearTimeout(flow.animationTimeout);
100 // kill the animation if iperfdata stops flowing
101 flow.animationTimeout = setTimeout(function () {
102 stopFlowAnimation(flow);
103 }, updateRate*1.5);
104 }
105
Paul Greyson17f84472013-04-12 14:39:21 -0700106 var lastTime;
107 function fetchData() {
Paul Greysoneeb69962013-04-12 15:53:29 -0700108 iperfLog('Requesting iperf data', flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700109 var fetchTime = Date.now();
110 getIPerfData(flow, function (data) {
111 var requestTime = Date.now() - fetchTime;
112 var requestTimeMessage = 'iperf request completed in: ' + requestTime + 'ms';
113 if (requestTime > 1000) {
114 requestTimeMessage = requestTimeMessage.toUpperCase();
115 }
Paul Greysoneeb69962013-04-12 15:53:29 -0700116 iperfLog(requestTimeMessage, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700117
118 if (!flow.iperfData) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700119 iperfLog('iperf session closed', flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700120 return;
121 }
122
123 try {
124 var iperfData = JSON.parse(data);
125
Paul Greyson80bee442013-04-14 15:29:09 -0700126// console.log('end-time: ' + iperfData['end-time']);
Paul Greyson17f84472013-04-12 14:39:21 -0700127
128 // if the data is fresh
129 if (!(flow.iperfData.timestamp && iperfData.timestamp != flow.iperfData.timestamp)) {
130 if (!flow.iperfData.timestamp) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700131 iperfLog('received first iperf buffer', flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700132 } else {
Paul Greysoneeb69962013-04-12 15:53:29 -0700133 iperfLog('received duplicate iperf buffer with timestamp: ' + iperfData.timestamp, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700134 }
135 } else {
Paul Greysoneeb69962013-04-12 15:53:29 -0700136 iperfLog('received new iperf buffer with timstamp: ' + iperfData.timestamp, flow);
137 startFlowAnimation(flow);
138 resetFlowAnimationTimeout();
Paul Greyson17f84472013-04-12 14:39:21 -0700139
140 var endTime = Math.floor(iperfData['end-time']*10)/10;
141
142 var startTime = endTime - (iperfData.samples.length * interval/1000);
143 // set now on the first buffer
144 if (!flow.iperfData.startTime) {
145 flow.iperfData.startTime = startTime;
146 flow.iperfData.localNow = Date.now();
147 }
148
Paul Greysoneeb69962013-04-12 15:53:29 -0700149 iperfLog('iperf buffer start time: ' + startTime, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700150 if (lastTime && (startTime - lastTime) > updateRate/1000) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700151 iperfLog('iperf buffer gap: ' + (startTime - lastTime), flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700152 }
153 lastTime = startTime;
154
155 // clear out the old data
156 while (flow.iperfData.samples.length > pointsToDisplay + iperfData.samples.length) {
157 flow.iperfData.samples.shift();
158 }
159
160 // if the client gets too out of sync, resynchronize
161 var clientNow = flow.iperfData.startTime + (Date.now() - flow.iperfData.localNow)/1000;
162 if (Math.abs(clientNow - startTime) > (updateRate/1000) * 2) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700163 iperfLog('resynchronizing now: ' + clientNow + ' => ' + startTime, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700164 flow.iperfData.startTime = startTime;
165 flow.iperfData.localNow = Date.now();
166 }
167
168 var time = startTime;
169 iperfData.samples.forEach(function (s) {
170 var sample = {
171 time: time,
172 value: s
173 };
174 flow.iperfData.samples.push(sample);
175 time += interval/1000;
176 });
177 }
178 flow.iperfData.timestamp = iperfData.timestamp;
179 } catch (e) {
Paul Greysoneeb69962013-04-12 15:53:29 -0700180 iperfLog('bad iperf data: ' + data, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700181 }
182 flow.iperfFetchTimeout = setTimeout(fetchData, updateRate*.25); // over sample to avoid gaps
Paul Greysoneeb69962013-04-12 15:53:29 -0700183// iperfLog(data, flow);
Paul Greyson17f84472013-04-12 14:39:21 -0700184 });
185 }
Paul Greyson17f84472013-04-12 14:39:21 -0700186
Paul Greyson60b4c0a2013-04-12 16:13:00 -0700187 // wait a buffer to make sure the old iperf session gets cleared out
Paul Greysone21602a2013-04-12 16:17:22 -0700188 flow.iperfFetchTimeout = setTimeout(fetchData, updateRate);
Paul Greyson17f84472013-04-12 14:39:21 -0700189 }
190}