2 * libusb example program to measure Atmel SAM3U isochronous performance
3 * Copyright (C) 2012 Harald Welte <laforge@gnumonks.org>
5 * Copied with the author's permission under LGPL-2.1 from
6 * http://git.gnumonks.org/cgi-bin/gitweb.cgi?p=sam3u-tests.git;a=blob;f=usb-benchmark-project/host/benchmark.c;h=74959f7ee88f1597286cd435f312a8ff52c56b7e
8 * An Atmel SAM3U test firmware is also available in the above repository.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
34 #define EP_DATA_IN 0x82
35 #define EP_ISO_IN 0x86
37 static int do_exit
= 0;
38 static struct libusb_device_handle
*devh
= NULL
;
40 static unsigned long num_bytes
= 0, num_xfer
= 0;
41 static struct timeval tv_start
;
43 static void LIBUSB_CALL
cb_xfr(struct libusb_transfer
*xfr
)
47 if (xfr
->status
!= LIBUSB_TRANSFER_COMPLETED
) {
48 fprintf(stderr
, "transfer status %d\n", xfr
->status
);
49 libusb_free_transfer(xfr
);
53 if (xfr
->type
== LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
) {
54 for (i
= 0; i
< xfr
->num_iso_packets
; i
++) {
55 struct libusb_iso_packet_descriptor
*pack
= &xfr
->iso_packet_desc
[i
];
57 if (pack
->status
!= LIBUSB_TRANSFER_COMPLETED
) {
58 fprintf(stderr
, "Error: pack %u status %d\n", i
, pack
->status
);
62 printf("pack%u length:%u, actual_length:%u\n", i
, pack
->length
, pack
->actual_length
);
66 printf("length:%u, actual_length:%u\n", xfr
->length
, xfr
->actual_length
);
67 for (i
= 0; i
< xfr
->actual_length
; i
++) {
68 printf("%02x", xfr
->buffer
[i
]);
76 num_bytes
+= xfr
->actual_length
;
79 if (libusb_submit_transfer(xfr
) < 0) {
80 fprintf(stderr
, "error re-submitting URB\n");
85 static int benchmark_in(uint8_t ep
)
87 static uint8_t buf
[2048];
88 static struct libusb_transfer
*xfr
;
94 xfr
= libusb_alloc_transfer(num_iso_pack
);
98 if (ep
== EP_ISO_IN
) {
99 libusb_fill_iso_transfer(xfr
, devh
, ep
, buf
,
100 sizeof(buf
), num_iso_pack
, cb_xfr
, NULL
, 0);
101 libusb_set_iso_packet_lengths(xfr
, sizeof(buf
)/num_iso_pack
);
103 libusb_fill_bulk_transfer(xfr
, devh
, ep
, buf
,
104 sizeof(buf
), cb_xfr
, NULL
, 0);
106 gettimeofday(&tv_start
, NULL
);
108 /* NOTE: To reach maximum possible performance the program must
109 * submit *multiple* transfers here, not just one.
111 * When only one transfer is submitted there is a gap in the bus
112 * schedule from when the transfer completes until a new transfer
113 * is submitted by the callback. This causes some jitter for
114 * isochronous transfers and loss of throughput for bulk transfers.
116 * This is avoided by queueing multiple transfers in advance, so
117 * that the host controller is always kept busy, and will schedule
118 * more transfers on the bus while the callback is running for
119 * transfers which have completed on the bus.
122 return libusb_submit_transfer(xfr
);
125 static void measure(void)
127 struct timeval tv_stop
;
128 unsigned int diff_msec
;
130 gettimeofday(&tv_stop
, NULL
);
132 diff_msec
= (tv_stop
.tv_sec
- tv_start
.tv_sec
)*1000;
133 diff_msec
+= (tv_stop
.tv_usec
- tv_start
.tv_usec
)/1000;
135 printf("%lu transfers (total %lu bytes) in %u miliseconds => %lu bytes/sec\n",
136 num_xfer
, num_bytes
, diff_msec
, (num_bytes
*1000)/diff_msec
);
139 static void sig_hdlr(int signum
)
149 int main(int argc
, char **argv
)
152 struct sigaction sigact
;
154 sigact
.sa_handler
= sig_hdlr
;
155 sigemptyset(&sigact
.sa_mask
);
157 sigaction(SIGINT
, &sigact
, NULL
);
159 rc
= libusb_init(NULL
);
161 fprintf(stderr
, "Error initializing libusb: %s\n", libusb_error_name(rc
));
165 devh
= libusb_open_device_with_vid_pid(NULL
, 0x16c0, 0x0763);
167 fprintf(stderr
, "Error finding USB device\n");
171 rc
= libusb_claim_interface(devh
, 2);
173 fprintf(stderr
, "Error claiming interface: %s\n", libusb_error_name(rc
));
177 benchmark_in(EP_ISO_IN
);
180 rc
= libusb_handle_events(NULL
);
181 if (rc
!= LIBUSB_SUCCESS
)
185 /* Measurement has already been done by the signal handler. */
187 libusb_release_interface(devh
, 0);