Skip to content

Instantly share code, notes, and snippets.

@sfackler
Created March 29, 2015 01:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfackler/e979711b0ee2f2063462 to your computer and use it in GitHub Desktop.
Save sfackler/e979711b0ee2f2063462 to your computer and use it in GitHub Desktop.
#![feature(test, std_misc, thread_sleep)]
extern crate test;
use std::io::prelude::*;
use std::cmp;
use std::iter;
use std::time::Duration;
use std::thread;
use std::io::{self, ErrorKind};
fn with_end_to_cap<F>(v: &mut Vec<u8>, f: F) -> io::Result<usize>
where F: FnOnce(&mut [u8]) -> io::Result<usize>
{
let len = v.len();
let new_area = v.capacity() - len;
v.extend(iter::repeat(0).take(new_area));
match f(&mut v[len..]) {
Ok(n) => {
v.truncate(len + n);
Ok(n)
}
Err(e) => {
v.truncate(len);
Err(e)
}
}
}
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut read = 0;
loop {
if buf.capacity() == buf.len() {
buf.reserve(64 * 1024);
}
match with_end_to_cap(buf, |b| r.read(b)) {
Ok(0) => return Ok(read),
Ok(n) => read += n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
}
fn read_to_end_new<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> io::Result<usize> {
let start_len = buf.len();
let mut len = start_len;
let mut cap_bump = 16;
let ret;
loop {
if len == buf.len() {
if buf.capacity() == buf.len() {
if cap_bump < 64 * 1024 {
cap_bump *= 2;
}
buf.reserve(cap_bump);
}
let new_area = buf.capacity() - buf.len();
buf.extend(iter::repeat(0).take(new_area));
}
match r.read(&mut buf[len..]) {
Ok(0) => {
ret = Ok(len - start_len);
break;
}
Ok(n) => len += n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => {
ret = Err(e);
break;
}
}
}
buf.truncate(len);
ret
}
#[test]
fn test_new() {
let mut v = vec![1, 2, 3];
assert_eq!(Ok(5), read_to_end_new(&mut io::repeat(4).take(5), &mut v));
assert_eq!(vec![1, 2, 3, 4, 4, 4, 4, 4], v);
}
fn bench_std(b: &mut test::Bencher, size: u64) {
b.iter(|| {
let mut v = vec![];
read_to_end(&mut io::repeat(1).take(size), &mut v)
})
}
fn bench_new(b: &mut test::Bencher, size: u64) {
b.iter(|| {
let mut v = vec![];
read_to_end_new(&mut io::repeat(1).take(size), &mut v)
})
}
#[bench]
fn std_nodelay_4(b: &mut test::Bencher) {
bench_std(b, 4);
}
#[bench]
fn new_nodelay_4(b: &mut test::Bencher) {
bench_new(b, 4);
}
#[bench]
fn std_nodelay_5m(b: &mut test::Bencher) {
bench_std(b, 5 * 1024 * 1024);
}
#[bench]
fn new_nodelay_5m(b: &mut test::Bencher) {
bench_new(b, 5 * 1024 * 1024);
}
struct Delay<R: Read>(Duration, R);
impl<R: Read> Read for Delay<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
thread::sleep(self.0);
self.1.read(buf)
}
}
fn bench_std_delay(b: &mut test::Bencher, size: u64, delay: Duration) {
b.iter(|| {
let mut v = vec![];
read_to_end(&mut Delay(delay, io::repeat(1).take(size)), &mut v)
})
}
fn bench_new_delay(b: &mut test::Bencher, size: u64, delay: Duration) {
b.iter(|| {
let mut v = vec![];
read_to_end_new(&mut Delay(delay, io::repeat(1).take(size)), &mut v)
})
}
#[bench]
fn std_delay_4(b: &mut test::Bencher) {
bench_std_delay(b, 4, Duration::microseconds(1));
}
#[bench]
fn new_delay_4(b: &mut test::Bencher) {
bench_new_delay(b, 4, Duration::microseconds(1));
}
#[bench]
fn std_delay_5m(b: &mut test::Bencher) {
bench_std_delay(b, 5 * 1024 * 1024, Duration::microseconds(1));
}
#[bench]
fn new_delay_5m(b: &mut test::Bencher) {
bench_new_delay(b, 5 * 1024 * 1024, Duration::microseconds(1));
}
struct Cap<R: Read>(usize, R);
impl<R: Read> Read for Cap<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let end = cmp::min(buf.len(), self.0);
self.1.read(&mut buf[..end])
}
}
fn bench_std_delay_cap(b: &mut test::Bencher, size: u64, delay: Duration) {
b.iter(|| {
let mut v = vec![];
read_to_end(&mut Cap(10240, Delay(delay, io::repeat(1).take(size))), &mut v)
})
}
fn bench_new_delay_cap(b: &mut test::Bencher, size: u64, delay: Duration) {
b.iter(|| {
let mut v = vec![];
read_to_end_new(&mut Cap(10240, Delay(delay, io::repeat(1).take(size))), &mut v)
})
}
#[bench]
fn std_delay_4_cap(b: &mut test::Bencher) {
bench_std_delay_cap(b, 4, Duration::microseconds(1));
}
#[bench]
fn new_delay_4_cap(b: &mut test::Bencher) {
bench_new_delay_cap(b, 4, Duration::microseconds(1));
}
#[bench]
fn std_delay_5m_cap(b: &mut test::Bencher) {
bench_std_delay_cap(b, 5 * 1024 * 1024, Duration::microseconds(1));
}
#[bench]
fn new_delay_5m_cap(b: &mut test::Bencher) {
bench_new_delay_cap(b, 5 * 1024 * 1024, Duration::microseconds(1));
}
~/foo ❯ cargo bench
Compiling foo v0.0.1 (file:///home/sfackler/foo)
Running target/release/foo-7498d7dd7faecf5c
running 13 tests
test test_new ... ignored
test new_delay_4 ... bench: 230768 ns/iter (+/- 14812)
test new_delay_4_cap ... bench: 231421 ns/iter (+/- 7211)
test new_delay_5m ... bench: 14495370 ns/iter (+/- 4008648)
test new_delay_5m_cap ... bench: 73127954 ns/iter (+/- 59908587)
test new_nodelay_4 ... bench: 83 ns/iter (+/- 2)
test new_nodelay_5m ... bench: 12527237 ns/iter (+/- 335243)
test std_delay_4 ... bench: 373095 ns/iter (+/- 12613)
test std_delay_4_cap ... bench: 374190 ns/iter (+/- 19611)
test std_delay_5m ... bench: 17356012 ns/iter (+/- 15906588)
test std_delay_5m_cap ... bench: 883555035 ns/iter (+/- 205559857)
test std_nodelay_4 ... bench: 144937 ns/iter (+/- 2448)
test std_nodelay_5m ... bench: 16095893 ns/iter (+/- 3315116)
test result: ok. 0 passed; 0 failed; 1 ignored; 12 measured
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment