1 | %============================================================================== |
---|
2 | % Function wl_benchmark() |
---|
3 | % |
---|
4 | % Usage: |
---|
5 | % - results = wl_benchmark( nodes ) - Interactive mode |
---|
6 | % - results = wl_benchmark( nodes, 'read_iq', num_trials, num_samples_per_read, num_buffers ) - Read IQ benchmark |
---|
7 | % - results = wl_benchmark( nodes, 'write_iq', num_trials, num_samples_per_write, num_buffers ) - Write IQ benchmark |
---|
8 | % |
---|
9 | % NOTE: Can be used on a single node or an array of nodes |
---|
10 | % NOTE: If no output arguments are specified, then the function just prints the benchmark data |
---|
11 | % |
---|
12 | % Output: |
---|
13 | % - Pretty print of benchmark info |
---|
14 | % - Array of benchmark info (if the number of output arguments is 1) |
---|
15 | % |
---|
16 | %============================================================================== |
---|
17 | |
---|
18 | function data = wl_benchmark(varargin) |
---|
19 | interactive_mode = 0; |
---|
20 | benchmark = 99; |
---|
21 | num_rx_samples = 0; % Default to zero, set to the max samples per the node Read IQ length |
---|
22 | num_tx_samples = 0; % Default to zero, set to the max samples per the node Write IQ length |
---|
23 | num_trials = 1000; % Default to 1000 |
---|
24 | num_buffers = 1; |
---|
25 | |
---|
26 | |
---|
27 | %-------------------------------------------------------------------------- |
---|
28 | % Get inputs |
---|
29 | % |
---|
30 | if (nargin == 0) |
---|
31 | fprintf('Usage wl_benchmark:\n'); |
---|
32 | fprintf(' 1. Interactive Mode: \n'); |
---|
33 | fprintf(' results = wl_benchmark( nodes ) \n'); |
---|
34 | fprintf(' 2. Batch Mode: \n'); |
---|
35 | fprintf(' results = wl_benchmark( nodes, "benchmark", num_trials, num_samples_per_trial, num_buffers ) \n'); |
---|
36 | fprintf(' where \n'); |
---|
37 | fprintf(' benchmark is: [read_iq, write_iq] \n'); |
---|
38 | fprintf(' num_trials is: Number of trials to conduct for the benchmark\n'); |
---|
39 | fprintf(' num_samples_per_trial is: Number (1 ... Max IQ length) or "max" \n\n'); |
---|
40 | fprintf(' num_buffers is: Number of RF buffers to request ([1..4] depending on the node capabilities)\n\n'); |
---|
41 | error('Not enough arguments are provided'); |
---|
42 | |
---|
43 | elseif (nargin == 1) |
---|
44 | interactive_mode = 1; |
---|
45 | |
---|
46 | switch( class(varargin{1}) ) |
---|
47 | case 'wl_node' |
---|
48 | nodes = varargin{1}; |
---|
49 | numNodes = length(nodes); |
---|
50 | otherwise |
---|
51 | error('Unknown argument. Argument is of type "%s", need "wl_node"', class(varargin{1})); |
---|
52 | end |
---|
53 | |
---|
54 | elseif ((nargin == 4) || (nargin == 5)) |
---|
55 | switch( class(varargin{1}) ) |
---|
56 | case 'wl_node' |
---|
57 | nodes = varargin{1}; |
---|
58 | numNodes = length(nodes); |
---|
59 | otherwise |
---|
60 | error('Unknown argument. Argument is of type "%s", need "wl_node"', class(varargin{1})); |
---|
61 | end |
---|
62 | |
---|
63 | switch( class(varargin{2}) ) |
---|
64 | case 'char' |
---|
65 | func = lower( varargin{2} ); |
---|
66 | |
---|
67 | switch( func ) |
---|
68 | case 'read_iq' |
---|
69 | benchmark = 1; |
---|
70 | case 'write_iq' |
---|
71 | benchmark = 2; |
---|
72 | otherwise |
---|
73 | fprintf('Unknown Argument. Currently supported benchmarks are: \n'); |
---|
74 | fprintf(' read_iq \n'); |
---|
75 | fprintf(' write_iq \n'); |
---|
76 | error('Unknown benchmark function: %s \n', varargin{1} ); |
---|
77 | end |
---|
78 | otherwise |
---|
79 | error('Unknown argument. Argument is of type "%s", need "string"', class(varargin{2})); |
---|
80 | end |
---|
81 | |
---|
82 | switch( class(varargin{3}) ) |
---|
83 | case 'double' |
---|
84 | num_trials = varargin{3}; |
---|
85 | |
---|
86 | if ( num_trials <= 0 ) |
---|
87 | num_trials = 1; |
---|
88 | end |
---|
89 | |
---|
90 | otherwise |
---|
91 | error('Unknown argument. Argument is of type "%s", need "double"', class(varargin{3})); |
---|
92 | end |
---|
93 | |
---|
94 | switch( class(varargin{4}) ) |
---|
95 | case 'double' |
---|
96 | num_rx_samples = varargin{4}; |
---|
97 | num_tx_samples = varargin{4}; |
---|
98 | |
---|
99 | % Error checking for num_*_samples is done below on a per node basis |
---|
100 | |
---|
101 | case 'char' |
---|
102 | if( strcmp( 'max', lower( varargin{4} ) ) ) |
---|
103 | num_rx_samples = 0; |
---|
104 | num_tx_samples = 0; |
---|
105 | else |
---|
106 | fprintf('Unknown Argument. Number of Samples currently supports: \n'); |
---|
107 | fprintf(' Number - (ie 2^15) \n'); |
---|
108 | fprintf(' "max" - Set the number of samples to the maximum number of samples supported by the board \n'); |
---|
109 | error('Unknown argument: %s \n', varargin{4} ); |
---|
110 | end |
---|
111 | |
---|
112 | % Error checking for num_*_samples is done below on a per node basis |
---|
113 | |
---|
114 | otherwise |
---|
115 | error('Unknown argument. Argument is of type "%s", need "double" or "char"', class(varargin{4})); |
---|
116 | end |
---|
117 | |
---|
118 | % Default to 1 buffer if num_buffers is not specified |
---|
119 | if (nargin == 5) |
---|
120 | switch( class(varargin{5}) ) |
---|
121 | case 'double' |
---|
122 | num_buffers = varargin{5}; |
---|
123 | |
---|
124 | if ( num_buffers <= 0 ) |
---|
125 | num_buffers = 1; |
---|
126 | end |
---|
127 | |
---|
128 | otherwise |
---|
129 | error('Unknown argument. Argument is of type "%s", need "double"', class(varargin{5})); |
---|
130 | end |
---|
131 | else |
---|
132 | num_buffers = 1; |
---|
133 | end |
---|
134 | else |
---|
135 | error('Arguments incorrect. Please see usage.'); |
---|
136 | end |
---|
137 | |
---|
138 | |
---|
139 | |
---|
140 | if ( interactive_mode ) |
---|
141 | |
---|
142 | fprintf('------------------------------------------------------------\n'); |
---|
143 | fprintf('Please select benchmark to run:\n'); |
---|
144 | fprintf(' [ 1] Read IQ \n'); |
---|
145 | fprintf(' [ 2] Write IQ \n'); |
---|
146 | fprintf(' [99] Quit (default) \n'); |
---|
147 | |
---|
148 | temp = input('Enter benchmark number: ','s'); |
---|
149 | if(isempty(temp)) |
---|
150 | temp = benchmark; |
---|
151 | fprintf(' quitting.\n'); |
---|
152 | return |
---|
153 | else |
---|
154 | fprintf(' running test %s\n',temp); |
---|
155 | benchmark = str2num( temp ); |
---|
156 | end |
---|
157 | |
---|
158 | %---------------------------------------------------------------------- |
---|
159 | % Specific Arguments for each benchmark |
---|
160 | % |
---|
161 | switch( benchmark ) |
---|
162 | |
---|
163 | %------------------------------------------------------------------ |
---|
164 | % Read IQ Benchmark |
---|
165 | % |
---|
166 | case 1 |
---|
167 | fprintf('------------------------------------------------------------\n'); |
---|
168 | temp = input('Please enter the number of samples (default = Read IQ length of board): ','s'); |
---|
169 | if(isempty(temp)) |
---|
170 | fprintf(' defaulting to Read IQ length of the board \n'); |
---|
171 | else |
---|
172 | fprintf(' setting to %s (will be truncated to Read IQ length of the board)\n',temp); |
---|
173 | num_rx_samples = str2num( temp ); |
---|
174 | end |
---|
175 | |
---|
176 | %------------------------------------------------------------------ |
---|
177 | % Write IQ Benchmark |
---|
178 | % |
---|
179 | case 2 |
---|
180 | fprintf('------------------------------------------------------------\n'); |
---|
181 | temp = input('Please enter the number of samples (default = Write IQ length of board): ','s'); |
---|
182 | if(isempty(temp)) |
---|
183 | fprintf(' defaulting to Write IQ length of the board \n'); |
---|
184 | else |
---|
185 | fprintf(' setting to %s (will be truncated to Write IQ length of the board)\n',temp); |
---|
186 | num_tx_samples = str2num( temp ); |
---|
187 | end |
---|
188 | |
---|
189 | %------------------------------------------------------------------ |
---|
190 | % Default case |
---|
191 | % |
---|
192 | otherwise |
---|
193 | fprintf('Invalid benchmark selection. Quitting. \n'); |
---|
194 | return |
---|
195 | |
---|
196 | end |
---|
197 | |
---|
198 | %---------------------------------------------------------------------- |
---|
199 | % Common Arguments for all benchmarks |
---|
200 | % |
---|
201 | fprintf('------------------------------------------------------------\n'); |
---|
202 | temp = input('Please enter the number of trials (default = 1000): ','s'); |
---|
203 | if(isempty(temp)) |
---|
204 | temp = sprintf('%d', num_trials); |
---|
205 | fprintf(' defaulting to %s \n', temp); |
---|
206 | else |
---|
207 | num_trials = str2num( temp ); |
---|
208 | |
---|
209 | if ( num_trials <= 0 ) |
---|
210 | num_trials = 1; |
---|
211 | fprintf(' setting to 1 \n'); |
---|
212 | else |
---|
213 | fprintf(' setting to %s \n',temp); |
---|
214 | end |
---|
215 | end |
---|
216 | |
---|
217 | end % END interactive_mode |
---|
218 | |
---|
219 | |
---|
220 | |
---|
221 | %-------------------------------------------------------------------------- |
---|
222 | % Run the benchmark |
---|
223 | % |
---|
224 | |
---|
225 | fprintf('------------------------------------------------------------\n'); |
---|
226 | |
---|
227 | results = []; |
---|
228 | RxLength = num_rx_samples; |
---|
229 | TxLength = num_tx_samples; |
---|
230 | |
---|
231 | for n = 1:1:numNodes |
---|
232 | currNode = nodes(n); |
---|
233 | |
---|
234 | % Set the severity of the sequence number matching to IGNORE |
---|
235 | curr_severity = currNode.baseband.seq_num_match_severity; |
---|
236 | currNode.baseband.seq_num_match_severity = currNode.baseband.SEQ_NUM_MATCH_IGNORE; |
---|
237 | |
---|
238 | %---------------------------------------------------------------------- |
---|
239 | % Common Parameters for all benchmarks |
---|
240 | % |
---|
241 | if(currNode.hwVer == 3) |
---|
242 | SN = sprintf('W3-a-%05d',currNode.serialNumber); |
---|
243 | else |
---|
244 | SN = 'Serial Number N/A'; |
---|
245 | end |
---|
246 | |
---|
247 | ifc_ids = currNode.wl_getInterfaceIDs(); |
---|
248 | maximum_rx_len = wl_basebandCmd(currNode, ifc_ids.RF_A, 'rx_buff_max_num_samples'); |
---|
249 | |
---|
250 | if ( ( RxLength == 0 ) || ( RxLength > maximum_rx_len ) ) |
---|
251 | RxLength = maximum_rx_len; |
---|
252 | num_rx_samples = RxLength; |
---|
253 | end |
---|
254 | |
---|
255 | maximum_tx_len = wl_basebandCmd(currNode, ifc_ids.RF_A, 'tx_buff_max_num_samples'); |
---|
256 | |
---|
257 | if ( ( TxLength == 0 ) || ( TxLength > maximum_tx_len ) ) |
---|
258 | TxLength = maximum_tx_len; |
---|
259 | num_tx_samples = TxLength; |
---|
260 | end |
---|
261 | |
---|
262 | % Set up the buffers to transfer |
---|
263 | if (num_buffers <= currNode.num_interfaces) |
---|
264 | switch (num_buffers) |
---|
265 | case 1 |
---|
266 | RF_INF = [ifc_ids.RF_A]; |
---|
267 | case 2 |
---|
268 | RF_INF = [ifc_ids.RF_A, ifc_ids.RF_B]; |
---|
269 | case 3 |
---|
270 | RF_INF = [ifc_ids.RF_A, ifc_ids.RF_B, ifc_ids.RF_C]; |
---|
271 | case 4 |
---|
272 | RF_INF = [ifc_ids.RF_A, ifc_ids.RF_B, ifc_ids.RF_C, ifc_ids.RF_D]; |
---|
273 | end |
---|
274 | else |
---|
275 | error('Node does not support that many buffers'); |
---|
276 | end |
---|
277 | |
---|
278 | |
---|
279 | % Run Benchmark |
---|
280 | % |
---|
281 | % NOTE: To get a look at the memory used during each benchmark, use the following |
---|
282 | % commands to print memory usage: |
---|
283 | % x = memory; |
---|
284 | % fprintf('Memory Usage = %20d\n', x.MemUsedMATLAB); |
---|
285 | % |
---|
286 | switch( benchmark ) |
---|
287 | |
---|
288 | %------------------------------------------------------------------ |
---|
289 | % Read IQ Benchmark |
---|
290 | % |
---|
291 | case 1 |
---|
292 | fprintf('Read IQ running on node %d of %d: ID = %4s Serial Number = %12s Num samples = %10d Num buffers = %5d\n', n, numNodes, sprintf('%d',currNode.ID), SN, RxLength, num_buffers); |
---|
293 | |
---|
294 | rx_time = zeros(num_trials, 1); |
---|
295 | |
---|
296 | i = num_trials; |
---|
297 | |
---|
298 | % Test TX performance of node |
---|
299 | while( i > 0 ) |
---|
300 | |
---|
301 | xt = tic; |
---|
302 | |
---|
303 | rx_IQ = wl_basebandCmd(currNode, RF_INF, 'read_IQ', 0, RxLength); |
---|
304 | |
---|
305 | rx_time(i,1) = toc(xt); |
---|
306 | |
---|
307 | % NOTE: We clear the rx_IQ variable so that it is not maintained in memory during the |
---|
308 | % next Read IQ, thereby doubling the memory required for the test. |
---|
309 | clear rx_IQ; |
---|
310 | |
---|
311 | i = i - 1; |
---|
312 | end |
---|
313 | |
---|
314 | if ( num_trials > 5 ) |
---|
315 | rx_min_time = min( rx_time(1:(num_trials - 5),:) ); |
---|
316 | rx_max_time = max( rx_time(1:(num_trials - 5),:) ); |
---|
317 | rx_avg_time = mean( rx_time(1:(num_trials - 5),:) ); |
---|
318 | else |
---|
319 | rx_min_time = min( rx_time(1:(num_trials),:) ); |
---|
320 | rx_max_time = max( rx_time(1:(num_trials),:) ); |
---|
321 | rx_avg_time = mean( rx_time(1:(num_trials),:) ); |
---|
322 | end |
---|
323 | |
---|
324 | sec_ota_time(n) = RxLength / 40e6; % Each sample is at 40 MHz |
---|
325 | sec_per_iq(n) = rx_avg_time(1) / num_buffers; % Average IQ time over all trials (for a single buffer) |
---|
326 | bits_per_sec(n) = ((RxLength * num_buffers * 4 * 8) / rx_avg_time(1)); % Each sample is 4 bytes; 8 bits per byte |
---|
327 | |
---|
328 | |
---|
329 | %------------------------------------------------------------------ |
---|
330 | % Write IQ Benchmark |
---|
331 | % |
---|
332 | case 2 |
---|
333 | fprintf('Write IQ running on node %d of %d: ID = %4s Serial Number = %12s Num samples = %10d Num buffers = %5d\n', n, numNodes, sprintf('%d',currNode.ID), SN, TxLength, num_buffers ); |
---|
334 | |
---|
335 | TxData = zeros(TxLength, 1, 'double'); |
---|
336 | tx_time = zeros(num_trials, 1); |
---|
337 | |
---|
338 | i = num_trials; |
---|
339 | |
---|
340 | % Test RX performance of node |
---|
341 | while ( i > 0 ) |
---|
342 | xt = tic; |
---|
343 | wl_basebandCmd(currNode, RF_INF, 'write_IQ', TxData); |
---|
344 | tx_time(i,1) = toc(xt); |
---|
345 | |
---|
346 | i = i - 1; |
---|
347 | end |
---|
348 | |
---|
349 | if ( num_trials > 5 ) |
---|
350 | tx_min_time = min( tx_time(1:(num_trials - 5),:) ); |
---|
351 | tx_max_time = max( tx_time(1:(num_trials - 5),:) ); |
---|
352 | tx_avg_time = mean( tx_time(1:(num_trials - 5),:) ); |
---|
353 | else |
---|
354 | tx_min_time = min( tx_time(1:(num_trials),:) ); |
---|
355 | tx_max_time = max( tx_time(1:(num_trials),:) ); |
---|
356 | tx_avg_time = mean( tx_time(1:(num_trials),:) ); |
---|
357 | end |
---|
358 | |
---|
359 | sec_ota_time(n) = TxLength / 40e6; % Each sample is at 40 MHz |
---|
360 | sec_per_iq(n) = tx_avg_time(1); % Average IQ time over all trials |
---|
361 | bits_per_sec(n) = ((TxLength * 4 * 8) / tx_avg_time(1)); % Each sample is 4 bytes; 8 bits per byte |
---|
362 | |
---|
363 | |
---|
364 | %------------------------------------------------------------------ |
---|
365 | % Default case |
---|
366 | % |
---|
367 | otherwise |
---|
368 | fprintf('Invalid benchmark selection. Quitting. \n'); |
---|
369 | return |
---|
370 | |
---|
371 | end % END switch( benchmark ) |
---|
372 | |
---|
373 | % Restore the severity of the sequence number matching on the node |
---|
374 | currNode.baseband.seq_num_match_severity = curr_severity; |
---|
375 | |
---|
376 | end % END for each node |
---|
377 | |
---|
378 | |
---|
379 | %-------------------------------------------------------------------------- |
---|
380 | % Print the benchmark results |
---|
381 | % |
---|
382 | fprintf('------------------------------------------------------------\n'); |
---|
383 | fprintf('Displaying results of %d nodes:\n\n', n); |
---|
384 | |
---|
385 | extraTitle = ''; |
---|
386 | extraLine = ''; |
---|
387 | extraArgs = ''; |
---|
388 | |
---|
389 | switch( benchmark ) |
---|
390 | |
---|
391 | %---------------------------------------------------------------------- |
---|
392 | % Read IQ Benchmark |
---|
393 | % |
---|
394 | case 1 |
---|
395 | extraTitle = ' Transport | MTU Size (B) | Num Samples | TX/RX Time (ms) | Num Trials | Avg Read IQ Time (ms) | Avg Transfer Speed (Mbps) |'; |
---|
396 | extraLine = '-------------------------------------------------------------------------------------------------------------------------------'; |
---|
397 | |
---|
398 | %---------------------------------------------------------------------- |
---|
399 | % Write IQ Benchmark |
---|
400 | % |
---|
401 | case 2 |
---|
402 | extraTitle = ' Transport | MTU Size (B) | Num Samples | TX/RX Time (ms) | Num Trials | Avg Write IQ Time (ms) | Avg Transfer Speed (Mbps) |'; |
---|
403 | extraLine = '-----------------------------------------------------------------------------------------------------------------------------'; |
---|
404 | |
---|
405 | %---------------------------------------------------------------------- |
---|
406 | % Default case |
---|
407 | % |
---|
408 | otherwise |
---|
409 | fprintf('Invalid benchmark selection. Quitting. \n'); |
---|
410 | return |
---|
411 | |
---|
412 | end % END switch( benchmark ) |
---|
413 | |
---|
414 | |
---|
415 | fprintf('------------------------------%s\n',extraLine); |
---|
416 | fprintf('| ID | WLVER | Serial # |%s\n',extraTitle); |
---|
417 | fprintf('------------------------------%s\n',extraLine); |
---|
418 | |
---|
419 | for n = 1:1:numNodes |
---|
420 | currNode = nodes(n); |
---|
421 | |
---|
422 | ID = sprintf('%d', currNode.ID); |
---|
423 | WLVER = sprintf('%d.%d.%d',currNode.wlVer_major,currNode.wlVer_minor,currNode.wlVer_revision); |
---|
424 | HWVER = sprintf('%d', currNode.hwVer); |
---|
425 | MTU_SIZE = sprintf('%d', currNode.transport.getMaxPayload()); |
---|
426 | |
---|
427 | if(currNode.hwVer == 3) |
---|
428 | SN = sprintf('W3-a-%05d',currNode.serialNumber); |
---|
429 | else |
---|
430 | SN = 'N/A'; |
---|
431 | end |
---|
432 | |
---|
433 | if( strcmp( class(currNode.transport), 'wl_transport_eth_udp_mex' ) ) |
---|
434 | TPORT = 'WL Mex UDP'; |
---|
435 | elseif ( strcmp( class(currNode.transport), 'wl_transport_eth_udp_java' ) ) |
---|
436 | TPORT = 'Java UDP'; |
---|
437 | else |
---|
438 | TPORT = 'N/A'; |
---|
439 | end |
---|
440 | |
---|
441 | |
---|
442 | switch( benchmark ) |
---|
443 | |
---|
444 | %------------------------------------------------------------------ |
---|
445 | % Read IQ Benchmark |
---|
446 | % |
---|
447 | case 1 |
---|
448 | extraArgs = sprintf('%12s |%13s |%12d |%16.2f |%11d |%23.2f |%26.2f |',TPORT, MTU_SIZE, num_rx_samples, (sec_ota_time(n) * 1e3), num_trials, (sec_per_iq(n) * 1e3), (bits_per_sec(n) / 1e6) ); |
---|
449 | |
---|
450 | %------------------------------------------------------------------ |
---|
451 | % Write IQ Benchmark |
---|
452 | % |
---|
453 | case 2 |
---|
454 | extraArgs = sprintf('%12s |%13s |%12d |%16.2f |%11d |%23.2f |%26.2f |',TPORT, MTU_SIZE, num_tx_samples, (sec_ota_time(n) * 1e3), num_trials, (sec_per_iq(n) * 1e3), (bits_per_sec(n) / 1e6) ); |
---|
455 | |
---|
456 | %------------------------------------------------------------------ |
---|
457 | % Default case |
---|
458 | % |
---|
459 | otherwise |
---|
460 | fprintf('Invalid benchmark selection. Quitting. \n'); |
---|
461 | return |
---|
462 | |
---|
463 | end % END switch( benchmark ) |
---|
464 | |
---|
465 | fprintf('|%4s |%7s |%12s |%s\n',ID,WLVER,SN,extraArgs); |
---|
466 | fprintf('------------------------------%s\n',extraLine); |
---|
467 | end |
---|
468 | |
---|
469 | fprintf('\n'); |
---|
470 | |
---|
471 | |
---|
472 | %-------------------------------------------------------------------------- |
---|
473 | % Set outputs |
---|
474 | % |
---|
475 | if nargout == 0 |
---|
476 | return |
---|
477 | elseif nargout == 1 |
---|
478 | data = results; |
---|
479 | else |
---|
480 | error('Too many output arguments provided'); |
---|
481 | end |
---|
482 | |
---|
483 | end |
---|
484 | |
---|
485 | |
---|
486 | |
---|