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