sam3u_benchmark.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * libusb example program to measure Atmel SAM3U isochronous performance
  3. * Copyright (C) 2012 Harald Welte <laforge@gnumonks.org>
  4. *
  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
  7. *
  8. * An Atmel SAM3U test firmware is also available in the above repository.
  9. *
  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.
  14. *
  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.
  19. *
  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
  23. */
  24. #include <unistd.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <errno.h>
  28. #include <signal.h>
  29. #include <libusb.h>
  30. #define EP_DATA_IN 0x82
  31. #define EP_ISO_IN 0x86
  32. static int do_exit = 0;
  33. static struct libusb_device_handle *devh = NULL;
  34. static unsigned long num_bytes = 0, num_xfer = 0;
  35. static struct timeval tv_start;
  36. static void cb_xfr(struct libusb_transfer *xfr)
  37. {
  38. unsigned int i;
  39. if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
  40. fprintf(stderr, "transfer status %d\n", xfr->status);
  41. libusb_free_transfer(xfr);
  42. exit(3);
  43. }
  44. if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
  45. for (i = 0; i < xfr->num_iso_packets; i++) {
  46. struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
  47. if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
  48. fprintf(stderr, "Error: pack %u status %d\n", i, pack->status);
  49. exit(5);
  50. }
  51. printf("pack%u length:%u, actual_length:%u\n", i, pack->length, pack->actual_length);
  52. }
  53. }
  54. printf("length:%u, actual_length:%u\n", xfr->length, xfr->actual_length);
  55. for (i = 0; i < xfr->actual_length; i++) {
  56. printf("%02x", xfr->buffer[i]);
  57. if (i % 16)
  58. printf("\n");
  59. else if (i % 8)
  60. printf(" ");
  61. else
  62. printf(" ");
  63. }
  64. num_bytes += xfr->actual_length;
  65. num_xfer++;
  66. if (libusb_submit_transfer(xfr) < 0) {
  67. fprintf(stderr, "error re-submitting URB\n");
  68. exit(1);
  69. }
  70. }
  71. static int benchmark_in(uint8_t ep)
  72. {
  73. static uint8_t buf[2048];
  74. static struct libusb_transfer *xfr;
  75. int num_iso_pack = 0;
  76. if (ep == EP_ISO_IN)
  77. num_iso_pack = 16;
  78. xfr = libusb_alloc_transfer(num_iso_pack);
  79. if (!xfr)
  80. return -ENOMEM;
  81. if (ep == EP_ISO_IN) {
  82. libusb_fill_iso_transfer(xfr, devh, ep, buf,
  83. sizeof(buf), num_iso_pack, cb_xfr, NULL, 0);
  84. libusb_set_iso_packet_lengths(xfr, sizeof(buf)/num_iso_pack);
  85. } else
  86. libusb_fill_bulk_transfer(xfr, devh, ep, buf,
  87. sizeof(buf), cb_xfr, NULL, 0);
  88. gettimeofday(&tv_start, NULL);
  89. /* NOTE: To reach maximum possible performance the program must
  90. * submit *multiple* transfers here, not just one.
  91. *
  92. * When only one transfer is submitted there is a gap in the bus
  93. * schedule from when the transfer completes until a new transfer
  94. * is submitted by the callback. This causes some jitter for
  95. * isochronous transfers and loss of throughput for bulk transfers.
  96. *
  97. * This is avoided by queueing multiple transfers in advance, so
  98. * that the host controller is always kept busy, and will schedule
  99. * more transfers on the bus while the callback is running for
  100. * transfers which have completed on the bus.
  101. */
  102. return libusb_submit_transfer(xfr);
  103. }
  104. static void measure(void)
  105. {
  106. struct timeval tv_stop;
  107. unsigned int diff_msec;
  108. gettimeofday(&tv_stop, NULL);
  109. diff_msec = (tv_stop.tv_sec - tv_start.tv_sec)*1000;
  110. diff_msec += (tv_stop.tv_usec - tv_start.tv_usec)/1000;
  111. printf("%lu transfers (total %lu bytes) in %u miliseconds => %lu bytes/sec\n",
  112. num_xfer, num_bytes, diff_msec, (num_bytes*1000)/diff_msec);
  113. }
  114. static void sig_hdlr(int signum)
  115. {
  116. switch (signum) {
  117. case SIGINT:
  118. measure();
  119. do_exit = 1;
  120. break;
  121. }
  122. }
  123. int main(int argc, char **argv)
  124. {
  125. int rc;
  126. struct sigaction sigact;
  127. sigact.sa_handler = sig_hdlr;
  128. sigemptyset(&sigact.sa_mask);
  129. sigact.sa_flags = 0;
  130. sigaction(SIGINT, &sigact, NULL);
  131. rc = libusb_init(NULL);
  132. if (rc < 0) {
  133. fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
  134. exit(1);
  135. }
  136. devh = libusb_open_device_with_vid_pid(NULL, 0x16c0, 0x0763);
  137. if (!devh) {
  138. fprintf(stderr, "Error finding USB device\n");
  139. goto out;
  140. }
  141. rc = libusb_claim_interface(devh, 2);
  142. if (rc < 0) {
  143. fprintf(stderr, "Error claiming interface: %s\n", libusb_error_name(rc));
  144. goto out;
  145. }
  146. benchmark_in(EP_ISO_IN);
  147. while (!do_exit) {
  148. rc = libusb_handle_events(NULL);
  149. if (rc != LIBUSB_SUCCESS)
  150. break;
  151. }
  152. /* Measurement has already been done by the signal handler. */
  153. libusb_release_interface(devh, 0);
  154. out:
  155. if (devh)
  156. libusb_close(devh);
  157. libusb_exit(NULL);
  158. return rc;
  159. }