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