source: mainline/uspace/app/tmon/burst_tests.c@ 2aaba7e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2aaba7e was f4b83cc, checked in by Petr Manek <petr.manek@…>, 8 years ago

tmon: change format string

  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 * Copyright (c) 2017 Petr Manek
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup tmon
30 * @{
31 */
32/**
33 * @file
34 * USB burst tests.
35 */
36
37#include <stdio.h>
38#include <errno.h>
39#include <str_error.h>
40#include <getopt.h>
41#include <usbdiag_iface.h>
42#include <macros.h>
43#include "commands.h"
44#include "tf.h"
45
46#define NAME "tmon"
47#define INDENT " "
48
49/** Generic burst test parameters. */
50typedef struct tmon_burst_test_params {
51 /** Inherited base. */
52 tmon_test_params_t base;
53 /** The count of reads/writes to perform. */
54 uint32_t cycles;
55 /** Size of single read/write. */
56 size_t size;
57} tmon_burst_test_params_t;
58
59/** Static array of long options, from which test parameters are parsed. */
60static struct option long_options[] = {
61 {"cycles", required_argument, NULL, 'n'},
62 {"size", required_argument, NULL, 's'},
63 {0, 0, NULL, 0}
64};
65
66/** String of short options, from which test parameters are parsed. */
67static const char *short_options = "n:s:";
68
69/** Common option parser for all burst tests.
70 * @param[in] argc Number of arguments.
71 * @param[in] argv Argument values. Must point to exactly `argc` strings.
72 * @param[out] params Parsed test parameters (if successful).
73 *
74 * @return EOK if successful (in such case caller becomes the owner of `params`).
75 */
76static int read_params(int argc, char *argv[], tmon_test_params_t **params)
77{
78 int rc;
79 tmon_burst_test_params_t *p = (tmon_burst_test_params_t *) malloc(sizeof(tmon_burst_test_params_t));
80 if (!p)
81 return ENOMEM;
82
83 // Default values.
84 p->cycles = 256;
85 p->size = 1024;
86
87 // Parse other than default values.
88 int c;
89 for (c = 0, optreset = 1, optind = 0; c != -1;) {
90 c = getopt_long(argc, argv, short_options, long_options, NULL);
91 switch (c) {
92 case -1:
93 break;
94 case 'n':
95 if (!optarg || str_uint32_t(optarg, NULL, 10, false, &p->cycles) != EOK) {
96 puts(NAME ": Invalid number of cycles.\n");
97 rc = EINVAL;
98 goto err_malloc;
99 }
100 break;
101 case 's':
102 if (!optarg || str_size_t(optarg, NULL, 10, false, &p->size) != EOK) {
103 puts(NAME ": Invalid data size.\n");
104 rc = EINVAL;
105 goto err_malloc;
106 }
107 break;
108 }
109 }
110
111 *params = (tmon_test_params_t *) p;
112 return EOK;
113
114err_malloc:
115 free(p);
116 *params = NULL;
117 return rc;
118}
119
120/** Unit of quantity used for pretty formatting. */
121typedef struct tmon_unit {
122 /** Prefix letter, which is printed before the actual unit. */
123 char prefix;
124 /** Factor of the unit. */
125 uint64_t factor;
126} tmon_unit_t;
127
128/** Static array of units with decreasing factors. */
129static const tmon_unit_t units[] = {
130 { .prefix = 'E', .factor = 1ul << 60 },
131 { .prefix = 'P', .factor = 1ul << 50 },
132 { .prefix = 'T', .factor = 1ul << 40 },
133 { .prefix = 'G', .factor = 1ul << 30 },
134 { .prefix = 'M', .factor = 1ul << 20 },
135 { .prefix = 'k', .factor = 1ul << 10 }
136};
137
138/** Format size in bytes for human reading.
139 * @param[in] size The size to format.
140 * @param[in] fmt Format string. Must include one double and char.
141 *
142 * @return Heap-allocated string if successful (caller becomes its owner), NULL otherwise.
143 */
144static char * format_size(double size, const char *fmt)
145{
146 // Figure out the "tightest" unit.
147 unsigned i;
148 for (i = 0; i < ARRAY_SIZE(units); ++i) {
149 if (units[i].factor <= size)
150 break;
151 }
152
153 char prefix[] = { '\0', '\0' };
154 double factor = 1;
155
156 if (i < ARRAY_SIZE(units)) {
157 prefix[0] = units[i].prefix;
158 factor = units[i].factor;
159 }
160
161 // Format the size.
162 const double div_size = size / factor;
163
164 char *out = NULL;
165 asprintf(&out, fmt, div_size, prefix);
166
167 return out;
168}
169
170/** Print burst test parameters.
171 * @param[in] params Test parameters to print.
172 */
173static void print_params(const tmon_burst_test_params_t *params)
174{
175 printf(INDENT "Number of cycles: %d\n", params->cycles);
176
177 char *str_size = format_size(params->size, "%.3f %sB");
178 printf(INDENT "Data size: %s\n", str_size);
179 free(str_size);
180}
181
182/** Print burst test results.
183 * @param[in] params Test parameters.
184 * @param[in] duration Duration of the burst test.
185 */
186static void print_results(const tmon_burst_test_params_t *params, usbdiag_dur_t duration)
187{
188 printf(INDENT "Total duration: %ld ms\n", duration);
189
190 const double dur_per_cycle = (double) duration / (double) params->cycles;
191 printf(INDENT "Duration per cycle: %.3f ms\n", dur_per_cycle);
192
193 const size_t total_size = params->size * params->cycles;
194 char *str_total_size = format_size(total_size, "%.3f %sB");
195 printf(INDENT "Total size: %s\n", str_total_size);
196 free(str_total_size);
197
198 const double speed = 1000.0 * (double) total_size / (double) duration;
199 char *str_speed = format_size(speed, "%.3f %sB/s");
200 printf(INDENT "Average speed: %s\n", str_speed);
201 free(str_speed);
202}
203
204/** Run "interrupt in" burst test.
205 * @param[in] exch Open async exchange with the diagnostic device.
206 * @param[in] generic_params Test parameters. Must point to 'tmon_burst_test_params_t'.
207 *
208 * @return Exit code
209 */
210static int run_intr_in(async_exch_t *exch, const tmon_test_params_t *generic_params)
211{
212 const tmon_burst_test_params_t *params = (tmon_burst_test_params_t *) generic_params;
213 puts("Reading data from interrupt endpoint.\n");
214 print_params(params);
215
216 usbdiag_dur_t duration;
217 int rc = usbdiag_burst_intr_in(exch, params->cycles, params->size, &duration);
218 if (rc) {
219 printf(NAME ": Test failed with error: %s\n", str_error(rc));
220 return 1;
221 }
222
223 puts("Test succeeded.\n");
224 print_results(params, duration);
225 return 0;
226}
227
228/** Run "interrupt out" burst test.
229 * @param[in] exch Open async exchange with the diagnostic device.
230 * @param[in] generic_params Test parameters. Must point to 'tmon_burst_test_params_t'.
231 *
232 * @return Exit code
233 */
234static int run_intr_out(async_exch_t *exch, const tmon_test_params_t *generic_params)
235{
236 const tmon_burst_test_params_t *params = (tmon_burst_test_params_t *) generic_params;
237 puts("Writing data to interrupt endpoint.\n");
238 print_params(params);
239
240 usbdiag_dur_t duration;
241 int rc = usbdiag_burst_intr_out(exch, params->cycles, params->size, &duration);
242 if (rc) {
243 printf(NAME ": Test failed with error: %s\n", str_error(rc));
244 return 1;
245 }
246
247 puts("Test succeeded.\n");
248 print_results(params, duration);
249 return 0;
250}
251
252/** Run "bulk in" burst test.
253 * @param[in] exch Open async exchange with the diagnostic device.
254 * @param[in] generic_params Test parameters. Must point to 'tmon_burst_test_params_t'.
255 *
256 * @return Exit code
257 */
258static int run_bulk_in(async_exch_t *exch, const tmon_test_params_t *generic_params)
259{
260 const tmon_burst_test_params_t *params = (tmon_burst_test_params_t *) generic_params;
261 puts("Reading data from bulk endpoint.\n");
262 print_params(params);
263
264 usbdiag_dur_t duration;
265 int rc = usbdiag_burst_bulk_in(exch, params->cycles, params->size, &duration);
266 if (rc) {
267 printf(NAME ": Test failed with error: %s\n", str_error(rc));
268 return 1;
269 }
270
271 puts("Test succeeded.\n");
272 print_results(params, duration);
273 return 0;
274}
275
276/** Run "bulk out" burst test.
277 * @param[in] exch Open async exchange with the diagnostic device.
278 * @param[in] generic_params Test parameters. Must point to 'tmon_burst_test_params_t'.
279 *
280 * @return Exit code
281 */
282static int run_bulk_out(async_exch_t *exch, const tmon_test_params_t *generic_params)
283{
284 const tmon_burst_test_params_t *params = (tmon_burst_test_params_t *) generic_params;
285 puts("Writing data to bulk endpoint.\n");
286 print_params(params);
287
288 usbdiag_dur_t duration;
289 int rc = usbdiag_burst_bulk_out(exch, params->cycles, params->size, &duration);
290 if (rc) {
291 printf(NAME ": Test failed with error: %s\n", str_error(rc));
292 return 1;
293 }
294
295 puts("Test succeeded.\n");
296 print_results(params, duration);
297 return 0;
298}
299
300/** Run "isochronous in" burst test.
301 * @param[in] exch Open async exchange with the diagnostic device.
302 * @param[in] generic_params Test parameters. Must point to 'tmon_burst_test_params_t'.
303 *
304 * @return Exit code
305 */
306static int run_isoch_in(async_exch_t *exch, const tmon_test_params_t *generic_params)
307{
308 const tmon_burst_test_params_t *params = (tmon_burst_test_params_t *) generic_params;
309 puts("Reading data from isochronous endpoint.\n");
310 print_params(params);
311
312 usbdiag_dur_t duration;
313 int rc = usbdiag_burst_isoch_in(exch, params->cycles, params->size, &duration);
314 if (rc) {
315 printf(NAME ": Test failed with error: %s\n", str_error(rc));
316 return 1;
317 }
318
319 puts("Test succeeded.\n");
320 print_results(params, duration);
321 return 0;
322}
323
324/** Run "isochronous out" burst test.
325 * @param[in] exch Open async exchange with the diagnostic device.
326 * @param[in] generic_params Test parameters. Must point to 'tmon_burst_test_params_t'.
327 *
328 * @return Exit code
329 */
330static int run_isoch_out(async_exch_t *exch, const tmon_test_params_t *generic_params)
331{
332 const tmon_burst_test_params_t *params = (tmon_burst_test_params_t *) generic_params;
333 puts("Writing data to isochronous endpoint.\n");
334 print_params(params);
335
336 usbdiag_dur_t duration;
337 int rc = usbdiag_burst_isoch_out(exch, params->cycles, params->size, &duration);
338 if (rc) {
339 printf(NAME ": Test failed with error: %s\n", str_error(rc));
340 return 1;
341 }
342
343 puts("Test succeeded.\n");
344 print_results(params, duration);
345 return 0;
346}
347
348/** Interrupt in burst test command handler.
349 * @param[in] argc Number of arguments.
350 * @param[in] argv Argument values. Must point to exactly `argc` strings.
351 *
352 * @return Exit code
353 */
354int tmon_burst_intr_in(int argc, char *argv[])
355{
356 static const tmon_test_ops_t ops = {
357 .run = run_intr_in,
358 .read_params = read_params
359 };
360
361 return tmon_test_main(argc, argv, &ops);
362}
363
364/** Interrupt out burst test command handler.
365 * @param[in] argc Number of arguments.
366 * @param[in] argv Argument values. Must point to exactly `argc` strings.
367 *
368 * @return Exit code
369 */
370int tmon_burst_intr_out(int argc, char *argv[])
371{
372 static const tmon_test_ops_t ops = {
373 .run = run_intr_out,
374 .read_params = read_params
375 };
376
377 return tmon_test_main(argc, argv, &ops);
378}
379
380/** Interrupt bulk burst test command handler.
381 * @param[in] argc Number of arguments.
382 * @param[in] argv Argument values. Must point to exactly `argc` strings.
383 *
384 * @return Exit code
385 */
386int tmon_burst_bulk_in(int argc, char *argv[])
387{
388 static const tmon_test_ops_t ops = {
389 .run = run_bulk_in,
390 .read_params = read_params
391 };
392
393 return tmon_test_main(argc, argv, &ops);
394}
395
396/** Bulk out burst test command handler.
397 * @param[in] argc Number of arguments.
398 * @param[in] argv Argument values. Must point to exactly `argc` strings.
399 *
400 * @return Exit code
401 */
402int tmon_burst_bulk_out(int argc, char *argv[])
403{
404 static const tmon_test_ops_t ops = {
405 .run = run_bulk_out,
406 .read_params = read_params
407 };
408
409 return tmon_test_main(argc, argv, &ops);
410}
411
412/** Isochronous in burst test command handler.
413 * @param[in] argc Number of arguments.
414 * @param[in] argv Argument values. Must point to exactly `argc` strings.
415 *
416 * @return Exit code
417 */
418int tmon_burst_isoch_in(int argc, char *argv[])
419{
420 static const tmon_test_ops_t ops = {
421 .run = run_isoch_in,
422 .read_params = read_params
423 };
424
425 return tmon_test_main(argc, argv, &ops);
426}
427
428/** Isochronous out burst test command handler.
429 * @param[in] argc Number of arguments.
430 * @param[in] argv Argument values. Must point to exactly `argc` strings.
431 *
432 * @return Exit code
433 */
434int tmon_burst_isoch_out(int argc, char *argv[])
435{
436 static const tmon_test_ops_t ops = {
437 .run = run_isoch_out,
438 .read_params = read_params
439 };
440
441 return tmon_test_main(argc, argv, &ops);
442}
443
444/** @}
445 */
Note: See TracBrowser for help on using the repository browser.