Skip to content

Commit b09b764

Browse files
committed
iio_{readdev,writedev}: Add benchmark feature
Add a new --benchmark (or -B) option. With this option enabled, no data is written to the standard output (for iio_readdev) or read from the standard input (for iio_writedev). Instead, the buffers are flipped as fast as possible. This functionality permits to benchmark the speed at which the data flows, and compare the performance of the various backends and/or with various buffer sizes. Signed-off-by: Paul Cercueil <[email protected]>
1 parent 21b466d commit b09b764

File tree

4 files changed

+94
-8
lines changed

4 files changed

+94
-8
lines changed

tests/iio_common.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <inttypes.h>
2626
#include <getopt.h>
2727
#include <string.h>
28+
#include <time.h>
2829

2930
#include "iio_common.h"
3031
#include "gen_code.h"
@@ -431,3 +432,15 @@ void usage(char *name, const struct option *options,
431432
exit(0);
432433
}
433434

435+
uint64_t get_time_us(void)
436+
{
437+
struct timespec tp;
438+
439+
#ifdef _WIN32
440+
timespec_get(&tp, TIME_UTC);
441+
#else
442+
clock_gettime(CLOCK_REALTIME, &tp);
443+
#endif
444+
445+
return tp.tv_sec * 1000000ull + tp.tv_nsec / 1000;
446+
}

tests/iio_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define IIO_TESTS_COMMON_H
2424

2525
#include <getopt.h>
26+
#include <stdint.h>
2627

