xref: /aosp_15_r20/external/libusb/examples/sam3u_benchmark.c (revision 86b64dcb59b3a0b37502ecd56e119234366a6f7e)
1*86b64dcbSAndroid Build Coastguard Worker /*
2*86b64dcbSAndroid Build Coastguard Worker  * libusb example program to measure Atmel SAM3U isochronous performance
3*86b64dcbSAndroid Build Coastguard Worker  * Copyright (C) 2012 Harald Welte <[email protected]>
4*86b64dcbSAndroid Build Coastguard Worker  *
5*86b64dcbSAndroid Build Coastguard Worker  * Copied with the author's permission under LGPL-2.1 from
6*86b64dcbSAndroid Build Coastguard Worker  * http://git.gnumonks.org/cgi-bin/gitweb.cgi?p=sam3u-tests.git;a=blob;f=usb-benchmark-project/host/benchmark.c;h=74959f7ee88f1597286cd435f312a8ff52c56b7e
7*86b64dcbSAndroid Build Coastguard Worker  *
8*86b64dcbSAndroid Build Coastguard Worker  * An Atmel SAM3U test firmware is also available in the above repository.
9*86b64dcbSAndroid Build Coastguard Worker  *
10*86b64dcbSAndroid Build Coastguard Worker  * This library is free software; you can redistribute it and/or
11*86b64dcbSAndroid Build Coastguard Worker  * modify it under the terms of the GNU Lesser General Public
12*86b64dcbSAndroid Build Coastguard Worker  * License as published by the Free Software Foundation; either
13*86b64dcbSAndroid Build Coastguard Worker  * version 2.1 of the License, or (at your option) any later version.
14*86b64dcbSAndroid Build Coastguard Worker  *
15*86b64dcbSAndroid Build Coastguard Worker  * This library is distributed in the hope that it will be useful,
16*86b64dcbSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*86b64dcbSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18*86b64dcbSAndroid Build Coastguard Worker  * Lesser General Public License for more details.
19*86b64dcbSAndroid Build Coastguard Worker  *
20*86b64dcbSAndroid Build Coastguard Worker  * You should have received a copy of the GNU Lesser General Public
21*86b64dcbSAndroid Build Coastguard Worker  * License along with this library; if not, write to the Free Software
22*86b64dcbSAndroid Build Coastguard Worker  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23*86b64dcbSAndroid Build Coastguard Worker  */
24*86b64dcbSAndroid Build Coastguard Worker 
25*86b64dcbSAndroid Build Coastguard Worker #include <config.h>
26*86b64dcbSAndroid Build Coastguard Worker 
27*86b64dcbSAndroid Build Coastguard Worker #include <errno.h>
28*86b64dcbSAndroid Build Coastguard Worker #include <signal.h>
29*86b64dcbSAndroid Build Coastguard Worker #include <stdio.h>
30*86b64dcbSAndroid Build Coastguard Worker #include <stdlib.h>
31*86b64dcbSAndroid Build Coastguard Worker #ifdef HAVE_SYS_TIME_H
32*86b64dcbSAndroid Build Coastguard Worker #include <sys/time.h>
33*86b64dcbSAndroid Build Coastguard Worker #endif
34*86b64dcbSAndroid Build Coastguard Worker #include <time.h>
35*86b64dcbSAndroid Build Coastguard Worker 
36*86b64dcbSAndroid Build Coastguard Worker #include "libusb.h"
37*86b64dcbSAndroid Build Coastguard Worker 
38*86b64dcbSAndroid Build Coastguard Worker #define EP_DATA_IN	0x82
39*86b64dcbSAndroid Build Coastguard Worker #define EP_ISO_IN	0x86
40*86b64dcbSAndroid Build Coastguard Worker 
41*86b64dcbSAndroid Build Coastguard Worker static volatile sig_atomic_t do_exit = 0;
42*86b64dcbSAndroid Build Coastguard Worker static struct libusb_device_handle *devh = NULL;
43*86b64dcbSAndroid Build Coastguard Worker 
44*86b64dcbSAndroid Build Coastguard Worker static unsigned long num_bytes = 0, num_xfer = 0;
45*86b64dcbSAndroid Build Coastguard Worker static struct timeval tv_start;
46*86b64dcbSAndroid Build Coastguard Worker 
get_timestamp(struct timeval * tv)47*86b64dcbSAndroid Build Coastguard Worker static void get_timestamp(struct timeval *tv)
48*86b64dcbSAndroid Build Coastguard Worker {
49*86b64dcbSAndroid Build Coastguard Worker #if defined(PLATFORM_WINDOWS)
50*86b64dcbSAndroid Build Coastguard Worker 	static LARGE_INTEGER frequency;
51*86b64dcbSAndroid Build Coastguard Worker 	LARGE_INTEGER counter;
52*86b64dcbSAndroid Build Coastguard Worker 
53*86b64dcbSAndroid Build Coastguard Worker 	if (!frequency.QuadPart)
54*86b64dcbSAndroid Build Coastguard Worker 		QueryPerformanceFrequency(&frequency);
55*86b64dcbSAndroid Build Coastguard Worker 
56*86b64dcbSAndroid Build Coastguard Worker 	QueryPerformanceCounter(&counter);
57*86b64dcbSAndroid Build Coastguard Worker 	counter.QuadPart *= 1000000;
58*86b64dcbSAndroid Build Coastguard Worker 	counter.QuadPart /= frequency.QuadPart;
59*86b64dcbSAndroid Build Coastguard Worker 
60*86b64dcbSAndroid Build Coastguard Worker 	tv->tv_sec = (long)(counter.QuadPart / 1000000ULL);
61*86b64dcbSAndroid Build Coastguard Worker 	tv->tv_usec = (long)(counter.QuadPart % 1000000ULL);
62*86b64dcbSAndroid Build Coastguard Worker #elif defined(HAVE_CLOCK_GETTIME)
63*86b64dcbSAndroid Build Coastguard Worker 	struct timespec ts;
64*86b64dcbSAndroid Build Coastguard Worker 
65*86b64dcbSAndroid Build Coastguard Worker 	(void)clock_gettime(CLOCK_MONOTONIC, &ts);
66*86b64dcbSAndroid Build Coastguard Worker 	tv->tv_sec = ts.tv_sec;
67*86b64dcbSAndroid Build Coastguard Worker 	tv->tv_usec = (int)(ts.tv_nsec / 1000L);
68*86b64dcbSAndroid Build Coastguard Worker #else
69*86b64dcbSAndroid Build Coastguard Worker 	gettimeofday(tv, NULL);
70*86b64dcbSAndroid Build Coastguard Worker #endif
71*86b64dcbSAndroid Build Coastguard Worker }
72*86b64dcbSAndroid Build Coastguard Worker 
cb_xfr(struct libusb_transfer * xfr)73*86b64dcbSAndroid Build Coastguard Worker static void LIBUSB_CALL cb_xfr(struct libusb_transfer *xfr)
74*86b64dcbSAndroid Build Coastguard Worker {
75*86b64dcbSAndroid Build Coastguard Worker 	int i;
76*86b64dcbSAndroid Build Coastguard Worker 
77*86b64dcbSAndroid Build Coastguard Worker 	if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
78*86b64dcbSAndroid Build Coastguard Worker 		fprintf(stderr, "transfer status %d\n", xfr->status);
79*86b64dcbSAndroid Build Coastguard Worker 		libusb_free_transfer(xfr);
80*86b64dcbSAndroid Build Coastguard Worker 		exit(3);
81*86b64dcbSAndroid Build Coastguard Worker 	}
82*86b64dcbSAndroid Build Coastguard Worker 
83*86b64dcbSAndroid Build Coastguard Worker 	if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
84*86b64dcbSAndroid Build Coastguard Worker 		for (i = 0; i < xfr->num_iso_packets; i++) {
85*86b64dcbSAndroid Build Coastguard Worker 			struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
86*86b64dcbSAndroid Build Coastguard Worker 
87*86b64dcbSAndroid Build Coastguard Worker 			if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
88*86b64dcbSAndroid Build Coastguard Worker 				fprintf(stderr, "Error: pack %d status %d\n", i, pack->status);
89*86b64dcbSAndroid Build Coastguard Worker 				exit(5);
90*86b64dcbSAndroid Build Coastguard Worker 			}
91*86b64dcbSAndroid Build Coastguard Worker 
92*86b64dcbSAndroid Build Coastguard Worker 			printf("pack%d length:%u, actual_length:%u\n", i, pack->length, pack->actual_length);
93*86b64dcbSAndroid Build Coastguard Worker 		}
94*86b64dcbSAndroid Build Coastguard Worker 	}
95*86b64dcbSAndroid Build Coastguard Worker 
96*86b64dcbSAndroid Build Coastguard Worker 	printf("length:%u, actual_length:%u\n", xfr->length, xfr->actual_length);
97*86b64dcbSAndroid Build Coastguard Worker 	for (i = 0; i < xfr->actual_length; i++) {
98*86b64dcbSAndroid Build Coastguard Worker 		printf("%02x", xfr->buffer[i]);
99*86b64dcbSAndroid Build Coastguard Worker 		if (i % 16)
100*86b64dcbSAndroid Build Coastguard Worker 			printf("\n");
101*86b64dcbSAndroid Build Coastguard Worker 		else if (i % 8)
102*86b64dcbSAndroid Build Coastguard Worker 			printf("  ");
103*86b64dcbSAndroid Build Coastguard Worker 		else
104*86b64dcbSAndroid Build Coastguard Worker 			printf(" ");
105*86b64dcbSAndroid Build Coastguard Worker 	}
106*86b64dcbSAndroid Build Coastguard Worker 	num_bytes += xfr->actual_length;
107*86b64dcbSAndroid Build Coastguard Worker 	num_xfer++;
108*86b64dcbSAndroid Build Coastguard Worker 
109*86b64dcbSAndroid Build Coastguard Worker 	if (libusb_submit_transfer(xfr) < 0) {
110*86b64dcbSAndroid Build Coastguard Worker 		fprintf(stderr, "error re-submitting URB\n");
111*86b64dcbSAndroid Build Coastguard Worker 		exit(1);
112*86b64dcbSAndroid Build Coastguard Worker 	}
113*86b64dcbSAndroid Build Coastguard Worker }
114*86b64dcbSAndroid Build Coastguard Worker 
benchmark_in(uint8_t ep)115*86b64dcbSAndroid Build Coastguard Worker static int benchmark_in(uint8_t ep)
116*86b64dcbSAndroid Build Coastguard Worker {
117*86b64dcbSAndroid Build Coastguard Worker 	static uint8_t buf[2048];
118*86b64dcbSAndroid Build Coastguard Worker 	static struct libusb_transfer *xfr;
119*86b64dcbSAndroid Build Coastguard Worker 	int num_iso_pack = 0;
120*86b64dcbSAndroid Build Coastguard Worker 
121*86b64dcbSAndroid Build Coastguard Worker 	if (ep == EP_ISO_IN)
122*86b64dcbSAndroid Build Coastguard Worker 		num_iso_pack = 16;
123*86b64dcbSAndroid Build Coastguard Worker 
124*86b64dcbSAndroid Build Coastguard Worker 	xfr = libusb_alloc_transfer(num_iso_pack);
125*86b64dcbSAndroid Build Coastguard Worker 	if (!xfr) {
126*86b64dcbSAndroid Build Coastguard Worker 		errno = ENOMEM;
127*86b64dcbSAndroid Build Coastguard Worker 		return -1;
128*86b64dcbSAndroid Build Coastguard Worker 	}
129*86b64dcbSAndroid Build Coastguard Worker 
130*86b64dcbSAndroid Build Coastguard Worker 	if (ep == EP_ISO_IN) {
131*86b64dcbSAndroid Build Coastguard Worker 		libusb_fill_iso_transfer(xfr, devh, ep, buf,
132*86b64dcbSAndroid Build Coastguard Worker 				sizeof(buf), num_iso_pack, cb_xfr, NULL, 0);
133*86b64dcbSAndroid Build Coastguard Worker 		libusb_set_iso_packet_lengths(xfr, sizeof(buf)/num_iso_pack);
134*86b64dcbSAndroid Build Coastguard Worker 	} else
135*86b64dcbSAndroid Build Coastguard Worker 		libusb_fill_bulk_transfer(xfr, devh, ep, buf,
136*86b64dcbSAndroid Build Coastguard Worker 				sizeof(buf), cb_xfr, NULL, 0);
137*86b64dcbSAndroid Build Coastguard Worker 
138*86b64dcbSAndroid Build Coastguard Worker 	get_timestamp(&tv_start);
139*86b64dcbSAndroid Build Coastguard Worker 
140*86b64dcbSAndroid Build Coastguard Worker 	/* NOTE: To reach maximum possible performance the program must
141*86b64dcbSAndroid Build Coastguard Worker 	 * submit *multiple* transfers here, not just one.
142*86b64dcbSAndroid Build Coastguard Worker 	 *
143*86b64dcbSAndroid Build Coastguard Worker 	 * When only one transfer is submitted there is a gap in the bus
144*86b64dcbSAndroid Build Coastguard Worker 	 * schedule from when the transfer completes until a new transfer
145*86b64dcbSAndroid Build Coastguard Worker 	 * is submitted by the callback. This causes some jitter for
146*86b64dcbSAndroid Build Coastguard Worker 	 * isochronous transfers and loss of throughput for bulk transfers.
147*86b64dcbSAndroid Build Coastguard Worker 	 *
148*86b64dcbSAndroid Build Coastguard Worker 	 * This is avoided by queueing multiple transfers in advance, so
149*86b64dcbSAndroid Build Coastguard Worker 	 * that the host controller is always kept busy, and will schedule
150*86b64dcbSAndroid Build Coastguard Worker 	 * more transfers on the bus while the callback is running for
151*86b64dcbSAndroid Build Coastguard Worker 	 * transfers which have completed on the bus.
152*86b64dcbSAndroid Build Coastguard Worker 	 */
153*86b64dcbSAndroid Build Coastguard Worker 
154*86b64dcbSAndroid Build Coastguard Worker 	return libusb_submit_transfer(xfr);
155*86b64dcbSAndroid Build Coastguard Worker }
156*86b64dcbSAndroid Build Coastguard Worker 
measure(void)157*86b64dcbSAndroid Build Coastguard Worker static void measure(void)
158*86b64dcbSAndroid Build Coastguard Worker {
159*86b64dcbSAndroid Build Coastguard Worker 	struct timeval tv_stop;
160*86b64dcbSAndroid Build Coastguard Worker 	unsigned long diff_msec;
161*86b64dcbSAndroid Build Coastguard Worker 
162*86b64dcbSAndroid Build Coastguard Worker 	get_timestamp(&tv_stop);
163*86b64dcbSAndroid Build Coastguard Worker 
164*86b64dcbSAndroid Build Coastguard Worker 	diff_msec = (tv_stop.tv_sec - tv_start.tv_sec) * 1000L;
165*86b64dcbSAndroid Build Coastguard Worker 	diff_msec += (tv_stop.tv_usec - tv_start.tv_usec) / 1000L;
166*86b64dcbSAndroid Build Coastguard Worker 
167*86b64dcbSAndroid Build Coastguard Worker 	printf("%lu transfers (total %lu bytes) in %lu milliseconds => %lu bytes/sec\n",
168*86b64dcbSAndroid Build Coastguard Worker 		num_xfer, num_bytes, diff_msec, (num_bytes * 1000L) / diff_msec);
169*86b64dcbSAndroid Build Coastguard Worker }
170*86b64dcbSAndroid Build Coastguard Worker 
sig_hdlr(int signum)171*86b64dcbSAndroid Build Coastguard Worker static void sig_hdlr(int signum)
172*86b64dcbSAndroid Build Coastguard Worker {
173*86b64dcbSAndroid Build Coastguard Worker 	(void)signum;
174*86b64dcbSAndroid Build Coastguard Worker 
175*86b64dcbSAndroid Build Coastguard Worker 	measure();
176*86b64dcbSAndroid Build Coastguard Worker 	do_exit = 1;
177*86b64dcbSAndroid Build Coastguard Worker }
178*86b64dcbSAndroid Build Coastguard Worker 
main(void)179*86b64dcbSAndroid Build Coastguard Worker int main(void)
180*86b64dcbSAndroid Build Coastguard Worker {
181*86b64dcbSAndroid Build Coastguard Worker 	int rc;
182*86b64dcbSAndroid Build Coastguard Worker 
183*86b64dcbSAndroid Build Coastguard Worker #if defined(PLATFORM_POSIX)
184*86b64dcbSAndroid Build Coastguard Worker 	struct sigaction sigact;
185*86b64dcbSAndroid Build Coastguard Worker 
186*86b64dcbSAndroid Build Coastguard Worker 	sigact.sa_handler = sig_hdlr;
187*86b64dcbSAndroid Build Coastguard Worker 	sigemptyset(&sigact.sa_mask);
188*86b64dcbSAndroid Build Coastguard Worker 	sigact.sa_flags = 0;
189*86b64dcbSAndroid Build Coastguard Worker 	(void)sigaction(SIGINT, &sigact, NULL);
190*86b64dcbSAndroid Build Coastguard Worker #else
191*86b64dcbSAndroid Build Coastguard Worker 	(void)signal(SIGINT, sig_hdlr);
192*86b64dcbSAndroid Build Coastguard Worker #endif
193*86b64dcbSAndroid Build Coastguard Worker 
194*86b64dcbSAndroid Build Coastguard Worker 	rc = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0);
195*86b64dcbSAndroid Build Coastguard Worker 	if (rc < 0) {
196*86b64dcbSAndroid Build Coastguard Worker 		fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
197*86b64dcbSAndroid Build Coastguard Worker 		exit(1);
198*86b64dcbSAndroid Build Coastguard Worker 	}
199*86b64dcbSAndroid Build Coastguard Worker 
200*86b64dcbSAndroid Build Coastguard Worker 	devh = libusb_open_device_with_vid_pid(NULL, 0x16c0, 0x0763);
201*86b64dcbSAndroid Build Coastguard Worker 	if (!devh) {
202*86b64dcbSAndroid Build Coastguard Worker 		fprintf(stderr, "Error finding USB device\n");
203*86b64dcbSAndroid Build Coastguard Worker 		goto out;
204*86b64dcbSAndroid Build Coastguard Worker 	}
205*86b64dcbSAndroid Build Coastguard Worker 
206*86b64dcbSAndroid Build Coastguard Worker 	rc = libusb_claim_interface(devh, 2);
207*86b64dcbSAndroid Build Coastguard Worker 	if (rc < 0) {
208*86b64dcbSAndroid Build Coastguard Worker 		fprintf(stderr, "Error claiming interface: %s\n", libusb_error_name(rc));
209*86b64dcbSAndroid Build Coastguard Worker 		goto out;
210*86b64dcbSAndroid Build Coastguard Worker 	}
211*86b64dcbSAndroid Build Coastguard Worker 
212*86b64dcbSAndroid Build Coastguard Worker 	benchmark_in(EP_ISO_IN);
213*86b64dcbSAndroid Build Coastguard Worker 
214*86b64dcbSAndroid Build Coastguard Worker 	while (!do_exit) {
215*86b64dcbSAndroid Build Coastguard Worker 		rc = libusb_handle_events(NULL);
216*86b64dcbSAndroid Build Coastguard Worker 		if (rc != LIBUSB_SUCCESS)
217*86b64dcbSAndroid Build Coastguard Worker 			break;
218*86b64dcbSAndroid Build Coastguard Worker 	}
219*86b64dcbSAndroid Build Coastguard Worker 
220*86b64dcbSAndroid Build Coastguard Worker 	/* Measurement has already been done by the signal handler. */
221*86b64dcbSAndroid Build Coastguard Worker 
222*86b64dcbSAndroid Build Coastguard Worker 	libusb_release_interface(devh, 2);
223*86b64dcbSAndroid Build Coastguard Worker out:
224*86b64dcbSAndroid Build Coastguard Worker 	if (devh)
225*86b64dcbSAndroid Build Coastguard Worker 		libusb_close(devh);
226*86b64dcbSAndroid Build Coastguard Worker 	libusb_exit(NULL);
227*86b64dcbSAndroid Build Coastguard Worker 	return rc;
228*86b64dcbSAndroid Build Coastguard Worker }
229