{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rust/issues/23820","labels_url":"https://api.github.com/repos/rust-lang/rust/issues/23820/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rust/issues/23820/comments","events_url":"https://api.github.com/repos/rust-lang/rust/issues/23820/events","html_url":"https://github.com/rust-lang/rust/pull/23820","id":65012421,"number":23820,"title":"Fix massive performance issue in read_to_end","user":{"login":"sfackler","id":1455697,"avatar_url":"https://avatars.githubusercontent.com/u/1455697?v=3","gravatar_id":"","url":"https://api.github.com/users/sfackler","html_url":"https://github.com/sfackler","followers_url":"https://api.github.com/users/sfackler/followers","following_url":"https://api.github.com/users/sfackler/following{/other_user}","gists_url":"https://api.github.com/users/sfackler/gists{/gist_id}","starred_url":"https://api.github.com/users/sfackler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sfackler/subscriptions","organizations_url":"https://api.github.com/users/sfackler/orgs","repos_url":"https://api.github.com/users/sfackler/repos","events_url":"https://api.github.com/users/sfackler/events{/privacy}","received_events_url":"https://api.github.com/users/sfackler/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"milestone":null,"comments":5,"created_at":"2015-03-29T02:02:18Z","updated_at":"2015-03-29T17:13:24Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/rust-lang/rust/pulls/23820","html_url":"https://github.com/rust-lang/rust/pull/23820","diff_url":"https://github.com/rust-lang/rust/pull/23820.diff","patch_url":"https://github.com/rust-lang/rust/pull/23820.patch"},"body":"with_end_to_cap is enormously expensive now that it's initializing\r\nmemory since it involves 64k allocation + memset on every call. This is\r\nmost noticable when calling read_to_end on very small readers, where the\r\nnew version if **4 orders of magnitude** faster.\r\n\r\nBufReader also depended on with_end_to_cap so I've rewritten it in its\r\noriginal form.\r\n\r\nAs a bonus, converted the buffered IO struct Debug impls to use the\r\ndebug builders.\r\n\r\nI first came across this in sfackler/rust-postgres#106 where a user reported a 10x performance regression. A call to read_to_end turned out to be the culprit: https://github.com/sfackler/rust-postgres/commit/9cd413d42c287154d6c64cc7913666b0517f35f3.\r\n\r\nThe new version differs from the old in a couple of ways. The buffer size used is now adaptive. It starts at 32 bytes and doubles each time EOF hasn't been reached up to a limit of 64k. In addition, the buffer is only truncated when EOF or an error has been reached, rather than after every call to read as was the case for the old implementation.\r\n\r\nI wrote up a benchmark to compare the old version and new version: https://gist.github.com/sfackler/e979711b0ee2f2063462\r\n\r\nIt tests a couple of different cases: a high bandwidth reader, a low bandwidth reader, and a low bandwidth reader that won't return more than 10k per call to `read`. The high bandwidth reader should be analagous to use cases when reading from e.g. a `BufReader` or `Vec`, and the low bandwidth readers should be analogous to reading from something like a `TcpStream`.\r\n\r\nOf special note, reads from a high bandwith reader containing 4 bytes are now *4,495 times faster*. \r\n```\r\n~/foo ❯ cargo bench\r\n   Compiling foo v0.0.1 (file:///home/sfackler/foo)\r\n     Running target/release/foo-7498d7dd7faecf5c\r\n\r\nrunning 13 tests\r\ntest test_new ... ignored\r\ntest new_delay_4      ... bench:    230768 ns/iter (+/- 14812)\r\ntest new_delay_4_cap  ... bench:    231421 ns/iter (+/- 7211)\r\ntest new_delay_5m     ... bench:  14495370 ns/iter (+/- 4008648)\r\ntest new_delay_5m_cap ... bench:  73127954 ns/iter (+/- 59908587)\r\ntest new_nodelay_4    ... bench:        83 ns/iter (+/- 2)\r\ntest new_nodelay_5m   ... bench:  12527237 ns/iter (+/- 335243)\r\ntest std_delay_4      ... bench:    373095 ns/iter (+/- 12613)\r\ntest std_delay_4_cap  ... bench:    374190 ns/iter (+/- 19611)\r\ntest std_delay_5m     ... bench:  17356012 ns/iter (+/- 15906588)\r\ntest std_delay_5m_cap ... bench: 883555035 ns/iter (+/- 205559857)\r\ntest std_nodelay_4    ... bench:    144937 ns/iter (+/- 2448)\r\ntest std_nodelay_5m   ... bench:  16095893 ns/iter (+/- 3315116)\r\n\r\ntest result: ok. 0 passed; 0 failed; 1 ignored; 12 measured\r\n```\r\n\r\nr? @alexcrichton "},"comment":{"url":"https://api.github.com/repos/rust-lang/rust/issues/comments/87445434","html_url":"https://github.com/rust-lang/rust/pull/23820#issuecomment-87445434","issue_url":"https://api.github.com/repos/rust-lang/rust/issues/23820","id":87445434,"user":{"login":"alexcrichton","id":64996,"avatar_url":"https://avatars.githubusercontent.com/u/64996?v=3","gravatar_id":"","url":"https://api.github.com/users/alexcrichton","html_url":"https://github.com/alexcrichton","followers_url":"https://api.github.com/users/alexcrichton/followers","following_url":"https://api.github.com/users/alexcrichton/following{/other_user}","gists_url":"https://api.github.com/users/alexcrichton/gists{/gist_id}","starred_url":"https://api.github.com/users/alexcrichton/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexcrichton/subscriptions","organizations_url":"https://api.github.com/users/alexcrichton/orgs","repos_url":"https://api.github.com/users/alexcrichton/repos","events_url":"https://api.github.com/users/alexcrichton/events{/privacy}","received_events_url":"https://api.github.com/users/alexcrichton/received_events","type":"User","site_admin":false},"created_at":"2015-03-29T17:13:24Z","updated_at":"2015-03-29T17:13:24Z","body":"@bors: retry"}}