1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Loopback test application
4  *
5  * Copyright 2015 Google Inc.
6  * Copyright 2015 Linaro Ltd.
7  */
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14 #include <poll.h>
15 #include <sys/types.h>
16 #include <time.h>
17 #include <unistd.h>
18 #include <dirent.h>
19 #include <signal.h>
20 
21 #define MAX_NUM_DEVICES 10
22 #define MAX_SYSFS_PREFIX 0x80
23 #define MAX_SYSFS_PATH	0x200
24 #define CSV_MAX_LINE	0x1000
25 #define SYSFS_MAX_INT	0x20
26 #define MAX_STR_LEN	255
27 #define DEFAULT_ASYNC_TIMEOUT 200000
28 
29 struct dict {
30 	char *name;
31 	int type;
32 };
33 
34 static struct dict dict[] = {
35 	{"ping", 2},
36 	{"transfer", 3},
37 	{"sink", 4},
38 	{NULL,}		/* list termination */
39 };
40 
41 struct loopback_results {
42 	float latency_avg;
43 	uint32_t latency_max;
44 	uint32_t latency_min;
45 	uint32_t latency_jitter;
46 
47 	float request_avg;
48 	uint32_t request_max;
49 	uint32_t request_min;
50 	uint32_t request_jitter;
51 
52 	float throughput_avg;
53 	uint32_t throughput_max;
54 	uint32_t throughput_min;
55 	uint32_t throughput_jitter;
56 
57 	float apbridge_unipro_latency_avg;
58 	uint32_t apbridge_unipro_latency_max;
59 	uint32_t apbridge_unipro_latency_min;
60 	uint32_t apbridge_unipro_latency_jitter;
61 
62 	float gbphy_firmware_latency_avg;
63 	uint32_t gbphy_firmware_latency_max;
64 	uint32_t gbphy_firmware_latency_min;
65 	uint32_t gbphy_firmware_latency_jitter;
66 
67 	uint32_t error;
68 };
69 
70 struct loopback_device {
71 	char name[MAX_STR_LEN];
72 	char sysfs_entry[MAX_SYSFS_PATH];
73 	char debugfs_entry[MAX_SYSFS_PATH];
74 	struct loopback_results results;
75 };
76 
77 struct loopback_test {
78 	int verbose;
79 	int debug;
80 	int raw_data_dump;
81 	int porcelain;
82 	int mask;
83 	int size;
84 	int iteration_max;
85 	int aggregate_output;
86 	int test_id;
87 	int device_count;
88 	int list_devices;
89 	int use_async;
90 	int async_timeout;
91 	int async_outstanding_operations;
92 	int us_wait;
93 	int file_output;
94 	int stop_all;
95 	int poll_count;
96 	char test_name[MAX_STR_LEN];
97 	char sysfs_prefix[MAX_SYSFS_PREFIX];
98 	char debugfs_prefix[MAX_SYSFS_PREFIX];
99 	struct timespec poll_timeout;
100 	struct loopback_device devices[MAX_NUM_DEVICES];
101 	struct loopback_results aggregate_results;
102 	struct pollfd fds[MAX_NUM_DEVICES];
103 };
104 
105 struct loopback_test t;
106 
107 /* Helper macros to calculate the aggregate results for all devices */
108 static inline int device_enabled(struct loopback_test *t, int dev_idx);
109 
110 #define GET_MAX(field)							\
111 static int get_##field##_aggregate(struct loopback_test *t)		\
112 {									\
113 	uint32_t max = 0;						\
114 	int i;								\
115 	for (i = 0; i < t->device_count; i++) {				\
116 		if (!device_enabled(t, i))				\
117 			continue;					\
118 		if (t->devices[i].results.field > max)			\
119 			max = t->devices[i].results.field;		\
120 	}								\
121 	return max;							\
122 }									\
123 
124 #define GET_MIN(field)							\
125 static int get_##field##_aggregate(struct loopback_test *t)		\
126 {									\
127 	uint32_t min = ~0;						\
128 	int i;								\
129 	for (i = 0; i < t->device_count; i++) {				\
130 		if (!device_enabled(t, i))				\
131 			continue;					\
132 		if (t->devices[i].results.field < min)			\
133 			min = t->devices[i].results.field;		\
134 	}								\
135 	return min;							\
136 }									\
137 
138 #define GET_AVG(field)							\
139 static int get_##field##_aggregate(struct loopback_test *t)		\
140 {									\
141 	uint32_t val = 0;						\
142 	uint32_t count = 0;						\
143 	int i;								\
144 	for (i = 0; i < t->device_count; i++) {				\
145 		if (!device_enabled(t, i))				\
146 			continue;					\
147 		count++;						\
148 		val += t->devices[i].results.field;			\
149 	}								\
150 	if (count)							\
151 		val /= count;						\
152 	return val;							\
153 }									\
154 
155 GET_MAX(throughput_max);
156 GET_MAX(request_max);
157 GET_MAX(latency_max);
158 GET_MAX(apbridge_unipro_latency_max);
159 GET_MAX(gbphy_firmware_latency_max);
160 GET_MIN(throughput_min);
161 GET_MIN(request_min);
162 GET_MIN(latency_min);
163 GET_MIN(apbridge_unipro_latency_min);
164 GET_MIN(gbphy_firmware_latency_min);
165 GET_AVG(throughput_avg);
166 GET_AVG(request_avg);
167 GET_AVG(latency_avg);
168 GET_AVG(apbridge_unipro_latency_avg);
169 GET_AVG(gbphy_firmware_latency_avg);
170 
abort(void)171 void abort(void)
172 {
173 	_exit(1);
174 }
175 
usage(void)176 void usage(void)
177 {
178 	fprintf(stderr, "Usage: loopback_test TEST [SIZE] ITERATIONS [SYSPATH] [DBGPATH]\n\n"
179 	"  Run TEST for a number of ITERATIONS with operation data SIZE bytes\n"
180 	"  TEST may be \'ping\' \'transfer\' or \'sink\'\n"
181 	"  SIZE indicates the size of transfer <= greybus max payload bytes\n"
182 	"  ITERATIONS indicates the number of times to execute TEST at SIZE bytes\n"
183 	"             Note if ITERATIONS is set to zero then this utility will\n"
184 	"             initiate an infinite (non terminating) test and exit\n"
185 	"             without logging any metrics data\n"
186 	"  SYSPATH indicates the sysfs path for the loopback greybus entries e.g.\n"
187 	"          /sys/bus/greybus/devices\n"
188 	"  DBGPATH indicates the debugfs path for the loopback greybus entries e.g.\n"
189 	"          /sys/kernel/debug/gb_loopback/\n"
190 	" Mandatory arguments\n"
191 	"   -t     must be one of the test names - sink, transfer or ping\n"
192 	"   -i     iteration count - the number of iterations to run the test over\n"
193 	" Optional arguments\n"
194 	"   -S     sysfs location - location for greybus 'endo' entries default /sys/bus/greybus/devices/\n"
195 	"   -D     debugfs location - location for loopback debugfs entries default /sys/kernel/debug/gb_loopback/\n"
196 	"   -s     size of data packet to send during test - defaults to zero\n"
197 	"   -m     mask - a bit mask of connections to include example: -m 8 = 4th connection -m 9 = 1st and 4th connection etc\n"
198 	"                 default is zero which means broadcast to all connections\n"
199 	"   -v     verbose output\n"
200 	"   -d     debug output\n"
201 	"   -r     raw data output - when specified the full list of latency values are included in the output CSV\n"
202 	"   -p     porcelain - when specified printout is in a user-friendly non-CSV format. This option suppresses writing to CSV file\n"
203 	"   -a     aggregate - show aggregation of all enabled devices\n"
204 	"   -l     list found loopback devices and exit\n"
205 	"   -x     Async - Enable async transfers\n"
206 	"   -o     Async Timeout - Timeout in uSec for async operations\n"
207 	"   -O     Poll loop time out in seconds(max time a test is expected to last, default: 30sec)\n"
208 	"   -c     Max number of outstanding operations for async operations\n"
209 	"   -w     Wait in uSec between operations\n"
210 	"   -z     Enable output to a CSV file (incompatible with -p)\n"
211 	"   -f     When starting new loopback test, stop currently running tests on all devices\n"
212 	"Examples:\n"
213 	"  Send 10000 transfers with a packet size of 128 bytes to all active connections\n"
214 	"  loopback_test -t transfer -s 128 -i 10000 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"
215 	"  loopback_test -t transfer -s 128 -i 10000 -m 0\n"
216 	"  Send 10000 transfers with a packet size of 128 bytes to connection 1 and 4\n"
217 	"  loopback_test -t transfer -s 128 -i 10000 -m 9\n"
218 	"  loopback_test -t ping -s 0 128 -i -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n"
219 	"  loopback_test -t sink -s 2030 -i 32768 -S /sys/bus/greybus/devices/ -D /sys/kernel/debug/gb_loopback/\n");
220 	abort();
221 }
222 
device_enabled(struct loopback_test * t,int dev_idx)223 static inline int device_enabled(struct loopback_test *t, int dev_idx)
224 {
225 	if (!t->mask || (t->mask & (1 << dev_idx)))
226 		return 1;
227 
228 	return 0;
229 }
230 
show_loopback_devices(struct loopback_test * t)231 static void show_loopback_devices(struct loopback_test *t)
232 {
233 	int i;
234 
235 	if (t->device_count == 0) {
236 		printf("No loopback devices.\n");
237 		return;
238 	}
239 
240 	for (i = 0; i < t->device_count; i++)
241 		printf("device[%d] = %s\n", i, t->devices[i].name);
242 
243 }
244 
open_sysfs(const char * sys_pfx,const char * node,int flags)245 int open_sysfs(const char *sys_pfx, const char *node, int flags)
246 {
247 	int fd;
248 	char path[MAX_SYSFS_PATH];
249 
250 	snprintf(path, sizeof(path), "%s%s", sys_pfx, node);
251 	fd = open(path, flags);
252 	if (fd < 0) {
253 		fprintf(stderr, "unable to open %s\n", path);
254 		abort();
255 	}
256 	return fd;
257 }
258 
read_sysfs_int_fd(int fd,const char * sys_pfx,const char * node)259 int read_sysfs_int_fd(int fd, const char *sys_pfx, const char *node)
260 {
261 	char buf[SYSFS_MAX_INT];
262 
263 	if (read(fd, buf, sizeof(buf)) < 0) {
264 		fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node,
265 			strerror(errno));
266 		close(fd);
267 		abort();
268 	}
269 	return atoi(buf);
270 }
271 
read_sysfs_float_fd(int fd,const char * sys_pfx,const char * node)272 float read_sysfs_float_fd(int fd, const char *sys_pfx, const char *node)
273 {
274 	char buf[SYSFS_MAX_INT];
275 
276 	if (read(fd, buf, sizeof(buf)) < 0) {
277 
278 		fprintf(stderr, "unable to read from %s%s %s\n", sys_pfx, node,
279 			strerror(errno));
280 		close(fd);
281 		abort();
282 	}
283 	return atof(buf);
284 }
285 
read_sysfs_int(const char * sys_pfx,const char * node)286 int read_sysfs_int(const char *sys_pfx, const char *node)
287 {
288 	int fd, val;
289 
290 	fd = open_sysfs(sys_pfx, node, O_RDONLY);
291 	val = read_sysfs_int_fd(fd, sys_pfx, node);
292 	close(fd);
293 	return val;
294 }
295 
read_sysfs_float(const char * sys_pfx,const char * node)296 float read_sysfs_float(const char *sys_pfx, const char *node)
297 {
298 	int fd;
299 	float val;
300 
301 	fd = open_sysfs(sys_pfx, node, O_RDONLY);
302 	val = read_sysfs_float_fd(fd, sys_pfx, node);
303 	close(fd);
304 	return val;
305 }
306 
write_sysfs_val(const char * sys_pfx,const char * node,int val)307 void write_sysfs_val(const char *sys_pfx, const char *node, int val)
308 {
309 	int fd, len;
310 	char buf[SYSFS_MAX_INT];
311 
312 	fd = open_sysfs(sys_pfx, node, O_RDWR);
313 	len = snprintf(buf, sizeof(buf), "%d", val);
314 	if (write(fd, buf, len) < 0) {
315 		fprintf(stderr, "unable to write to %s%s %s\n", sys_pfx, node,
316 			strerror(errno));
317 		close(fd);
318 		abort();
319 	}
320 	close(fd);
321 }
322 
get_results(struct loopback_test * t)323 static int get_results(struct loopback_test *t)
324 {
325 	struct loopback_device *d;
326 	struct loopback_results *r;
327 	int i;
328 
329 	for (i = 0; i < t->device_count; i++) {
330 		if (!device_enabled(t, i))
331 			continue;
332 
333 		d = &t->devices[i];
334 		r = &d->results;
335 
336 		r->error = read_sysfs_int(d->sysfs_entry, "error");
337 		r->request_min = read_sysfs_int(d->sysfs_entry, "requests_per_second_min");
338 		r->request_max = read_sysfs_int(d->sysfs_entry, "requests_per_second_max");
339 		r->request_avg = read_sysfs_float(d->sysfs_entry, "requests_per_second_avg");
340 
341 		r->latency_min = read_sysfs_int(d->sysfs_entry, "latency_min");
342 		r->latency_max = read_sysfs_int(d->sysfs_entry, "latency_max");
343 		r->latency_avg = read_sysfs_float(d->sysfs_entry, "latency_avg");
344 
345 		r->throughput_min = read_sysfs_int(d->sysfs_entry, "throughput_min");
346 		r->throughput_max = read_sysfs_int(d->sysfs_entry, "throughput_max");
347 		r->throughput_avg = read_sysfs_float(d->sysfs_entry, "throughput_avg");
348 
349 		r->apbridge_unipro_latency_min =
350 			read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_min");
351 		r->apbridge_unipro_latency_max =
352 			read_sysfs_int(d->sysfs_entry, "apbridge_unipro_latency_max");
353 		r->apbridge_unipro_latency_avg =
354 			read_sysfs_float(d->sysfs_entry, "apbridge_unipro_latency_avg");
355 
356 		r->gbphy_firmware_latency_min =
357 			read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_min");
358 		r->gbphy_firmware_latency_max =
359 			read_sysfs_int(d->sysfs_entry, "gbphy_firmware_latency_max");
360 		r->gbphy_firmware_latency_avg =
361 			read_sysfs_float(d->sysfs_entry, "gbphy_firmware_latency_avg");
362 
363 		r->request_jitter = r->request_max - r->request_min;
364 		r->latency_jitter = r->latency_max - r->latency_min;
365 		r->throughput_jitter = r->throughput_max - r->throughput_min;
366 		r->apbridge_unipro_latency_jitter =
367 			r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min;
368 		r->gbphy_firmware_latency_jitter =
369 			r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
370 
371 	}
372 
373 	/*calculate the aggregate results of all enabled devices */
374 	if (t->aggregate_output) {
375 		r = &t->aggregate_results;
376 
377 		r->request_min = get_request_min_aggregate(t);
378 		r->request_max = get_request_max_aggregate(t);
379 		r->request_avg = get_request_avg_aggregate(t);
380 
381 		r->latency_min = get_latency_min_aggregate(t);
382 		r->latency_max = get_latency_max_aggregate(t);
383 		r->latency_avg = get_latency_avg_aggregate(t);
384 
385 		r->throughput_min = get_throughput_min_aggregate(t);
386 		r->throughput_max = get_throughput_max_aggregate(t);
387 		r->throughput_avg = get_throughput_avg_aggregate(t);
388 
389 		r->apbridge_unipro_latency_min =
390 			get_apbridge_unipro_latency_min_aggregate(t);
391 		r->apbridge_unipro_latency_max =
392 			get_apbridge_unipro_latency_max_aggregate(t);
393 		r->apbridge_unipro_latency_avg =
394 			get_apbridge_unipro_latency_avg_aggregate(t);
395 
396 		r->gbphy_firmware_latency_min =
397 			get_gbphy_firmware_latency_min_aggregate(t);
398 		r->gbphy_firmware_latency_max =
399 			get_gbphy_firmware_latency_max_aggregate(t);
400 		r->gbphy_firmware_latency_avg =
401 			get_gbphy_firmware_latency_avg_aggregate(t);
402 
403 		r->request_jitter = r->request_max - r->request_min;
404 		r->latency_jitter = r->latency_max - r->latency_min;
405 		r->throughput_jitter = r->throughput_max - r->throughput_min;
406 		r->apbridge_unipro_latency_jitter =
407 			r->apbridge_unipro_latency_max - r->apbridge_unipro_latency_min;
408 		r->gbphy_firmware_latency_jitter =
409 			r->gbphy_firmware_latency_max - r->gbphy_firmware_latency_min;
410 
411 	}
412 
413 	return 0;
414 }
415 
format_output(struct loopback_test * t,struct loopback_results * r,const char * dev_name,char * buf,int buf_len,struct tm * tm)416 int format_output(struct loopback_test *t,
417 		  struct loopback_results *r,
418 		  const char *dev_name,
419 		  char *buf, int buf_len,
420 		  struct tm *tm)
421 {
422 	int len = 0;
423 
424 	memset(buf, 0x00, buf_len);
425 	len = snprintf(buf, buf_len, "%u-%u-%u %u:%u:%u",
426 		       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
427 		       tm->tm_hour, tm->tm_min, tm->tm_sec);
428 
429 	if (t->porcelain) {
430 		len += snprintf(&buf[len], buf_len - len,
431 			"\n test:\t\t\t%s\n path:\t\t\t%s\n size:\t\t\t%u\n iterations:\t\t%u\n errors:\t\t%u\n async:\t\t\t%s\n",
432 			t->test_name,
433 			dev_name,
434 			t->size,
435 			t->iteration_max,
436 			r->error,
437 			t->use_async ? "Enabled" : "Disabled");
438 
439 		len += snprintf(&buf[len], buf_len - len,
440 			" requests per-sec:\tmin=%u, max=%u, average=%f, jitter=%u\n",
441 			r->request_min,
442 			r->request_max,
443 			r->request_avg,
444 			r->request_jitter);
445 
446 		len += snprintf(&buf[len], buf_len - len,
447 			" ap-throughput B/s:\tmin=%u max=%u average=%f jitter=%u\n",
448 			r->throughput_min,
449 			r->throughput_max,
450 			r->throughput_avg,
451 			r->throughput_jitter);
452 		len += snprintf(&buf[len], buf_len - len,
453 			" ap-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
454 			r->latency_min,
455 			r->latency_max,
456 			r->latency_avg,
457 			r->latency_jitter);
458 		len += snprintf(&buf[len], buf_len - len,
459 			" apbridge-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
460 			r->apbridge_unipro_latency_min,
461 			r->apbridge_unipro_latency_max,
462 			r->apbridge_unipro_latency_avg,
463 			r->apbridge_unipro_latency_jitter);
464 
465 		len += snprintf(&buf[len], buf_len - len,
466 			" gbphy-latency usec:\tmin=%u max=%u average=%f jitter=%u\n",
467 			r->gbphy_firmware_latency_min,
468 			r->gbphy_firmware_latency_max,
469 			r->gbphy_firmware_latency_avg,
470 			r->gbphy_firmware_latency_jitter);
471 
472 	} else {
473 		len += snprintf(&buf[len], buf_len - len, ",%s,%s,%u,%u,%u",
474 			t->test_name, dev_name, t->size, t->iteration_max,
475 			r->error);
476 
477 		len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
478 			r->request_min,
479 			r->request_max,
480 			r->request_avg,
481 			r->request_jitter);
482 
483 		len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
484 			r->latency_min,
485 			r->latency_max,
486 			r->latency_avg,
487 			r->latency_jitter);
488 
489 		len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
490 			r->throughput_min,
491 			r->throughput_max,
492 			r->throughput_avg,
493 			r->throughput_jitter);
494 
495 		len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
496 			r->apbridge_unipro_latency_min,
497 			r->apbridge_unipro_latency_max,
498 			r->apbridge_unipro_latency_avg,
499 			r->apbridge_unipro_latency_jitter);
500 
501 		len += snprintf(&buf[len], buf_len - len, ",%u,%u,%f,%u",
502 			r->gbphy_firmware_latency_min,
503 			r->gbphy_firmware_latency_max,
504 			r->gbphy_firmware_latency_avg,
505 			r->gbphy_firmware_latency_jitter);
506 	}
507 
508 	printf("\n%s\n", buf);
509 
510 	return len;
511 }
512 
log_results(struct loopback_test * t)513 static int log_results(struct loopback_test *t)
514 {
515 	int fd, i, len, ret;
516 	struct tm tm;
517 	time_t local_time;
518 	char file_name[MAX_SYSFS_PATH];
519 	char data[CSV_MAX_LINE];
520 
521 	local_time = time(NULL);
522 	tm = *localtime(&local_time);
523 
524 	/*
525 	 * file name will test_name_size_iteration_max.csv
526 	 * every time the same test with the same parameters is run we will then
527 	 * append to the same CSV with datestamp - representing each test
528 	 * dataset.
529 	 */
530 	if (t->file_output && !t->porcelain) {
531 		snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv",
532 			 t->test_name, t->size, t->iteration_max);
533 
534 		fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, 0644);
535 		if (fd < 0) {
536 			fprintf(stderr, "unable to open %s for appending\n", file_name);
537 			abort();
538 		}
539 
540 	}
541 	for (i = 0; i < t->device_count; i++) {
542 		if (!device_enabled(t, i))
543 			continue;
544 
545 		len = format_output(t, &t->devices[i].results,
546 				    t->devices[i].name,
547 				    data, sizeof(data), &tm);
548 		if (t->file_output && !t->porcelain) {
549 			ret = write(fd, data, len);
550 			if (ret == -1)
551 				fprintf(stderr, "unable to write %d bytes to csv.\n", len);
552 		}
553 
554 	}
555 
556 
557 	if (t->aggregate_output) {
558 		len = format_output(t, &t->aggregate_results, "aggregate",
559 				    data, sizeof(data), &tm);
560 		if (t->file_output && !t->porcelain) {
561 			ret = write(fd, data, len);
562 			if (ret == -1)
563 				fprintf(stderr, "unable to write %d bytes to csv.\n", len);
564 		}
565 	}
566 
567 	if (t->file_output && !t->porcelain)
568 		close(fd);
569 
570 	return 0;
571 }
572 
is_loopback_device(const char * path,const char * node)573 int is_loopback_device(const char *path, const char *node)
574 {
575 	char file[MAX_SYSFS_PATH];
576 
577 	snprintf(file, MAX_SYSFS_PATH, "%s%s/iteration_count", path, node);
578 	if (access(file, F_OK) == 0)
579 		return 1;
580 	return 0;
581 }
582 
find_loopback_devices(struct loopback_test * t)583 int find_loopback_devices(struct loopback_test *t)
584 {
585 	struct dirent **namelist;
586 	int i, n, ret;
587 	unsigned int dev_id;
588 	struct loopback_device *d;
589 
590 	n = scandir(t->sysfs_prefix, &namelist, NULL, alphasort);
591 	if (n < 0) {
592 		perror("scandir");
593 		ret = -ENODEV;
594 		goto baddir;
595 	}
596 
597 	/* Don't include '.' and '..' */
598 	if (n <= 2) {
599 		ret = -ENOMEM;
600 		goto done;
601 	}
602 
603 	for (i = 0; i < n; i++) {
604 		ret = sscanf(namelist[i]->d_name, "gb_loopback%u", &dev_id);
605 		if (ret != 1)
606 			continue;
607 
608 		if (!is_loopback_device(t->sysfs_prefix, namelist[i]->d_name))
609 			continue;
610 
611 		if (t->device_count == MAX_NUM_DEVICES) {
612 			fprintf(stderr, "max number of devices reached!\n");
613 			break;
614 		}
615 
616 		d = &t->devices[t->device_count++];
617 		snprintf(d->name, MAX_STR_LEN, "gb_loopback%u", dev_id);
618 
619 		snprintf(d->sysfs_entry, MAX_SYSFS_PATH, "%s%s/",
620 			 t->sysfs_prefix, d->name);
621 
622 		snprintf(d->debugfs_entry, MAX_SYSFS_PATH, "%sraw_latency_%s",
623 			 t->debugfs_prefix, d->name);
624 
625 		if (t->debug)
626 			printf("add %s %s\n", d->sysfs_entry, d->debugfs_entry);
627 	}
628 
629 	ret = 0;
630 done:
631 	for (i = 0; i < n; i++)
632 		free(namelist[i]);
633 	free(namelist);
634 baddir:
635 	return ret;
636 }
637 
open_poll_files(struct loopback_test * t)638 static int open_poll_files(struct loopback_test *t)
639 {
640 	struct loopback_device *dev;
641 	char buf[MAX_SYSFS_PATH + MAX_STR_LEN];
642 	char dummy;
643 	int fds_idx = 0;
644 	int i;
645 
646 	for (i = 0; i < t->device_count; i++) {
647 		dev = &t->devices[i];
648 
649 		if (!device_enabled(t, i))
650 			continue;
651 
652 		snprintf(buf, sizeof(buf), "%s%s", dev->sysfs_entry, "iteration_count");
653 		t->fds[fds_idx].fd = open(buf, O_RDONLY);
654 		if (t->fds[fds_idx].fd < 0) {
655 			fprintf(stderr, "Error opening poll file!\n");
656 			goto err;
657 		}
658 		read(t->fds[fds_idx].fd, &dummy, 1);
659 		t->fds[fds_idx].events = POLLERR | POLLPRI;
660 		t->fds[fds_idx].revents = 0;
661 		fds_idx++;
662 	}
663 
664 	t->poll_count = fds_idx;
665 
666 	return 0;
667 
668 err:
669 	for (i = 0; i < fds_idx; i++)
670 		close(t->fds[i].fd);
671 
672 	return -1;
673 }
674 
close_poll_files(struct loopback_test * t)675 static int close_poll_files(struct loopback_test *t)
676 {
677 	int i;
678 	for (i = 0; i < t->poll_count; i++)
679 		close(t->fds[i].fd);
680 
681 	return 0;
682 }
is_complete(struct loopback_test * t)683 static int is_complete(struct loopback_test *t)
684 {
685 	int iteration_count;
686 	int i;
687 
688 	for (i = 0; i < t->device_count; i++) {
689 		if (!device_enabled(t, i))
690 			continue;
691 
692 		iteration_count = read_sysfs_int(t->devices[i].sysfs_entry,
693 						 "iteration_count");
694 
695 		/* at least one device did not finish yet */
696 		if (iteration_count != t->iteration_max)
697 			return 0;
698 	}
699 
700 	return 1;
701 }
702 
stop_tests(struct loopback_test * t)703 static void stop_tests(struct loopback_test *t)
704 {
705 	int i;
706 
707 	for (i = 0; i < t->device_count; i++) {
708 		if (!device_enabled(t, i))
709 			continue;
710 		write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
711 	}
712 }
713 
handler(int sig)714 static void handler(int sig) { /* do nothing */  }
715 
wait_for_complete(struct loopback_test * t)716 static int wait_for_complete(struct loopback_test *t)
717 {
718 	int number_of_events = 0;
719 	char dummy;
720 	int ret;
721 	int i;
722 	struct timespec *ts = NULL;
723 	struct sigaction sa;
724 	sigset_t mask_old, mask;
725 
726 	sigemptyset(&mask);
727 	sigemptyset(&mask_old);
728 	sigaddset(&mask, SIGINT);
729 	sigprocmask(SIG_BLOCK, &mask, &mask_old);
730 
731 	sa.sa_handler = handler;
732 	sa.sa_flags = 0;
733 	sigemptyset(&sa.sa_mask);
734 	if (sigaction(SIGINT, &sa, NULL) == -1) {
735 		fprintf(stderr, "sigaction error\n");
736 		return -1;
737 	}
738 
739 	if (t->poll_timeout.tv_sec != 0)
740 		ts = &t->poll_timeout;
741 
742 	while (1) {
743 
744 		ret = ppoll(t->fds, t->poll_count, ts, &mask_old);
745 		if (ret <= 0) {
746 			stop_tests(t);
747 			fprintf(stderr, "Poll exit with errno %d\n", errno);
748 			return -1;
749 		}
750 
751 		for (i = 0; i < t->poll_count; i++) {
752 			if (t->fds[i].revents & POLLPRI) {
753 				/* Dummy read to clear the event */
754 				read(t->fds[i].fd, &dummy, 1);
755 				number_of_events++;
756 			}
757 		}
758 
759 		if (number_of_events == t->poll_count)
760 			break;
761 	}
762 
763 	if (!is_complete(t)) {
764 		fprintf(stderr, "Iteration count did not finish!\n");
765 		return -1;
766 	}
767 
768 	return 0;
769 }
770 
prepare_devices(struct loopback_test * t)771 static void prepare_devices(struct loopback_test *t)
772 {
773 	int i;
774 
775 	/*
776 	 * Cancel any running tests on enabled devices. If
777 	 * stop_all option is given, stop test on all devices.
778 	 */
779 	for (i = 0; i < t->device_count; i++)
780 		if (t->stop_all || device_enabled(t, i))
781 			write_sysfs_val(t->devices[i].sysfs_entry, "type", 0);
782 
783 
784 	for (i = 0; i < t->device_count; i++) {
785 		if (!device_enabled(t, i))
786 			continue;
787 
788 		write_sysfs_val(t->devices[i].sysfs_entry, "us_wait",
789 				t->us_wait);
790 
791 		/* Set operation size */
792 		write_sysfs_val(t->devices[i].sysfs_entry, "size", t->size);
793 
794 		/* Set iterations */
795 		write_sysfs_val(t->devices[i].sysfs_entry, "iteration_max",
796 				t->iteration_max);
797 
798 		if (t->use_async) {
799 			write_sysfs_val(t->devices[i].sysfs_entry, "async", 1);
800 			write_sysfs_val(t->devices[i].sysfs_entry,
801 					"timeout", t->async_timeout);
802 			write_sysfs_val(t->devices[i].sysfs_entry,
803 					"outstanding_operations_max",
804 					t->async_outstanding_operations);
805 		} else {
806 			write_sysfs_val(t->devices[i].sysfs_entry, "async", 0);
807 		}
808 	}
809 }
810 
start(struct loopback_test * t)811 static int start(struct loopback_test *t)
812 {
813 	int i;
814 
815 	/* the test starts by writing test_id to the type file. */
816 	for (i = 0; i < t->device_count; i++) {
817 		if (!device_enabled(t, i))
818 			continue;
819 
820 		write_sysfs_val(t->devices[i].sysfs_entry, "type", t->test_id);
821 	}
822 
823 	return 0;
824 }
825 
826 
loopback_run(struct loopback_test * t)827 void loopback_run(struct loopback_test *t)
828 {
829 	int i;
830 	int ret;
831 
832 	for (i = 0; dict[i].name != NULL; i++) {
833 		if (strstr(dict[i].name, t->test_name))
834 			t->test_id = dict[i].type;
835 	}
836 	if (!t->test_id) {
837 		fprintf(stderr, "invalid test %s\n", t->test_name);
838 		usage();
839 		return;
840 	}
841 
842 	prepare_devices(t);
843 
844 	ret = open_poll_files(t);
845 	if (ret)
846 		goto err;
847 
848 	start(t);
849 
850 	ret = wait_for_complete(t);
851 	close_poll_files(t);
852 	if (ret)
853 		goto err;
854 
855 
856 	get_results(t);
857 
858 	log_results(t);
859 
860 	return;
861 
862 err:
863 	printf("Error running test\n");
864 	return;
865 }
866 
sanity_check(struct loopback_test * t)867 static int sanity_check(struct loopback_test *t)
868 {
869 	int i;
870 
871 	if (t->device_count == 0) {
872 		fprintf(stderr, "No loopback devices found\n");
873 		return -1;
874 	}
875 
876 	for (i = 0; i < MAX_NUM_DEVICES; i++) {
877 		if (!device_enabled(t, i))
878 			continue;
879 
880 		if (t->mask && !strcmp(t->devices[i].name, "")) {
881 			fprintf(stderr, "Bad device mask %x\n", (1 << i));
882 			return -1;
883 		}
884 
885 	}
886 
887 
888 	return 0;
889 }
890 
main(int argc,char * argv[])891 int main(int argc, char *argv[])
892 {
893 	int o, ret;
894 	char *sysfs_prefix = "/sys/class/gb_loopback/";
895 	char *debugfs_prefix = "/sys/kernel/debug/gb_loopback/";
896 
897 	memset(&t, 0, sizeof(t));
898 
899 	while ((o = getopt(argc, argv,
900 			   "t:s:i:S:D:m:v::d::r::p::a::l::x::o:O:c:w:z::f::")) != -1) {
901 		switch (o) {
902 		case 't':
903 			snprintf(t.test_name, MAX_STR_LEN, "%s", optarg);
904 			break;
905 		case 's':
906 			t.size = atoi(optarg);
907 			break;
908 		case 'i':
909 			t.iteration_max = atoi(optarg);
910 			break;
911 		case 'S':
912 			snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg);
913 			break;
914 		case 'D':
915 			snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg);
916 			break;
917 		case 'm':
918 			t.mask = atol(optarg);
919 			break;
920 		case 'v':
921 			t.verbose = 1;
922 			break;
923 		case 'd':
924 			t.debug = 1;
925 			break;
926 		case 'r':
927 			t.raw_data_dump = 1;
928 			break;
929 		case 'p':
930 			t.porcelain = 1;
931 			break;
932 		case 'a':
933 			t.aggregate_output = 1;
934 			break;
935 		case 'l':
936 			t.list_devices = 1;
937 			break;
938 		case 'x':
939 			t.use_async = 1;
940 			break;
941 		case 'o':
942 			t.async_timeout = atoi(optarg);
943 			break;
944 		case 'O':
945 			t.poll_timeout.tv_sec = atoi(optarg);
946 			break;
947 		case 'c':
948 			t.async_outstanding_operations = atoi(optarg);
949 			break;
950 		case 'w':
951 			t.us_wait = atoi(optarg);
952 			break;
953 		case 'z':
954 			t.file_output = 1;
955 			break;
956 		case 'f':
957 			t.stop_all = 1;
958 			break;
959 		default:
960 			usage();
961 			return -EINVAL;
962 		}
963 	}
964 
965 	if (!strcmp(t.sysfs_prefix, ""))
966 		snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", sysfs_prefix);
967 
968 	if (!strcmp(t.debugfs_prefix, ""))
969 		snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", debugfs_prefix);
970 
971 	ret = find_loopback_devices(&t);
972 	if (ret)
973 		return ret;
974 	ret = sanity_check(&t);
975 	if (ret)
976 		return ret;
977 
978 	if (t.list_devices) {
979 		show_loopback_devices(&t);
980 		return 0;
981 	}
982 
983 	if (t.test_name[0] == '\0' || t.iteration_max == 0)
984 		usage();
985 
986 	if (t.async_timeout == 0)
987 		t.async_timeout = DEFAULT_ASYNC_TIMEOUT;
988 
989 	loopback_run(&t);
990 
991 	return 0;
992 }
993