{"action":"created","issue":{"url":"https://api.github.com/repos/vpelletier/python-libusb1/issues/21","repository_url":"https://api.github.com/repos/vpelletier/python-libusb1","labels_url":"https://api.github.com/repos/vpelletier/python-libusb1/issues/21/labels{/name}","comments_url":"https://api.github.com/repos/vpelletier/python-libusb1/issues/21/comments","events_url":"https://api.github.com/repos/vpelletier/python-libusb1/issues/21/events","html_url":"https://github.com/vpelletier/python-libusb1/issues/21","id":183197680,"number":21,"title":"libusb1 slightly slower than pyusb for large data.","user":{"login":"diamondman","id":1037510,"avatar_url":"https://avatars.githubusercontent.com/u/1037510?v=3","gravatar_id":"","url":"https://api.github.com/users/diamondman","html_url":"https://github.com/diamondman","followers_url":"https://api.github.com/users/diamondman/followers","following_url":"https://api.github.com/users/diamondman/following{/other_user}","gists_url":"https://api.github.com/users/diamondman/gists{/gist_id}","starred_url":"https://api.github.com/users/diamondman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/diamondman/subscriptions","organizations_url":"https://api.github.com/users/diamondman/orgs","repos_url":"https://api.github.com/users/diamondman/repos","events_url":"https://api.github.com/users/diamondman/events{/privacy}","received_events_url":"https://api.github.com/users/diamondman/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2016-10-15T08:40:45Z","updated_at":"2016-10-16T09:40:29Z","closed_at":null,"body":"I am using libusb1 to communicate to a device and am looking for ways to make the transfer faster.\r\nThe bulk transfer is 5959114 bytes to the USB Bulk endpoint 2. Currently, the bulkWrite call of usb1 is taking the longest amount of time of my project. I tested sending the same data with pyusb and found pyusb usually faster than libusb1. I hope my statistics and use case can help increase performance of this great repository. Following are the statistics I came up with, and how to reproduce them.\r\n\r\nI hooked kernprof to my project and profiled usb1's bulkWrite function. Here are the results. I noticed the ctype conversion takes almost as much time as the transfer. Maybe there is a way to do this with zero copy in C?\r\n```\r\nLine #      Hits         Time  Per Hit   % Time  Line Contents\r\n==============================================================\r\n  1378                                               @profile\r\n  1379                                               def bulkWrite(self, endpoint, data, timeout=0):\r\n  1380                                                   \"\"\"\r\n  1381                                                   Synchronous bulk write.\r\n  1382                                                   endpoint: endpoint to send data to.\r\n  1383                                                   data: data to send.\r\n  1384                                                   timeout: in milliseconds, how long to wait for device acknowledgement.\r\n  1385                                                     Set to 0 to disable.\r\n  1386                                           \r\n  1387                                                   Returns the number of bytes actually sent.\r\n  1388                                                   \"\"\"\r\n  1389                                                   # pylint: disable=undefined-variable\r\n  1390         4           20      5.0      0.0          endpoint = (endpoint & ~ENDPOINT_DIR_MASK) | ENDPOINT_OUT\r\n  1391                                                   # pylint: enable=undefined-variable\r\n  1392         4      1381478 345369.5     41.5          data = (c_char * len(data))(*data)\r\n  1393         4      1945835 486458.8     58.5          return self._bulkTransfer(endpoint, data, sizeof(data), timeout)\r\n\r\n```\r\n\r\n# Example Code\r\n### Code with usb1\r\n```\r\nfrom usb1 import USBContext\r\nimport math\r\nc = USBContext()\r\nh = c.openByVendorIDAndProductID(0x03fd, 0x000d)\r\nh.claimInterface(0)\r\nh.setInterfaceAltSetting(0,1)\r\ndata = bytearray(b\"\\\\xf0\\\\x0f\"* (int(math.ceil(0xb5db91/4.0))))\r\nh.controlWrite(0x40, 0xb0, 0xb5A6, 0xdb91, b\"\")\r\nh.bulkWrite(2,data,timeout=5000)\r\n```\r\ntimeit line:\r\n```\r\ntimeit.timeit('h.controlWrite(0x40, 0xb0, 0xb5A6, 0xdb91, b\"\");h.bulkWrite(2,data,timeout=5000)', setup='from usb1 import USBContext;c = USBContext();h = c.openByVendorIDAndProductID(0x03fd, 0x000d);h.claimInterface(0);h.setInterfaceAltSetting(0,1);import math;data = bytearray(b\"\\\\xf0\\\\x0f\"* (int(math.ceil(0xb5db91/4.0))));',number=20)\r\n\r\n89.61355720099527 (Average 4.480677860049764s)\r\n```\r\n\r\n### Code with pyusb\r\n```\r\nimport usb.core\r\nfrom time import time\r\ndev = usb.core.find(idVendor=0x03fd, idProduct=0x000d)\r\ndev.set_configuration()\r\ncfg = dev.get_active_configuration()\r\nintf=cfg[0,1]\r\nintf.set_altsetting()\r\nep = intf.endpoints()[2]\r\ndata = bytearray(b\"\\\\xf0\\\\x0f\"*(int(math.ceil(0xb5db91/4.0))))\r\nh.controlWrite(0x40, 0xb0, 0xb5A6, 0xdb91, b\"\")\r\nh.bulkWrite(2,data,timeout=5000)\r\n```\r\nHere is the timeit line\r\n```\r\nimport timeit\r\ntimeit.timeit('h.controlWrite(0x40, 0xb0, 0xb5A6, 0xdb91, b\"\");h.bulkWrite(2,data,timeout=5000)', setup='from usb1 import USBContext;c = USBContext();h = c.openByVendorIDAndProductID(0x03fd, 0x000d);h.claimInterface(0);h.setInterfaceAltSetting(0,1);import math;data = bytearray(b\"\\\\xf0\\\\x0f\"*(int(math.ceil(0xb5db91/4.0))))',number=20)\r\n\r\n63.37948983995011 (Averate 3.1689744919975054s)\r\n```\r\n\r\n\r\nI can do a comparison with code in C directly calling libusb 1.0 if the benchmarks are useful.\r\n\r\nHere is my code that I ran during the profiling: https://github.com/diamondman/proteusisc/blob/059d94e3625331c2786bd5a592388bd9f4caa893/proteusisc/drivers/xilinxPC1driver.py#L327-L333 (Please forgive the messyness. It is still alpha)\r\n"},"comment":{"url":"https://api.github.com/repos/vpelletier/python-libusb1/issues/comments/254037083","html_url":"https://github.com/vpelletier/python-libusb1/issues/21#issuecomment-254037083","issue_url":"https://api.github.com/repos/vpelletier/python-libusb1/issues/21","id":254037083,"user":{"login":"diamondman","id":1037510,"avatar_url":"https://avatars.githubusercontent.com/u/1037510?v=3","gravatar_id":"","url":"https://api.github.com/users/diamondman","html_url":"https://github.com/diamondman","followers_url":"https://api.github.com/users/diamondman/followers","following_url":"https://api.github.com/users/diamondman/following{/other_user}","gists_url":"https://api.github.com/users/diamondman/gists{/gist_id}","starred_url":"https://api.github.com/users/diamondman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/diamondman/subscriptions","organizations_url":"https://api.github.com/users/diamondman/orgs","repos_url":"https://api.github.com/users/diamondman/repos","events_url":"https://api.github.com/users/diamondman/events{/privacy}","received_events_url":"https://api.github.com/users/diamondman/received_events","type":"User","site_admin":false},"created_at":"2016-10-16T09:40:29Z","updated_at":"2016-10-16T09:40:29Z","body":"I will pull the branch and test. \r\nI changed my code to generate a bytes object from C, so I no longer rely on bytesarray. \r\nInteresting issue of bytearray being easier to work with. I know that the C api has PyBytes_AsString (and the equivalent py2 version) that returns the internal buffer of a bytes object. I have not grasped the full code base yet, but maybe the functions like _bulkTransfer could take the bytes/bytearray and directly use the object's buffer with the libusb1 function calls.\r\n\r\nAnything else I can do to assist?\r\n"}}
{"actor":{"display_login":"diamondman"}}