2728
/*
2829
* internal buffers need to be big enough for attributes
@@ -62,6 +63,8 @@ void usage(char *name, const struct option *options, const char *options_descrip
6263
char ** dup_argv(char * name, int argc, char * argv[]);
6364
void free_argw(int argc, char * argw[]);
6465

66+
uint64_t get_time_us(void);
67+
6568
/* https://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html
6669
* {NAME_MAX} : Maximum number of bytes in a filename
6770
* {PATH_MAX} : Maximum number of bytes in a pathname

tests/iio_readdev.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <errno.h>
2323
#include <getopt.h>
2424
#include <iio.h>
25+
#include <inttypes.h>
2526
#include <signal.h>
2627
#include <stdio.h>
2728
#include <string.h>
@@ -33,12 +34,14 @@
3334

3435
#define SAMPLES_PER_READ 256
3536
#define DEFAULT_FREQ_HZ 100
37+
#define REFILL_PER_BENCHMARK 10
3638

3739
static const struct option options[] = {
3840
{"trigger", required_argument, 0, 't'},
3941
{"buffer-size", required_argument, 0, 'b'},
4042
{"samples", required_argument, 0, 's' },
4143
{"auto", no_argument, 0, 'a'},
44+
{"benchmark", no_argument, 0, 'B'},
4245
{0, 0, 0, 0},
4346
};
4447

@@ -49,6 +52,8 @@ static const char *options_descriptions[] = {
4952
"Size of the capture buffer. Default is 256.",
5053
"Number of samples to capture, 0 = infinite. Default is 0.",
5154
"Scan for available contexts and if only one is available use it.",
55+
"Benchmark throughput."
56+
"\n\t\t\tStatistics will be printed on the standard input.",
5257
};
5358

5459
static struct iio_context *ctx;
@@ -186,7 +191,7 @@ static ssize_t print_sample(const struct iio_channel *chn,
186191
return (ssize_t) len;
187192
}
188193

189-
#define MY_OPTS "t:b:s:T:"
194+
#define MY_OPTS "t:b:s:T:B"
190195
int main(int argc, char **argv)
191196
{
192197
char **argw;
@@ -198,6 +203,8 @@ int main(int argc, char **argv)
198203
ssize_t sample_size;
199204
ssize_t ret;
200205
struct option *opts;
206+
bool mib, benchmark = false;
207+
uint64_t before, after, rate, total;
201208

202209
argw = dup_argv(MY_NAME, argc, argv);
203210

@@ -238,6 +245,9 @@ int main(int argc, char **argv)
238245
}
239246
buffer_size = sanitize_clamp("buffer size", optarg, 1, SIZE_MAX);
240247
break;
248+
case 'B':
249+
benchmark = true;
250+
break;
241251
case 's':
242252
if (!optarg) {
243253
fprintf(stderr, "Number of Samples requires an argument\n");
@@ -371,7 +381,11 @@ int main(int argc, char **argv)
371381
_setmode(_fileno(stdout), _O_BINARY);
372382
#endif
373383

374-
while (app_running) {
384+
385+
for (i = 0, total = 0; app_running; ) {
386+
if (benchmark)
387+
before = get_time_us();
388+
375389
ret = iio_buffer_refill(buffer);
376390
if (ret < 0) {
377391
if (app_running) {
@@ -382,6 +396,26 @@ int main(int argc, char **argv)
382396
break;
383397
}
384398

399+
if (benchmark) {
400+
after = get_time_us();
401+
rate = buffer_size * sample_size * 1000000ull / (after - before);
402+
403+
total += rate;
404+
405+
if (++i == REFILL_PER_BENCHMARK) {
406+
mib = rate > 1000000;
407+
408+
fprintf(stderr, "\33[2K\rThroughput: %" PRIu64 " %ciB/s",
409+
total / (REFILL_PER_BENCHMARK * 1000 * (mib ? 1000 : 1)),
410+
mib ? 'M' : 'K');
411+
412+
i = 0;
413+
total = 0;
414+
}
415+
416+
continue;
417+
}
418+
385419
/* If there are only the samples we requested, we don't need to
386420
* demux */
387421
if (iio_buffer_step(buffer) == sample_size) {

tests/iio_writedev.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <errno.h>
2424
#include <getopt.h>
2525
#include <iio.h>
26+
#include <inttypes.h>
2627
#include <signal.h>
2728
#include <stdio.h>
2829
#include <string.h>
@@ -42,13 +43,15 @@
4243

4344
#define SAMPLES_PER_READ 256
4445
#define DEFAULT_FREQ_HZ 100
46+
#define REFILL_PER_BENCHMARK 10
4547

4648
static const struct option options[] = {
4749
{"trigger", required_argument, 0, 't'},
4850
{"buffer-size", required_argument, 0, 'b'},
4951
{"samples", required_argument, 0, 's' },
5052
{"auto", no_argument, 0, 'a'},
5153
{"cyclic", no_argument, 0, 'c'},
54+
{"benchmark", no_argument, 0, 'B'},
5255
{0, 0, 0, 0},
5356
};
5457

@@ -61,6 +64,8 @@ static const char *options_descriptions[] = {
6164
"Number of samples to write, 0 = infinite. Default is 0.",
6265
"Scan for available contexts and if only one is available use it.",
6366
"Use cyclic buffer mode.",
67+
"Benchmark throughput."
68+
"\n\t\t\tStatistics will be printed on the standard input.",
6469
};
6570

6671
static struct iio_context *ctx;
@@ -196,7 +201,7 @@ static ssize_t read_sample(const struct iio_channel *chn,
196201
return (ssize_t) nb;
197202
}
198203

199-
#define MY_OPTS "t:b:s:T:ac"
204+
#define MY_OPTS "t:b:s:T:acB"
200205

201206
int main(int argc, char **argv)
202207
{
@@ -207,9 +212,10 @@ int main(int argc, char **argv)
207212
int c;
208213
struct iio_device *dev;
209214
ssize_t sample_size;
210-
bool cyclic_buffer = false;
215+
bool mib, cyclic_buffer = false, benchmark = false;
211216
ssize_t ret;
212217
struct option *opts;
218+
uint64_t before, after, rate, total;
213219

214220
argw = dup_argv(MY_NAME, argc, argv);
215221

@@ -249,6 +255,9 @@ int main(int argc, char **argv)
249255
}
250256
buffer_size = sanitize_clamp("buffer size", optarg, 1, SIZE_MAX);
251257
break;
258+
case 'B':
259+
benchmark = true;
260+
break;
252261
case 's':
253262
if (!optarg) {
254263
fprintf(stderr, "Number of samples requires argument\n");
@@ -275,6 +284,12 @@ int main(int argc, char **argv)
275284
if (!ctx)
276285
return EXIT_FAILURE;
277286

287+
if (benchmark && cyclic_buffer) {
288+
fprintf(stderr, "Cannot benchmark in cyclic mode.\n");
289+
iio_context_destroy(ctx);
290+
return EXIT_FAILURE;
291+
}
292+
278293
setup_sig_handler();
279294

280295
dev = iio_context_find_device(ctx, argw[optind]);
@@ -381,10 +396,12 @@ int main(int argc, char **argv)
381396
_setmode(_fileno( stdin ), _O_BINARY);
382397
#endif
383398

384-
while (app_running) {
385-
/* If there are only the samples we requested, we don't need to
386-
* demux */
387-
if (iio_buffer_step(buffer) == sample_size) {
399+
for (i = 0, total = 0; app_running; ) {
400+
if (benchmark) {
401+
before = get_time_us();
402+
} else if (iio_buffer_step(buffer) == sample_size) {
403+
/* If there are only the samples we requested, we don't
404+
* need to demux */
388405
void *start = iio_buffer_start(buffer);
389406
size_t write_len, len = (intptr_t) iio_buffer_end(buffer)
390407
- (intptr_t) start;
@@ -424,6 +441,25 @@ int main(int argc, char **argv)
424441
break;
425442
}
426443

444+
if (benchmark) {
445+
after = get_time_us();
446+
rate = buffer_size * sample_size * 1000000ull / (after - before);
447+
448+
total += rate;
449+
450+
if (++i == REFILL_PER_BENCHMARK) {
451+
mib = rate > 1000000;
452+
453+
fprintf(stderr, "\33[2K\rThroughput: %" PRIu64 " %ciB/s",
454+
total / (REFILL_PER_BENCHMARK * 1000 * (mib ? 1000 : 1)),
455+
mib ? 'M' : 'K');
456+
457+
i = 0;
458+
total = 0;
459+
}
460+
}
461+
462+
427463
while(cyclic_buffer && app_running) {
428464
#ifdef _WIN32
429465
Sleep(1000);

0 commit comments

Comments
 (0)