<commit_before>#![feature(test)]
extern crate test;
extern crate byteorder;
extern crate scroll;
extern crate rayon;
//extern crate byteio;

use scroll::{Cread, Cwrite, Pread, Pwrite, IOread, IOwrite, LE};
use test::black_box;

#[bench]
fn bench_parallel_cread_with(b: &mut test::Bencher) {
    use rayon::prelude::*;
    let vec = vec![0u8; 1_000_000];
    let nums = vec![0usize; 500_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        nums.par_iter().for_each(| offset | {
            let _: u16 = black_box(data.cread_with(*offset, LE));
        });
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_cread_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: u16 = black_box(val.cread_with(0, LE));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_cread(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.cread(0));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_ctx_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread(0));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_with_unwrap(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data: &[u8] = &black_box([1, 2]);
            let _: u16 = black_box(data.pread_with(0, LE).unwrap());
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread_with(0, LE));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_unwrap(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.pread(0)).unwrap();
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_gread_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let mut offset = 0;
            let _: Result<u16, _> = black_box(val.gread(&mut offset));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_gread_unwrap(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let mut offset = 0;
            let _: u16 = black_box(data.gread_with(&mut offset, LE).unwrap());
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_parallel_pread_with(b: &mut test::Bencher) {
    use rayon::prelude::*;
    let vec = vec![0u8; 1_000_000];
    let nums = vec![0usize; 500_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        nums.par_iter().for_each(| offset | {
            let _: Result<u16, _> = black_box(data.pread_with(*offset, LE));
        });
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteorder_vec(b: &mut test::Bencher) {
    use byteorder::ReadBytesExt;
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for mut val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.read_u16::<byteorder::LittleEndian>());
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteorder(b: &mut test::Bencher) {
    use byteorder::ByteOrder;
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(byteorder::LittleEndian::read_u16(&data));
        }
    });
    b.bytes = 2 * NITER as u64;
}

// #[bench]
// fn bench_byteio_vec(b: &mut test::Bencher) {
//     use byteio::ReadBytesExt;
//     let vec = vec![0u8; 1_000_000];
//     b.iter(|| {
//         let data = black_box(&vec[..]);
//         for mut val in data.chunks(2) {
//             let _: Result<u16, _> = black_box(val.read_as::<byteio::LittleEndian>());
//         }
//     });
//     b.bytes = vec.len() as u64;
// }

// #[bench]
// fn bench_byteio(b: &mut test::Bencher) {
//     use byteio::ByteOrder;
//     const NITER: i32 = 100_000;
//     b.iter(|| {
//         for _ in 1..NITER {
//             let data = black_box([1, 2]);
//             let _: u16 = black_box(byteio::LittleEndian::from_bytes(data));
//         }
//     });
//     b.bytes = 2 * NITER as u64;
// }
<commit_msg>bench: remove commented code<commit_after>#![feature(test)]
extern crate test;
extern crate byteorder;
extern crate scroll;
extern crate rayon;
//extern crate byteio;

use scroll::{Cread, Cwrite, Pread, Pwrite, IOread, IOwrite, LE};
use test::black_box;

#[bench]
fn bench_parallel_cread_with(b: &mut test::Bencher) {
    use rayon::prelude::*;
    let vec = vec![0u8; 1_000_000];
    let nums = vec![0usize; 500_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        nums.par_iter().for_each(| offset | {
            let _: u16 = black_box(data.cread_with(*offset, LE));
        });
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_cread_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: u16 = black_box(val.cread_with(0, LE));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_cread(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.cread(0));
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_ctx_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread(0));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_with_unwrap(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data: &[u8] = &black_box([1, 2]);
            let _: u16 = black_box(data.pread_with(0, LE).unwrap());
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_pread_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.pread_with(0, LE));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_pread_unwrap(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(data.pread(0)).unwrap();
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_gread_vec(b: &mut test::Bencher) {
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for val in data.chunks(2) {
            let mut offset = 0;
            let _: Result<u16, _> = black_box(val.gread(&mut offset));
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_gread_unwrap(b: &mut test::Bencher) {
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let mut offset = 0;
            let _: u16 = black_box(data.gread_with(&mut offset, LE).unwrap());
        }
    });
    b.bytes = 2 * NITER as u64;
}

#[bench]
fn bench_parallel_pread_with(b: &mut test::Bencher) {
    use rayon::prelude::*;
    let vec = vec![0u8; 1_000_000];
    let nums = vec![0usize; 500_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        nums.par_iter().for_each(| offset | {
            let _: Result<u16, _> = black_box(data.pread_with(*offset, LE));
        });
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteorder_vec(b: &mut test::Bencher) {
    use byteorder::ReadBytesExt;
    let vec = vec![0u8; 1_000_000];
    b.iter(|| {
        let data = black_box(&vec[..]);
        for mut val in data.chunks(2) {
            let _: Result<u16, _> = black_box(val.read_u16::<byteorder::LittleEndian>());
        }
    });
    b.bytes = vec.len() as u64;
}

#[bench]
fn bench_byteorder(b: &mut test::Bencher) {
    use byteorder::ByteOrder;
    const NITER: i32 = 100_000;
    b.iter(|| {
        for _ in 1..NITER {
            let data = black_box([1, 2]);
            let _: u16 = black_box(byteorder::LittleEndian::read_u16(&data));
        }
    });
    b.bytes = 2 * NITER as u64;
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "i128", feature(i128_type, i128))]
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
#![feature(test)]
#![allow(non_snake_case)]

extern crate itoa;
extern crate test;

macro_rules! benches {
    (
        $(
            $(#[$attr:meta])*
            $name:ident($value:expr)
        ),*
    ) => {
        mod bench_itoa_write {
            use test::{Bencher, black_box};
            $(
                $(#[$attr])*
                #[bench]
                fn $name(b: &mut Bencher) {
                    use itoa;

                    let mut buf = Vec::with_capacity(40);

                    b.iter(|| {
                        buf.clear();
                        itoa::write(&mut buf, black_box($value)).unwrap()
                    });
                }
            )*
        }

        mod bench_itoa_fmt {
            use test::{Bencher, black_box};
            $(
                $(#[$attr])*
                #[bench]
                fn $name(b: &mut Bencher) {
                    use itoa;

                    let mut buf = String::with_capacity(40);

                    b.iter(|| {
                        buf.clear();
                        itoa::fmt(&mut buf, black_box($value)).unwrap()
                    });
                }
            )*
        }

        mod bench_std_fmt {
            use test::{Bencher, black_box};
            $(
                $(#[$attr])*
                #[bench]
                fn $name(b: &mut Bencher) {
                    use std::io::Write;

                    let mut buf = Vec::with_capacity(40);

                    b.iter(|| {
                        buf.clear();
                        write!(&mut buf, "{}", black_box($value)).unwrap()
                    });
                }
            )*
        }
    }
}

benches!{
    bench_u64_0(0u64),
    bench_u64_half(<u32>::max_value() as u64),
    bench_u64_max(<u64>::max_value()),

    bench_i16_0(0i16),
    bench_i16_min(<i16>::min_value()),

    #[cfg(feature = "i128")]
    bench_u128_0(0u128),
    #[cfg(feature = "i128")]
    bench_u128_max(<u128>::max_value())
}
<commit_msg>Remove nightly flags from benchmark<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
#![feature(test)]
#![allow(non_snake_case)]

extern crate itoa;
extern crate test;

macro_rules! benches {
    (
        $(
            $(#[$attr:meta])*
            $name:ident($value:expr)
        ),*
    ) => {
        mod bench_itoa_write {
            use test::{Bencher, black_box};
            $(
                $(#[$attr])*
                #[bench]
                fn $name(b: &mut Bencher) {
                    use itoa;

                    let mut buf = Vec::with_capacity(40);

                    b.iter(|| {
                        buf.clear();
                        itoa::write(&mut buf, black_box($value)).unwrap()
                    });
                }
            )*
        }

        mod bench_itoa_fmt {
            use test::{Bencher, black_box};
            $(
                $(#[$attr])*
                #[bench]
                fn $name(b: &mut Bencher) {
                    use itoa;

                    let mut buf = String::with_capacity(40);

                    b.iter(|| {
                        buf.clear();
                        itoa::fmt(&mut buf, black_box($value)).unwrap()
                    });
                }
            )*
        }

        mod bench_std_fmt {
            use test::{Bencher, black_box};
            $(
                $(#[$attr])*
                #[bench]
                fn $name(b: &mut Bencher) {
                    use std::io::Write;

                    let mut buf = Vec::with_capacity(40);

                    b.iter(|| {
                        buf.clear();
                        write!(&mut buf, "{}", black_box($value)).unwrap()
                    });
                }
            )*
        }
    }
}

benches!{
    bench_u64_0(0u64),
    bench_u64_half(<u32>::max_value() as u64),
    bench_u64_max(<u64>::max_value()),

    bench_i16_0(0i16),
    bench_i16_min(<i16>::min_value()),

    #[cfg(feature = "i128")]
    bench_u128_0(0u128),
    #[cfg(feature = "i128")]
    bench_u128_max(<u128>::max_value())
}
<|endoftext|>


<commit_before>// This benchmark suite contains some benchmarks along a set of dimensions:
//   Hasher: std default (SipHash) and crate default (AHash).
//   Int key distribution: low bit heavy, top bit heavy, and random.
//   Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter
#![feature(test)]

extern crate test;

use test::{black_box, Bencher};

use hashbrown::hash_map::DefaultHashBuilder;
use hashbrown::HashMap;
use std::collections::hash_map::RandomState;

const SIZE: usize = 1000;

// The default hashmap when using this crate directly.
type AHashMap<K, V> = HashMap<K, V, DefaultHashBuilder>;
// This uses the hashmap from this crate with the default hasher of the stdlib.
type StdHashMap<K, V> = HashMap<K, V, RandomState>;

// A random key iterator.
#[derive(Clone, Copy)]
struct RandomKeys {
    state: usize,
}

impl RandomKeys {
    fn new() -> Self {
        RandomKeys { state: 0 }
    }
}

impl Iterator for RandomKeys {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        // Add 1 then multiply by some 32 bit prime.
        self.state = self.state.wrapping_add(1).wrapping_mul(3787392781);
        Some(self.state)
    }
}

macro_rules! bench_suite {
    ($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident,
     $bench_ahash_highbits:ident, $bench_std_highbits:ident,
     $bench_ahash_random:ident, $bench_std_random:ident) => {
        $bench_macro!($bench_ahash_serial, AHashMap, 0..);
        $bench_macro!($bench_std_serial, StdHashMap, 0..);
        $bench_macro!(
            $bench_ahash_highbits,
            AHashMap,
            (0..).map(usize::swap_bytes)
        );
        $bench_macro!(
            $bench_std_highbits,
            StdHashMap,
            (0..).map(usize::swap_bytes)
        );
        $bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new());
        $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new());
    };
}

macro_rules! bench_insert {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default());
            b.iter(|| {
                m.clear();
                for i in ($keydist).take(SIZE) {
                    m.insert(i, i);
                }
                black_box(&mut m);
            })
        }
    };
}

bench_suite!(
    bench_insert,
    insert_ahash_serial,
    insert_std_serial,
    insert_ahash_highbits,
    insert_std_highbits,
    insert_ahash_random,
    insert_std_random
);

macro_rules! bench_insert_erase {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut base = $maptype::default();
            for i in ($keydist).take(SIZE) {
                base.insert(i, i);
            }
            let skip = $keydist.skip(SIZE);
            b.iter(|| {
                let mut m = base.clone();
                let mut add_iter = skip.clone();
                let mut remove_iter = $keydist;
                // While keeping the size constant,
                // replace the first keydist with the second.
                for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) {
                    m.insert(add, add);
                    black_box(m.remove(&remove));
                }
                black_box(m);
            })
        }
    };
}

bench_suite!(
    bench_insert_erase,
    insert_erase_ahash_serial,
    insert_erase_std_serial,
    insert_erase_ahash_highbits,
    insert_erase_std_highbits,
    insert_erase_ahash_random,
    insert_erase_std_random
);

macro_rules! bench_lookup {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in $keydist.take(SIZE) {
                m.insert(i, i);
            }

            b.iter(|| {
                for i in $keydist.take(SIZE) {
                    black_box(m.get(&i));
                }
            })
        }
    };
}

bench_suite!(
    bench_lookup,
    lookup_ahash_serial,
    lookup_std_serial,
    lookup_ahash_highbits,
    lookup_std_highbits,
    lookup_ahash_random,
    lookup_std_random
);

macro_rules! bench_lookup_fail {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            let mut iter = $keydist;
            for i in (&mut iter).take(SIZE) {
                m.insert(i, i);
            }

            b.iter(|| {
                for i in (&mut iter).take(SIZE) {
                    black_box(m.get(&i));
                }
            })
        }
    };
}

bench_suite!(
    bench_lookup_fail,
    lookup_fail_ahash_serial,
    lookup_fail_std_serial,
    lookup_fail_ahash_highbits,
    lookup_fail_std_highbits,
    lookup_fail_ahash_random,
    lookup_fail_std_random
);

macro_rules! bench_iter {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in ($keydist).take(SIZE) {
                m.insert(i, i);
            }

            b.iter(|| {
                for i in &m {
                    black_box(i);
                }
            })
        }
    };
}

bench_suite!(
    bench_iter,
    iter_ahash_serial,
    iter_std_serial,
    iter_ahash_highbits,
    iter_std_highbits,
    iter_ahash_random,
    iter_std_random
);

#[bench]
fn clone_small(b: &mut Bencher) {
    let mut m = HashMap::new();
    for i in 0..10 {
        m.insert(i, i);
    }

    b.iter(|| {
        black_box(m.clone());
    })
}

#[bench]
fn clone_from_small(b: &mut Bencher) {
    let mut m = HashMap::new();
    let mut m2 = HashMap::new();
    for i in 0..10 {
        m.insert(i, i);
    }

    b.iter(|| {
        m2.clone_from(&m);
        black_box(&mut m2);
    })
}

#[bench]
fn clone_large(b: &mut Bencher) {
    let mut m = HashMap::new();
    for i in 0..1000 {
        m.insert(i, i);
    }

    b.iter(|| {
        black_box(m.clone());
    })
}

#[bench]
fn clone_from_large(b: &mut Bencher) {
    let mut m = HashMap::new();
    let mut m2 = HashMap::new();
    for i in 0..1000 {
        m.insert(i, i);
    }

    b.iter(|| {
        m2.clone_from(&m);
        black_box(&mut m2);
    })
}
<commit_msg>Include dropping behaviour in bench<commit_after>// This benchmark suite contains some benchmarks along a set of dimensions:
//   Hasher: std default (SipHash) and crate default (AHash).
//   Int key distribution: low bit heavy, top bit heavy, and random.
//   Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter
#![feature(test)]

extern crate test;

use test::{black_box, Bencher};

use hashbrown::hash_map::DefaultHashBuilder;
use hashbrown::HashMap;
use std::{
    collections::hash_map::RandomState,
    sync::atomic::{self, AtomicUsize},
};

const SIZE: usize = 1000;

// The default hashmap when using this crate directly.
type AHashMap<K, V> = HashMap<K, V, DefaultHashBuilder>;
// This uses the hashmap from this crate with the default hasher of the stdlib.
type StdHashMap<K, V> = HashMap<K, V, RandomState>;

// A random key iterator.
#[derive(Clone, Copy)]
struct RandomKeys {
    state: usize,
}

impl RandomKeys {
    fn new() -> Self {
        RandomKeys { state: 0 }
    }
}

impl Iterator for RandomKeys {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        // Add 1 then multiply by some 32 bit prime.
        self.state = self.state.wrapping_add(1).wrapping_mul(3787392781);
        Some(self.state)
    }
}

// Just an arbitrary side effect to
lazy_static::lazy_static! {
    static ref SIDE_EFFECT: AtomicUsize = AtomicUsize::new(0);
}

#[derive(Clone)]
struct DropType(usize);
impl Drop for DropType {
    fn drop(&mut self) {
        SIDE_EFFECT.fetch_add(self.0, atomic::Ordering::SeqCst);
    }
}

macro_rules! bench_suite {
    ($bench_macro:ident, $bench_ahash_serial:ident, $bench_std_serial:ident,
     $bench_ahash_highbits:ident, $bench_std_highbits:ident,
     $bench_ahash_random:ident, $bench_std_random:ident) => {
        $bench_macro!($bench_ahash_serial, AHashMap, 0..);
        $bench_macro!($bench_std_serial, StdHashMap, 0..);
        $bench_macro!(
            $bench_ahash_highbits,
            AHashMap,
            (0..).map(usize::swap_bytes)
        );
        $bench_macro!(
            $bench_std_highbits,
            StdHashMap,
            (0..).map(usize::swap_bytes)
        );
        $bench_macro!($bench_ahash_random, AHashMap, RandomKeys::new());
        $bench_macro!($bench_std_random, StdHashMap, RandomKeys::new());
    };
}

macro_rules! bench_insert {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::with_capacity_and_hasher(SIZE, Default::default());
            b.iter(|| {
                m.clear();
                for i in ($keydist).take(SIZE) {
                    m.insert(i, DropType(i));
                }
                black_box(&mut m);
            });
            eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst));
        }
    };
}

bench_suite!(
    bench_insert,
    insert_ahash_serial,
    insert_std_serial,
    insert_ahash_highbits,
    insert_std_highbits,
    insert_ahash_random,
    insert_std_random
);

macro_rules! bench_insert_erase {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut base = $maptype::default();
            for i in ($keydist).take(SIZE) {
                base.insert(i, DropType(i));
            }
            let skip = $keydist.skip(SIZE);
            b.iter(|| {
                let mut m = base.clone();
                let mut add_iter = skip.clone();
                let mut remove_iter = $keydist;
                // While keeping the size constant,
                // replace the first keydist with the second.
                for (add, remove) in (&mut add_iter).zip(&mut remove_iter).take(SIZE) {
                    m.insert(add, DropType(add));
                    black_box(m.remove(&remove));
                }
                black_box(m);
            });
            eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst));
        }
    };
}

bench_suite!(
    bench_insert_erase,
    insert_erase_ahash_serial,
    insert_erase_std_serial,
    insert_erase_ahash_highbits,
    insert_erase_std_highbits,
    insert_erase_ahash_random,
    insert_erase_std_random
);

macro_rules! bench_lookup {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in $keydist.take(SIZE) {
                m.insert(i, DropType(i));
            }

            b.iter(|| {
                for i in $keydist.take(SIZE) {
                    black_box(m.get(&i));
                }
            });
            eprintln!("{}", SIDE_EFFECT.load(atomic::Ordering::SeqCst));
        }
    };
}

bench_suite!(
    bench_lookup,
    lookup_ahash_serial,
    lookup_std_serial,
    lookup_ahash_highbits,
    lookup_std_highbits,
    lookup_ahash_random,
    lookup_std_random
);

macro_rules! bench_lookup_fail {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            let mut iter = $keydist;
            for i in (&mut iter).take(SIZE) {
                m.insert(i, DropType(i));
            }

            b.iter(|| {
                for i in (&mut iter).take(SIZE) {
                    black_box(m.get(&i));
                }
            })
        }
    };
}

bench_suite!(
    bench_lookup_fail,
    lookup_fail_ahash_serial,
    lookup_fail_std_serial,
    lookup_fail_ahash_highbits,
    lookup_fail_std_highbits,
    lookup_fail_ahash_random,
    lookup_fail_std_random
);

macro_rules! bench_iter {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in ($keydist).take(SIZE) {
                m.insert(i, DropType(i));
            }

            b.iter(|| {
                for i in &m {
                    black_box(i);
                }
            })
        }
    };
}

bench_suite!(
    bench_iter,
    iter_ahash_serial,
    iter_std_serial,
    iter_ahash_highbits,
    iter_std_highbits,
    iter_ahash_random,
    iter_std_random
);

#[bench]
fn clone_small(b: &mut Bencher) {
    let mut m = HashMap::new();
    for i in 0..10 {
        m.insert(i, DropType(i));
    }

    b.iter(|| {
        black_box(m.clone());
    })
}

#[bench]
fn clone_from_small(b: &mut Bencher) {
    let mut m = HashMap::new();
    let mut m2 = HashMap::new();
    for i in 0..10 {
        m.insert(i, DropType(i));
    }

    b.iter(|| {
        m2.clone_from(&m);
        black_box(&mut m2);
    })
}

#[bench]
fn clone_large(b: &mut Bencher) {
    let mut m = HashMap::new();
    for i in 0..1000 {
        m.insert(i, DropType(i));
    }

    b.iter(|| {
        black_box(m.clone());
    })
}

#[bench]
fn clone_from_large(b: &mut Bencher) {
    let mut m = HashMap::new();
    let mut m2 = HashMap::new();
    for i in 0..1000 {
        m.insert(i, DropType(i));
    }

    b.iter(|| {
        m2.clone_from(&m);
        black_box(&mut m2);
    })
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

mod memory_usage;
#[cfg(feature = "cpu_profiler")]
mod google_cpu_profiler;

use std::{
    cell::RefCell,
    collections::HashSet,
    io::{stderr, Write},
    iter::repeat,
    mem,
    sync::{
        atomic::{AtomicBool, Ordering},
        RwLock,
    },
    time::{Duration, Instant},
};

use itertools::Itertools;
use once_cell::sync::Lazy;

pub use crate::memory_usage::{Bytes, MemoryUsage};

// We use jemalloc mainly to get heap usage statistics, actual performance
// difference is not measures.
#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

/// Set profiling filter. It specifies descriptions allowed to profile.
/// This is helpful when call stack has too many nested profiling scopes.
/// Additionally filter can specify maximum depth of profiling scopes nesting.
///
/// #Example
/// ```
/// use ra_prof::{set_filter, Filter};
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// ```
pub fn set_filter(f: Filter) {
    PROFILING_ENABLED.store(f.depth > 0, Ordering::SeqCst);
    let set: HashSet<_> = f.allowed.iter().cloned().collect();
    let mut old = FILTER.write().unwrap();
    let filter_data = FilterData {
        depth: f.depth,
        allowed: set,
        longer_than: f.longer_than,
        version: old.version + 1,
    };
    *old = filter_data;
}

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// # Example
/// ```
/// use ra_prof::{profile, set_filter, Filter};
///
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
pub fn profile(desc: &str) -> Profiler {
    assert!(!desc.is_empty());
    if !PROFILING_ENABLED.load(Ordering::Relaxed) {
        return Profiler { desc: None };
    }

    PROFILE_STACK.with(|stack| {
        let mut stack = stack.borrow_mut();
        if stack.starts.is_empty() {
            if let Ok(f) = FILTER.try_read() {
                if f.version > stack.filter_data.version {
                    stack.filter_data = f.clone();
                }
            };
        }
        if stack.starts.len() > stack.filter_data.depth {
            return Profiler { desc: None };
        }
        let allowed = &stack.filter_data.allowed;
        if stack.starts.is_empty() && !allowed.is_empty() && !allowed.contains(desc) {
            return Profiler { desc: None };
        }

        stack.starts.push(Instant::now());
        Profiler { desc: Some(desc.to_string()) }
    })
}

pub struct Profiler {
    desc: Option<String>,
}

pub struct Filter {
    depth: usize,
    allowed: Vec<String>,
    longer_than: Duration,
}

impl Filter {
    // Filtering syntax
    // env RA_PROFILE=*             // dump everything
    // env RA_PROFILE=foo|bar|baz   // enabled only selected entries
    // env RA_PROFILE=*@3>10        // dump everything, up to depth 3, if it takes more than 10 ms
    pub fn from_spec(mut spec: &str) -> Filter {
        let longer_than = if let Some(idx) = spec.rfind('>') {
            let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
            spec = &spec[..idx];
            Duration::from_millis(longer_than)
        } else {
            Duration::new(0, 0)
        };

        let depth = if let Some(idx) = spec.rfind('@') {
            let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
            spec = &spec[..idx];
            depth
        } else {
            999
        };
        let allowed =
            if spec == "*" { Vec::new() } else { spec.split('|').map(String::from).collect() };
        Filter::new(depth, allowed, longer_than)
    }

    pub fn disabled() -> Filter {
        Filter::new(0, Vec::new(), Duration::new(0, 0))
    }

    pub fn new(depth: usize, allowed: Vec<String>, longer_than: Duration) -> Filter {
        Filter { depth, allowed, longer_than }
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    messages: Vec<Message>,
    filter_data: FilterData,
}

struct Message {
    level: usize,
    duration: Duration,
    message: String,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
    }
}

#[derive(Default, Clone)]
struct FilterData {
    depth: usize,
    version: usize,
    allowed: HashSet<String>,
    longer_than: Duration,
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);

static FILTER: Lazy<RwLock<FilterData>> = Lazy::new(Default::default);

thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { desc: Some(desc) } => {
                PROFILE_STACK.with(|stack| {
                    let mut stack = stack.borrow_mut();
                    let start = stack.starts.pop().unwrap();
                    let duration = start.elapsed();
                    let level = stack.starts.len();
                    let message = mem::replace(desc, String::new());
                    stack.messages.push(Message { level, duration, message });
                    if level == 0 {
                        let stdout = stderr();
                        let longer_than = stack.filter_data.longer_than;
                        if duration >= longer_than {
                            print(0, &stack.messages, &mut stdout.lock(), longer_than, None);
                        }
                        stack.messages.clear();
                    }
                });
            }
            Profiler { desc: None } => (),
        }
    }
}

fn print(
    lvl: usize,
    msgs: &[Message],
    out: &mut impl Write,
    longer_than: Duration,
    total: Option<Duration>,
) {
    let mut last = 0;
    let indent = repeat("    ").take(lvl).collect::<String>();
    // We output hierarchy for long calls, but sum up all short calls
    let mut short = Vec::new();
    let mut accounted_for = Duration::default();
    for (i, &Message { level, duration, message: ref msg }) in msgs.iter().enumerate() {
        if level != lvl {
            continue;
        }
        accounted_for += duration;
        if duration >= longer_than {
            writeln!(out, "{}{:5}ms - {}", indent, duration.as_millis(), msg)
                .expect("printing profiling info to stdout");

            print(lvl + 1, &msgs[last..i], out, longer_than, Some(duration));
        } else {
            short.push((msg, duration))
        }

        last = i;
    }
    short.sort_by_key(|(msg, _time)| *msg);
    for (msg, entires) in short.iter().group_by(|(msg, _time)| msg).into_iter() {
        let mut count = 0;
        let mut total_duration = Duration::default();
        entires.for_each(|(_msg, time)| {
            count += 1;
            total_duration += *time;
        });
        writeln!(out, "{}{:5}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
            .expect("printing profiling info to stdout");
    }

    if let Some(total) = total {
        if let Some(unaccounted) = total.checked_sub(accounted_for) {
            if unaccounted >= longer_than && last > 0 {
                writeln!(out, "{}{:5}ms - ???", indent, unaccounted.as_millis())
                    .expect("printing profiling info to stdout");
            }
        }
    }
}

/// Prints backtrace to stderr, useful for debugging.
pub fn print_backtrace() {
    let bt = backtrace::Backtrace::new();
    eprintln!("{:?}", bt);
}

thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false));

/// Allows to check if the current code is withing some dynamic scope, can be
/// useful during debugging to figure out why a function is called.
pub struct Scope {
    prev: bool,
}

impl Scope {
    pub fn enter() -> Scope {
        let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true));
        Scope { prev }
    }
    pub fn is_active() -> bool {
        IN_SCOPE.with(|slot| *slot.borrow())
    }
}

impl Drop for Scope {
    fn drop(&mut self) {
        IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev);
    }
}

/// A wrapper around google_cpu_profiler.
///
/// Usage:
/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro.
/// 2. Build with `cpu_profiler` feature.
/// 3. Tun the code, the *raw* output would be in the `./out.profile` file.
/// 4. Install pprof for visualization (https://github.com/google/pprof).
/// 5. Use something like `pprof -svg target/release/ra_cli ./out.profile` to see the results.
///
/// For example, here's how I run profiling on NixOS:
///
/// ```bash
/// $ nix-shell -p gperftools --run \
///     'cargo run --release -p ra_cli -- parse < ~/projects/rustbench/parser.rs > /dev/null'
/// ```
#[derive(Debug)]
pub struct CpuProfiler {
    _private: (),
}

pub fn cpu_profiler() -> CpuProfiler {
    #[cfg(feature = "cpu_profiler")]
    {
        google_cpu_profiler::start("./out.profile".as_ref())
    }

    #[cfg(not(feature = "cpu_profiler"))]
    {
        eprintln!("cpu_profiler feature is disabled")
    }

    CpuProfiler { _private: () }
}

impl Drop for CpuProfiler {
    fn drop(&mut self) {
        #[cfg(feature = "cpu_profiler")]
        {
            google_cpu_profiler::stop()
        }
    }
}

pub fn memory_usage() -> MemoryUsage {
    MemoryUsage::current()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_profile() {
        let s = vec!["profile1".to_string(), "profile2".to_string()];
        let f = Filter::new(2, s, Duration::new(0, 0));
        set_filter(f);
        profiling_function1();
    }

    fn profiling_function1() {
        let _p = profile("profile1");
        profiling_function2();
    }

    fn profiling_function2() {
        let _p = profile("profile2");
    }
}
<commit_msg>Improve profiling output when duration filter is specified<commit_after>//! FIXME: write short doc here

mod memory_usage;
#[cfg(feature = "cpu_profiler")]
mod google_cpu_profiler;

use std::{
    cell::RefCell,
    collections::HashSet,
    io::{stderr, Write},
    iter::repeat,
    mem,
    sync::{
        atomic::{AtomicBool, Ordering},
        RwLock,
    },
    time::{Duration, Instant},
};

use itertools::Itertools;
use once_cell::sync::Lazy;

pub use crate::memory_usage::{Bytes, MemoryUsage};

// We use jemalloc mainly to get heap usage statistics, actual performance
// difference is not measures.
#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

/// Set profiling filter. It specifies descriptions allowed to profile.
/// This is helpful when call stack has too many nested profiling scopes.
/// Additionally filter can specify maximum depth of profiling scopes nesting.
///
/// #Example
/// ```
/// use ra_prof::{set_filter, Filter};
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// ```
pub fn set_filter(f: Filter) {
    PROFILING_ENABLED.store(f.depth > 0, Ordering::SeqCst);
    let set: HashSet<_> = f.allowed.iter().cloned().collect();
    let mut old = FILTER.write().unwrap();
    let filter_data = FilterData {
        depth: f.depth,
        allowed: set,
        longer_than: f.longer_than,
        version: old.version + 1,
    };
    *old = filter_data;
}

/// This function starts a profiling scope in the current execution stack with a given description.
/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop.
/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output.
/// Profiling information is being printed in the stderr.
///
/// # Example
/// ```
/// use ra_prof::{profile, set_filter, Filter};
///
/// let f = Filter::from_spec("profile1|profile2@2");
/// set_filter(f);
/// profiling_function1();
///
/// fn profiling_function1() {
///     let _p = profile("profile1");
///     profiling_function2();
/// }
///
/// fn profiling_function2() {
///     let _p = profile("profile2");
/// }
/// ```
/// This will print in the stderr the following:
/// ```text
///  0ms - profile
///      0ms - profile2
/// ```
pub fn profile(desc: &str) -> Profiler {
    assert!(!desc.is_empty());
    if !PROFILING_ENABLED.load(Ordering::Relaxed) {
        return Profiler { desc: None };
    }

    PROFILE_STACK.with(|stack| {
        let mut stack = stack.borrow_mut();
        if stack.starts.is_empty() {
            if let Ok(f) = FILTER.try_read() {
                if f.version > stack.filter_data.version {
                    stack.filter_data = f.clone();
                }
            };
        }
        if stack.starts.len() > stack.filter_data.depth {
            return Profiler { desc: None };
        }
        let allowed = &stack.filter_data.allowed;
        if stack.starts.is_empty() && !allowed.is_empty() && !allowed.contains(desc) {
            return Profiler { desc: None };
        }

        stack.starts.push(Instant::now());
        Profiler { desc: Some(desc.to_string()) }
    })
}

pub struct Profiler {
    desc: Option<String>,
}

pub struct Filter {
    depth: usize,
    allowed: Vec<String>,
    longer_than: Duration,
}

impl Filter {
    // Filtering syntax
    // env RA_PROFILE=*             // dump everything
    // env RA_PROFILE=foo|bar|baz   // enabled only selected entries
    // env RA_PROFILE=*@3>10        // dump everything, up to depth 3, if it takes more than 10 ms
    pub fn from_spec(mut spec: &str) -> Filter {
        let longer_than = if let Some(idx) = spec.rfind('>') {
            let longer_than = spec[idx + 1..].parse().expect("invalid profile longer_than");
            spec = &spec[..idx];
            Duration::from_millis(longer_than)
        } else {
            Duration::new(0, 0)
        };

        let depth = if let Some(idx) = spec.rfind('@') {
            let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
            spec = &spec[..idx];
            depth
        } else {
            999
        };
        let allowed =
            if spec == "*" { Vec::new() } else { spec.split('|').map(String::from).collect() };
        Filter::new(depth, allowed, longer_than)
    }

    pub fn disabled() -> Filter {
        Filter::new(0, Vec::new(), Duration::new(0, 0))
    }

    pub fn new(depth: usize, allowed: Vec<String>, longer_than: Duration) -> Filter {
        Filter { depth, allowed, longer_than }
    }
}

struct ProfileStack {
    starts: Vec<Instant>,
    messages: Vec<Message>,
    filter_data: FilterData,
}

struct Message {
    level: usize,
    duration: Duration,
    message: String,
}

impl ProfileStack {
    fn new() -> ProfileStack {
        ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
    }
}

#[derive(Default, Clone)]
struct FilterData {
    depth: usize,
    version: usize,
    allowed: HashSet<String>,
    longer_than: Duration,
}

static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);

static FILTER: Lazy<RwLock<FilterData>> = Lazy::new(Default::default);

thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));

impl Drop for Profiler {
    fn drop(&mut self) {
        match self {
            Profiler { desc: Some(desc) } => {
                PROFILE_STACK.with(|stack| {
                    let mut stack = stack.borrow_mut();
                    let start = stack.starts.pop().unwrap();
                    let duration = start.elapsed();
                    let level = stack.starts.len();
                    let message = mem::replace(desc, String::new());
                    stack.messages.push(Message { level, duration, message });
                    if level == 0 {
                        let stdout = stderr();
                        let longer_than = stack.filter_data.longer_than;
                        // Convert to millis for comparison to avoid problems with rounding
                        // (otherwise we could print `0ms` despite user's `>0` filter when
                        // `duration` is just a few nanos).
                        if duration.as_millis() > longer_than.as_millis() {
                            print(0, &stack.messages, &mut stdout.lock(), longer_than, None);
                        }
                        stack.messages.clear();
                    }
                });
            }
            Profiler { desc: None } => (),
        }
    }
}

fn print(
    lvl: usize,
    msgs: &[Message],
    out: &mut impl Write,
    longer_than: Duration,
    total: Option<Duration>,
) {
    let mut last = 0;
    let indent = repeat("    ").take(lvl).collect::<String>();
    // We output hierarchy for long calls, but sum up all short calls
    let mut short = Vec::new();
    let mut accounted_for = Duration::default();
    for (i, &Message { level, duration, message: ref msg }) in msgs.iter().enumerate() {
        if level != lvl {
            continue;
        }
        accounted_for += duration;
        if duration.as_millis() > longer_than.as_millis() {
            writeln!(out, "{}{:5}ms - {}", indent, duration.as_millis(), msg)
                .expect("printing profiling info to stdout");

            print(lvl + 1, &msgs[last..i], out, longer_than, Some(duration));
        } else {
            short.push((msg, duration))
        }

        last = i;
    }
    short.sort_by_key(|(msg, _time)| *msg);
    for (msg, entires) in short.iter().group_by(|(msg, _time)| msg).into_iter() {
        let mut count = 0;
        let mut total_duration = Duration::default();
        entires.for_each(|(_msg, time)| {
            count += 1;
            total_duration += *time;
        });
        writeln!(out, "{}{:5}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
            .expect("printing profiling info to stdout");
    }

    if let Some(total) = total {
        if let Some(unaccounted) = total.checked_sub(accounted_for) {
            let unaccounted_millis = unaccounted.as_millis();
            if unaccounted_millis > longer_than.as_millis() && unaccounted_millis > 0 && last > 0 {
                writeln!(out, "{}{:5}ms - ???", indent, unaccounted_millis)
                    .expect("printing profiling info to stdout");
            }
        }
    }
}

/// Prints backtrace to stderr, useful for debugging.
pub fn print_backtrace() {
    let bt = backtrace::Backtrace::new();
    eprintln!("{:?}", bt);
}

thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false));

/// Allows to check if the current code is withing some dynamic scope, can be
/// useful during debugging to figure out why a function is called.
pub struct Scope {
    prev: bool,
}

impl Scope {
    pub fn enter() -> Scope {
        let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true));
        Scope { prev }
    }
    pub fn is_active() -> bool {
        IN_SCOPE.with(|slot| *slot.borrow())
    }
}

impl Drop for Scope {
    fn drop(&mut self) {
        IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev);
    }
}

/// A wrapper around google_cpu_profiler.
///
/// Usage:
/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro.
/// 2. Build with `cpu_profiler` feature.
/// 3. Tun the code, the *raw* output would be in the `./out.profile` file.
/// 4. Install pprof for visualization (https://github.com/google/pprof).
/// 5. Use something like `pprof -svg target/release/ra_cli ./out.profile` to see the results.
///
/// For example, here's how I run profiling on NixOS:
///
/// ```bash
/// $ nix-shell -p gperftools --run \
///     'cargo run --release -p ra_cli -- parse < ~/projects/rustbench/parser.rs > /dev/null'
/// ```
#[derive(Debug)]
pub struct CpuProfiler {
    _private: (),
}

pub fn cpu_profiler() -> CpuProfiler {
    #[cfg(feature = "cpu_profiler")]
    {
        google_cpu_profiler::start("./out.profile".as_ref())
    }

    #[cfg(not(feature = "cpu_profiler"))]
    {
        eprintln!("cpu_profiler feature is disabled")
    }

    CpuProfiler { _private: () }
}

impl Drop for CpuProfiler {
    fn drop(&mut self) {
        #[cfg(feature = "cpu_profiler")]
        {
            google_cpu_profiler::stop()
        }
    }
}

pub fn memory_usage() -> MemoryUsage {
    MemoryUsage::current()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_profile() {
        let s = vec!["profile1".to_string(), "profile2".to_string()];
        let f = Filter::new(2, s, Duration::new(0, 0));
        set_filter(f);
        profiling_function1();
    }

    fn profiling_function1() {
        let _p = profile("profile1");
        profiling_function2();
    }

    fn profiling_function2() {
        let _p = profile("profile2");
    }

    #[test]
    fn test_longer_than() {
        let mut result = vec![];
        let msgs = vec![
            Message { level: 1, duration: Duration::from_nanos(3), message: "bar".to_owned() },
            Message { level: 1, duration: Duration::from_nanos(2), message: "bar".to_owned() },
            Message { level: 0, duration: Duration::from_millis(1), message: "foo".to_owned() },
        ];
        print(0, &msgs, &mut result, Duration::from_millis(0), Some(Duration::from_millis(1)));
        // The calls to `bar` are so short that they'll be rounded to 0ms and should get collapsed
        // when printing.
        assert_eq!(
            std::str::from_utf8(&result).unwrap(),
            "    1ms - foo\n        0ms - bar (2 calls)\n"
        );
    }
}
<|endoftext|>


<commit_before>#[cfg(not(feature = "no_std"))]
use std::fmt;

/// A r g b a color.
#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Color {
    pub data: u32,
}

impl Color {
    /// Create a new color from RGB
    pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
        Color {
            data: 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
        }
    }

    /// Set the alpha
    pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
        Color {
            data: ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
        }
    }

    /// Get the r value
    pub fn r(self) -> u8 {
        ((self.data & 0x00FF_0000) >> 16) as u8
    }

    /// Get the g value
    pub fn g(self) -> u8 {
        ((self.data & 0x0000_FF00) >> 8) as u8
    }

    /// Get the b value
    pub fn b(self) -> u8 {
        (self.data & 0x0000_00FF) as u8
    }

    /// Get the alpha value
    pub fn a(self) -> u8 {
        ((self.data & 0xFF00_0000) >> 24) as u8
    }

    /// Interpolate between two colors
    pub fn interpolate(start_color: Color, end_color: Color, scale: f64) -> Color {
        let r = Color::interp(start_color.r(), end_color.r(), scale);
        let g = Color::interp(start_color.g(), end_color.g(), scale);
        let b = Color::interp(start_color.b(), end_color.b(), scale);
        let a = Color::interp(start_color.a(), end_color.a(), scale);
        Color::rgba(r, g, b, a)
    }

    fn interp(start_color: u8, end_color: u8, scale: f64) -> u8 {
        (end_color as f64 - start_color as f64).mul_add(scale, start_color as f64) as u8
    }
}

impl ToString for Color {
    fn to_string(&self) -> String {
        if self.a() == 0 {
            return String::from("transparent");
        }

        let data = self.data;

        let mut color = format!("#{:x}", data);
        color.remove(1);
        color.remove(1);
        color
    }
}

impl From<&str> for Color {
    fn from(s: &str) -> Color {
        let clean_hex = s.trim_start_matches('#');
        match clean_hex.len() {
            6 | 8 => {
                let mut x = match u32::from_str_radix(&clean_hex, 16) {
                    Ok(x) => x,
                    Err(_) => 0,
                };

                if clean_hex.len() == 6 {
                    x |= 0xFF_000_000;
                }

                Color { data: x }
            }
            _ => Color { data: 0 },
        }
    }
}

impl From<String> for Color {
    fn from(s: String) -> Color {
        Color::from(s.as_str())
    }
}

/// Compare two colors (Do not take care of alpha)
impl PartialEq for Color {
    fn eq(&self, other: &Color) -> bool {
        self.r() == other.r() && self.g() == other.g() && self.b() == other.b()
    }
}

#[cfg(not(feature = "no_std"))]
impl fmt::Debug for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:#010X}", { self.data })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn partial_eq() {
        assert_eq!(true, Color::rgb(1, 2, 3) == Color::rgba(1, 2, 3, 200));
        assert_eq!(false, Color::rgb(1, 2, 3) == Color::rgba(11, 2, 3, 200));
        assert_eq!(true, Color::rgba(1, 2, 3, 200) == Color::rgba(1, 2, 3, 200));
    }
}
<commit_msg>Fixed docs<commit_after>#[cfg(not(feature = "no_std"))]
use std::fmt;

/// A r g b a color.
#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Color {
    pub data: u32,
}

impl Color {
    /// Create a new color from RGB
    pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
        Color {
            data: 0xFF00_0000 | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
        }
    }

    /// Create a new color from RGB and alpha values
    pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
        Color {
            data: ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32),
        }
    }

    /// Get the r value
    pub fn r(self) -> u8 {
        ((self.data & 0x00FF_0000) >> 16) as u8
    }

    /// Get the g value
    pub fn g(self) -> u8 {
        ((self.data & 0x0000_FF00) >> 8) as u8
    }

    /// Get the b value
    pub fn b(self) -> u8 {
        (self.data & 0x0000_00FF) as u8
    }

    /// Get the alpha value
    pub fn a(self) -> u8 {
        ((self.data & 0xFF00_0000) >> 24) as u8
    }

    /// Interpolate between two colors
    pub fn interpolate(start_color: Color, end_color: Color, scale: f64) -> Color {
        let r = Color::interp(start_color.r(), end_color.r(), scale);
        let g = Color::interp(start_color.g(), end_color.g(), scale);
        let b = Color::interp(start_color.b(), end_color.b(), scale);
        let a = Color::interp(start_color.a(), end_color.a(), scale);
        Color::rgba(r, g, b, a)
    }

    fn interp(start_color: u8, end_color: u8, scale: f64) -> u8 {
        (end_color as f64 - start_color as f64).mul_add(scale, start_color as f64) as u8
    }
}

impl ToString for Color {
    fn to_string(&self) -> String {
        if self.a() == 0 {
            return String::from("transparent");
        }

        let data = self.data;

        let mut color = format!("#{:x}", data);
        color.remove(1);
        color.remove(1);
        color
    }
}

impl From<&str> for Color {
    fn from(s: &str) -> Color {
        let clean_hex = s.trim_start_matches('#');
        match clean_hex.len() {
            6 | 8 => {
                let mut x = match u32::from_str_radix(&clean_hex, 16) {
                    Ok(x) => x,
                    Err(_) => 0,
                };

                if clean_hex.len() == 6 {
                    x |= 0xFF_000_000;
                }

                Color { data: x }
            }
            _ => Color { data: 0 },
        }
    }
}

impl From<String> for Color {
    fn from(s: String) -> Color {
        Color::from(s.as_str())
    }
}

/// Compares two colors (the alpha value is ignored)
impl PartialEq for Color {
    fn eq(&self, other: &Color) -> bool {
        self.r() == other.r() && self.g() == other.g() && self.b() == other.b()
    }
}

#[cfg(not(feature = "no_std"))]
impl fmt::Debug for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:#010X}", { self.data })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn partial_eq() {
        assert_eq!(true, Color::rgb(1, 2, 3) == Color::rgba(1, 2, 3, 200));
        assert_eq!(false, Color::rgb(1, 2, 3) == Color::rgba(11, 2, 3, 200));
        assert_eq!(true, Color::rgba(1, 2, 3, 200) == Color::rgba(1, 2, 3, 200));
    }
}
<|endoftext|>


<commit_before>// force-host

#![feature(plugin_registrar)]
#![feature(box_syntax, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use std::borrow::ToOwned;
use syntax::ast;
use syntax::ext::hygiene;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use syntax::tokenstream::TokenStream;
use rustc_plugin::Registry;

struct Expander {
    args: Vec<ast::NestedMetaItem>,
}

impl TTMacroExpander for Expander {
    fn expand<'cx>(&self,
                   ecx: &'cx mut ExtCtxt,
                   sp: Span,
                   _: TokenStream,
                   _: Option<Span>) -> Box<MacResult+'cx> {
        let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
            .collect::<Vec<_>>().join(", ");
        MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let args = reg.args().to_owned();
    reg.register_syntax_extension(Symbol::intern("plugin_args"),
        NormalTT {
            expander: Box::new(Expander { args: args, }),
            def_info: None,
            allow_internal_unstable: false,
            allow_internal_unsafe: false,
            local_inner_macros: false,
            unstable_feature: None,
            edition: hygiene::default_edition(),
        });
}
<commit_msg>Update fulldeps test<commit_after>// force-host

#![feature(plugin_registrar)]
#![feature(box_syntax, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use std::borrow::ToOwned;
use syntax::ast;
use syntax::ext::hygiene;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use syntax::tokenstream::TokenStream;
use rustc_plugin::Registry;

struct Expander {
    args: Vec<ast::NestedMetaItem>,
}

impl TTMacroExpander for Expander {
    fn expand<'cx>(&self,
                   ecx: &'cx mut ExtCtxt,
                   sp: Span,
                   _: TokenStream,
                   _: Option<Span>) -> Box<MacResult+'cx> {
        let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
            .collect::<Vec<_>>().join(", ");
        MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let args = reg.args().to_owned();
    reg.register_syntax_extension(Symbol::intern("plugin_args"),
        NormalTT {
            expander: Box::new(Expander { args: args, }),
            def_info: None,
            allow_internal_unstable: Vec::new(),
            allow_internal_unsafe: false,
            local_inner_macros: false,
            unstable_feature: None,
            edition: hygiene::default_edition(),
        });
}
<|endoftext|>


<commit_before>extern crate num_traits;

use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::{self, Display, Formatter};
use std::hash::Hash;
use std::iter::FromIterator;
use std::vec::Vec;
use self::num_traits::One;
use recognisable::Transition;
use pmcfg::{PMCFG, PMCFGRule, VarT};
use tree_stack_automaton::{TreeStack, TreeStackAutomaton, TreeStackInstruction};

// types for analysis of derivation trees of PMCFGs
pub type RuleCallerMap<N, T, W> = BTreeMap<PMCFGRule<N, T, W>, Vec<(usize, Vec<T>)>>;
pub type DerivationSnippet<N, T, W> = (PMCFGRule<N, T, W>, Vec<Vec<PMCFGRule<N, T, W>>>);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum PosState<X> {
    Designated,
    Initial,
    Position(X, usize, usize),
}

impl<X> PosState<X> {
    pub fn map<F, Y>(&self, f: F) -> PosState<Y>
        where F: Fn(&X) -> Y,
    {
        match *self {
            PosState::Designated => PosState::Designated,
            PosState::Initial => PosState::Initial,
            PosState::Position(ref x, i, j) => PosState::Position(f(x), i, j),
        }
    }
}

impl<X: Display> Display for PosState<X> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            PosState::Designated
                => write!(f, "@"),
            PosState::Initial
                => write!(f, "I"),
            PosState::Position(ref x, i, j)
                => write!(f, "({}, {}, {})", x, i, j)
        }
    }
}

// TODO assumes that the PMCFG is monotonic on the visit-order of components
impl<N: Clone + Ord + PartialEq + Hash,
     T: Clone + Ord + PartialEq + Hash,
     W: Clone + Ord + PartialEq + One
     > From<PMCFG<N, T, W>> for TreeStackAutomaton<PosState<PMCFGRule<N, T, W>>, T, W> {
    fn from(g: PMCFG<N, T, W>) -> Self {
        let mut transitions = Vec::new();

        let mut rule_map: BTreeMap<N, Vec<PMCFGRule<N, T, W>>>
            = BTreeSet::from_iter(
                g.rules
                    .iter()
                    .map(|r| r.head.clone())
            )
            .iter()
            .map(|n| (
                n.clone(),
                Vec::<PMCFGRule<N, T, W>>::new()
            ))
            .collect();

        let mut down_info: RuleCallerMap<N, T, W>
            = BTreeMap::new();

        let mut initial_rules: Vec<PMCFGRule<N, T, W>>
            = Vec::new();

        for r in g.rules.clone() {
            if g.initial.contains(&r.head) {
                initial_rules.push(r.clone())
            }
            rule_map.get_mut(&r.head).unwrap().push(r.clone());

            let mut var_cnt_vec = Vec::new();
            let mut i: usize;
            let mut down_buffer: Vec<T> = Vec::new();
            for component in &r.composition.composition {
                i = 0;
                for ntt in component {
                    down_buffer.clear();
                    match *ntt {
                        VarT::Var(_, _)
                            => {
                                i += 1;
                                down_buffer.clear();
                            },
                        VarT::T(ref t)
                            => {
                                down_buffer.push(t.clone());
                            }
                    }
                }
                var_cnt_vec.push((i, down_buffer.clone()));
            }
            down_info.insert(r.clone(), var_cnt_vec);
        }

        for r in initial_rules {
            transitions.push(
                Transition {
                    word: Vec::new(),
                    weight: r.weight.clone(),
                    instruction: TreeStackInstruction::Push {
                        n: 0,
                        current_val: PosState::Initial,
                        new_val: PosState::Position(r.clone(), 0, 0)
                    }
                }
            );

            match down_info[&r][0] {
                (j, ref word) => {
                    transitions.push(
                        Transition {
                            word: word.clone(),
                            weight: W::one(),
                            instruction: TreeStackInstruction::Down {
                                current_val: PosState::Position(r.clone(), 0, j),
                                old_val: PosState::Initial,
                                new_val: PosState::Designated
                            }
                        }
                    );
                }
            }
        }
        // each [r, [r₁, …, rₖ]] on the agenda signifies that r(r₁(…), …, rₖ(…)) is a possible subderivation
        let mut agenda: Vec<DerivationSnippet<N, T, W>>
            = Vec::new();

        for r in g.rules {
            agenda.push(
                ( r.clone(),
                  r.tail.iter().map(|n| rule_map[n].clone()).collect()
                )
            );
        }

        let mut buffer: Vec<T>;

        let mut j: usize;
        let mut k: usize;

        for (r, rss) in agenda {
            j = 0;
            let mut previous_component: Vec<Option<usize>> = rss.iter().map(|_| None).collect();
            for component in r.composition.composition.clone() {
                buffer = Vec::new();
                k = 0;
                for token in component {
                    match token {
                        VarT::Var(i1, j1) => {
                            for ri in &rss[i1] {
                                transitions.push(Transition {
                                    word: buffer.clone(),
                                    weight: match previous_component[i1] {
                                        None => ri.weight.clone(),
                                        Some(_) => W::one(),
                                    },
                                    instruction: match previous_component[i1] {
                                        None => {
                                            TreeStackInstruction::Push {
                                                n: i1,
                                                current_val: PosState::Position(r.clone(), j, k),
                                                new_val: PosState::Position(ri.clone(), j1, 0)
                                            }
                                        },
                                        Some(j0) => {
                                            TreeStackInstruction::Up {
                                                n: i1,
                                                current_val: PosState::Position(r.clone(), j, k),
                                                old_val: PosState::Position(
                                                    ri.clone(),
                                                    j0,
                                                    down_info[ri][j0].0
                                                ),
                                                new_val: PosState::Position(ri.clone(), j1, 0)
                                            }
                                        }
                                    }
                                });

                                transitions.push(Transition {
                                    word: down_info[ri][j1].1.clone(),
                                    weight: W::one(),
                                    instruction: TreeStackInstruction::Down {
                                        current_val: PosState::Position(
                                            ri.clone(),
                                            j1,
                                            down_info[ri][j1].0
                                        ),
                                        old_val: PosState::Position(r.clone(), j, k),
                                        new_val: PosState::Position(r.clone(), j, k + 1)
                                    }
                                });
                            }

                            previous_component[i1] = Some(j1);
                            k += 1;
                            buffer.clear();
                        },

                        VarT::T(t) => {
                            buffer.push(t);
                        }
                    }
                }

                j += 1;
            }
        }

        TreeStackAutomaton::new(
            transitions,
            TreeStack::new(PosState::Initial)
        )
    }
}

pub fn to_abstract_syntax_tree<A>((tree_map, _): (BTreeMap<Vec<usize>, PosState<A>>, Vec<usize>)) -> BTreeMap<Vec<usize>, A> {
    let mut abstract_syntax_tree = BTreeMap::new();

    for (address, pos_state) in tree_map {
        let (curr_root_child, relative_address) = if let Some((first, rest)) = address.split_first() {
            (first.clone(), rest.to_vec())
        } else {
            continue;
        };

        if curr_root_child != 0 {
            continue;
        }

        if let PosState::Position(value, _, _) = pos_state {
            abstract_syntax_tree.insert(relative_address, value);
        } else {
            panic!("The given tree map contains 'designated' or 'initial' nodes that are not the root!");
        }
    }

    abstract_syntax_tree
}
<commit_msg>src/tree_stack_automaton/from_pmcfg.rs: added tests for to_abstract_syntax_tree()<commit_after>extern crate num_traits;

use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::{self, Display, Formatter};
use std::hash::Hash;
use std::iter::FromIterator;
use std::vec::Vec;
use self::num_traits::One;
use recognisable::Transition;
use pmcfg::{PMCFG, PMCFGRule, VarT};
use tree_stack_automaton::{TreeStack, TreeStackAutomaton, TreeStackInstruction};

// types for analysis of derivation trees of PMCFGs
pub type RuleCallerMap<N, T, W> = BTreeMap<PMCFGRule<N, T, W>, Vec<(usize, Vec<T>)>>;
pub type DerivationSnippet<N, T, W> = (PMCFGRule<N, T, W>, Vec<Vec<PMCFGRule<N, T, W>>>);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub enum PosState<X> {
    Designated,
    Initial,
    Position(X, usize, usize),
}

impl<X> PosState<X> {
    pub fn map<F, Y>(&self, f: F) -> PosState<Y>
        where F: Fn(&X) -> Y,
    {
        match *self {
            PosState::Designated => PosState::Designated,
            PosState::Initial => PosState::Initial,
            PosState::Position(ref x, i, j) => PosState::Position(f(x), i, j),
        }
    }
}

impl<X: Display> Display for PosState<X> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            PosState::Designated
                => write!(f, "@"),
            PosState::Initial
                => write!(f, "I"),
            PosState::Position(ref x, i, j)
                => write!(f, "({}, {}, {})", x, i, j)
        }
    }
}

// TODO assumes that the PMCFG is monotonic on the visit-order of components
impl<N: Clone + Ord + PartialEq + Hash,
     T: Clone + Ord + PartialEq + Hash,
     W: Clone + Ord + PartialEq + One
     > From<PMCFG<N, T, W>> for TreeStackAutomaton<PosState<PMCFGRule<N, T, W>>, T, W> {
    fn from(g: PMCFG<N, T, W>) -> Self {
        let mut transitions = Vec::new();

        let mut rule_map: BTreeMap<N, Vec<PMCFGRule<N, T, W>>>
            = BTreeSet::from_iter(
                g.rules
                    .iter()
                    .map(|r| r.head.clone())
            )
            .iter()
            .map(|n| (
                n.clone(),
                Vec::<PMCFGRule<N, T, W>>::new()
            ))
            .collect();

        let mut down_info: RuleCallerMap<N, T, W>
            = BTreeMap::new();

        let mut initial_rules: Vec<PMCFGRule<N, T, W>>
            = Vec::new();

        for r in g.rules.clone() {
            if g.initial.contains(&r.head) {
                initial_rules.push(r.clone())
            }
            rule_map.get_mut(&r.head).unwrap().push(r.clone());

            let mut var_cnt_vec = Vec::new();
            let mut i: usize;
            let mut down_buffer: Vec<T> = Vec::new();
            for component in &r.composition.composition {
                i = 0;
                for ntt in component {
                    down_buffer.clear();
                    match *ntt {
                        VarT::Var(_, _)
                            => {
                                i += 1;
                                down_buffer.clear();
                            },
                        VarT::T(ref t)
                            => {
                                down_buffer.push(t.clone());
                            }
                    }
                }
                var_cnt_vec.push((i, down_buffer.clone()));
            }
            down_info.insert(r.clone(), var_cnt_vec);
        }

        for r in initial_rules {
            transitions.push(
                Transition {
                    word: Vec::new(),
                    weight: r.weight.clone(),
                    instruction: TreeStackInstruction::Push {
                        n: 0,
                        current_val: PosState::Initial,
                        new_val: PosState::Position(r.clone(), 0, 0)
                    }
                }
            );

            match down_info[&r][0] {
                (j, ref word) => {
                    transitions.push(
                        Transition {
                            word: word.clone(),
                            weight: W::one(),
                            instruction: TreeStackInstruction::Down {
                                current_val: PosState::Position(r.clone(), 0, j),
                                old_val: PosState::Initial,
                                new_val: PosState::Designated
                            }
                        }
                    );
                }
            }
        }
        // each [r, [r₁, …, rₖ]] on the agenda signifies that r(r₁(…), …, rₖ(…)) is a possible subderivation
        let mut agenda: Vec<DerivationSnippet<N, T, W>>
            = Vec::new();

        for r in g.rules {
            agenda.push(
                ( r.clone(),
                  r.tail.iter().map(|n| rule_map[n].clone()).collect()
                )
            );
        }

        let mut buffer: Vec<T>;

        let mut j: usize;
        let mut k: usize;

        for (r, rss) in agenda {
            j = 0;
            let mut previous_component: Vec<Option<usize>> = rss.iter().map(|_| None).collect();
            for component in r.composition.composition.clone() {
                buffer = Vec::new();
                k = 0;
                for token in component {
                    match token {
                        VarT::Var(i1, j1) => {
                            for ri in &rss[i1] {
                                transitions.push(Transition {
                                    word: buffer.clone(),
                                    weight: match previous_component[i1] {
                                        None => ri.weight.clone(),
                                        Some(_) => W::one(),
                                    },
                                    instruction: match previous_component[i1] {
                                        None => {
                                            TreeStackInstruction::Push {
                                                n: i1,
                                                current_val: PosState::Position(r.clone(), j, k),
                                                new_val: PosState::Position(ri.clone(), j1, 0)
                                            }
                                        },
                                        Some(j0) => {
                                            TreeStackInstruction::Up {
                                                n: i1,
                                                current_val: PosState::Position(r.clone(), j, k),
                                                old_val: PosState::Position(
                                                    ri.clone(),
                                                    j0,
                                                    down_info[ri][j0].0
                                                ),
                                                new_val: PosState::Position(ri.clone(), j1, 0)
                                            }
                                        }
                                    }
                                });

                                transitions.push(Transition {
                                    word: down_info[ri][j1].1.clone(),
                                    weight: W::one(),
                                    instruction: TreeStackInstruction::Down {
                                        current_val: PosState::Position(
                                            ri.clone(),
                                            j1,
                                            down_info[ri][j1].0
                                        ),
                                        old_val: PosState::Position(r.clone(), j, k),
                                        new_val: PosState::Position(r.clone(), j, k + 1)
                                    }
                                });
                            }

                            previous_component[i1] = Some(j1);
                            k += 1;
                            buffer.clear();
                        },

                        VarT::T(t) => {
                            buffer.push(t);
                        }
                    }
                }

                j += 1;
            }
        }

        TreeStackAutomaton::new(
            transitions,
            TreeStack::new(PosState::Initial)
        )
    }
}

pub fn to_abstract_syntax_tree<A>((tree_map, _): (BTreeMap<Vec<usize>, PosState<A>>, Vec<usize>)) -> BTreeMap<Vec<usize>, A> {
    let mut abstract_syntax_tree = BTreeMap::new();

    for (address, pos_state) in tree_map {
        let (curr_root_child, relative_address) = if let Some((first, rest)) = address.split_first() {
            (first.clone(), rest.to_vec())
        } else {
            continue;
        };

        if curr_root_child != 0 {
            continue;
        }

        if let PosState::Position(value, _, _) = pos_state {
            abstract_syntax_tree.insert(relative_address, value);
        } else {
            panic!("The given tree map contains 'designated' or 'initial' nodes that are not the root!");
        }
    }

    abstract_syntax_tree
}

#[cfg(test)]
pub mod tests {
    use super::*;

    #[test]
    fn test_to_abstract_syntax_tree() {
        let mut tree_map = BTreeMap::new();
        tree_map.insert(vec![], PosState::Initial);
        tree_map.insert(vec![0], PosState::Position('a', 0, 0));
        tree_map.insert(vec![0,0], PosState::Position('b', 0, 0));
        tree_map.insert(vec![0,2], PosState::Position('c', 0, 0));
        tree_map.insert(vec![2], PosState::Position('d', 0, 0));

        let mut abstract_syntax_tree = BTreeMap::new();
        abstract_syntax_tree.insert(vec![], 'a');
        abstract_syntax_tree.insert(vec![0], 'b');
        abstract_syntax_tree.insert(vec![2], 'c');

        assert_eq!(abstract_syntax_tree, to_abstract_syntax_tree((tree_map, vec![])));
    }

    #[test]
    fn test_to_abstract_syntax_tree_empty_tree() {
        let tree_map: BTreeMap<_, PosState<u8>> = BTreeMap::new();
        assert_eq!(BTreeMap::new(), to_abstract_syntax_tree((tree_map, vec![])));
    }

    #[test]
    #[should_panic(
        expected="The given tree map contains 'designated' or 'initial' nodes that are not the root!"
    )]
    fn test_to_abstract_syntax_tree_invalid_tree() {
        let mut tree_map: BTreeMap<_, PosState<u8>> = BTreeMap::new();
        tree_map.insert(vec![], PosState::Initial);
        tree_map.insert(vec![0], PosState::Initial);

        to_abstract_syntax_tree((tree_map, vec![]));
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Contains constants and struct definitions used for implementing vhost-user
//! frontend devices without compile-time dependencies on their corresponding
//! backend devices.

use data_model::DataInit;
use data_model::Le16;
use data_model::Le32;
use data_model::Le64;

pub mod block {
    use super::*;

    pub const VIRTIO_BLK_T_IN: u32 = 0;
    pub const VIRTIO_BLK_T_OUT: u32 = 1;
    pub const VIRTIO_BLK_T_FLUSH: u32 = 4;
    pub const VIRTIO_BLK_T_GET_ID: u32 = 8;
    pub const VIRTIO_BLK_T_DISCARD: u32 = 11;
    pub const VIRTIO_BLK_T_WRITE_ZEROES: u32 = 13;

    pub const VIRTIO_BLK_S_OK: u8 = 0;
    pub const VIRTIO_BLK_S_IOERR: u8 = 1;
    pub const VIRTIO_BLK_S_UNSUPP: u8 = 2;

    pub const VIRTIO_BLK_F_SEG_MAX: u32 = 2;
    pub const VIRTIO_BLK_F_RO: u32 = 5;
    pub const VIRTIO_BLK_F_BLK_SIZE: u32 = 6;
    pub const VIRTIO_BLK_F_FLUSH: u32 = 9;
    pub const VIRTIO_BLK_F_MQ: u32 = 12;
    pub const VIRTIO_BLK_F_DISCARD: u32 = 13;
    pub const VIRTIO_BLK_F_WRITE_ZEROES: u32 = 14;

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub struct virtio_blk_geometry {
        cylinders: Le16,
        heads: u8,
        sectors: u8,
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_geometry {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub struct virtio_blk_topology {
        physical_block_exp: u8,
        alignment_offset: u8,
        min_io_size: Le16,
        opt_io_size: Le32,
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_topology {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C, packed)]
    pub struct virtio_blk_config {
        pub capacity: Le64,
        pub size_max: Le32,
        pub seg_max: Le32,
        pub geometry: virtio_blk_geometry,
        pub blk_size: Le32,
        pub topology: virtio_blk_topology,
        pub writeback: u8,
        pub unused0: u8,
        pub num_queues: Le16,
        pub max_discard_sectors: Le32,
        pub max_discard_seg: Le32,
        pub discard_sector_alignment: Le32,
        pub max_write_zeroes_sectors: Le32,
        pub max_write_zeroes_seg: Le32,
        pub write_zeroes_may_unmap: u8,
        pub unused1: [u8; 3],
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_config {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub(crate) struct virtio_blk_req_header {
        pub req_type: Le32,
        pub reserved: Le32,
        pub sector: Le64,
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_req_header {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub(crate) struct virtio_blk_discard_write_zeroes {
        pub sector: Le64,
        pub num_sectors: Le32,
        pub flags: Le32,
    }

    pub(crate) const VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP: u32 = 1 << 0;

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_discard_write_zeroes {}
}

pub mod gpu {
    use super::*;

    // First queue is for virtio gpu commands. Second queue is for cursor commands, which we expect
    // there to be fewer of.
    pub const QUEUE_SIZES: &[u16] = &[256, 16];

    pub const VIRTIO_GPU_F_VIRGL: u32 = 0;
    pub const VIRTIO_GPU_F_EDID: u32 = 1;
    pub const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2;
    pub const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3;
    pub const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4;
    /* The following capabilities are not upstreamed. */
    pub const VIRTIO_GPU_F_RESOURCE_SYNC: u32 = 5;
    pub const VIRTIO_GPU_F_CREATE_GUEST_HANDLE: u32 = 6;

    pub const VIRTIO_GPU_SHM_ID_HOST_VISIBLE: u8 = 0x0001;

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub struct virtio_gpu_config {
        pub events_read: Le32,
        pub events_clear: Le32,
        pub num_scanouts: Le32,
        pub num_capsets: Le32,
    }

    unsafe impl DataInit for virtio_gpu_config {}
}

pub mod snd {
    use super::*;

    #[derive(Copy, Clone, Default)]
    #[repr(C, packed)]
    pub struct virtio_snd_config {
        pub jacks: Le32,
        pub streams: Le32,
        pub chmaps: Le32,
    }
    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_snd_config {}
}

pub mod video {
    use data_model::DataInit;
    use data_model::Le32;
    use serde::Deserialize;
    use serde::Serialize;
    use serde_keyvalue::FromKeyValues;

    // CMD_QUEUE_SIZE = max number of command descriptors for input and output queues
    // Experimentally, it appears a stream allocates 16 input and 26 output buffers = 42 total
    // For 8 simultaneous streams, 2 descs per buffer * 42 buffers * 8 streams = 672 descs
    // Allocate 1024 to give some headroom in case of extra streams/buffers
    //
    // TODO(b/204055006): Make cmd queue size dependent of
    // (max buf cnt for input + max buf cnt for output) * max descs per buffer * max nb of streams
    const CMD_QUEUE_SIZE: u16 = 1024;
    pub const CMD_QUEUE_INDEX: usize = 0;
    // EVENT_QUEUE_SIZE = max number of event descriptors for stream events like resolution changes
    const EVENT_QUEUE_SIZE: u16 = 256;
    pub const EVENT_QUEUE_INDEX: usize = 1;
    pub const QUEUE_SIZES: &[u16] = &[CMD_QUEUE_SIZE, EVENT_QUEUE_SIZE];

    pub const VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES: u32 = 0;
    pub const VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG: u32 = 1;
    pub const VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT: u32 = 2;

    #[derive(Debug, Clone, Copy)]
    pub enum VideoDeviceType {
        Decoder,
        Encoder,
    }

    #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
    #[serde(rename_all = "kebab-case")]
    pub enum VideoBackendType {
        #[cfg(feature = "libvda")]
        Libvda,
        #[cfg(feature = "libvda")]
        LibvdaVd,
        #[cfg(feature = "ffmpeg")]
        Ffmpeg,
        #[cfg(feature = "vaapi")]
        Vaapi,
    }

    #[derive(Debug, Serialize, Deserialize, FromKeyValues)]
    pub struct VideoDeviceConfig {
        pub backend: VideoBackendType,
    }

    /// The same set of virtio features is supported by the ffmpeg decoder and encoder.
    pub fn ffmpeg_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }

    /// The same set of virtio features is supported by the vaapi decoder and encoder.
    pub fn vaapi_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }

    /// The same set of virtio features is supported by the vda decoder and encoder.
    pub fn vda_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }

    /// Union of the supported features of all decoder and encoder backends.
    pub fn all_backend_virtio_features() -> u64 {
        ffmpeg_supported_virtio_features()
            | vaapi_supported_virtio_features()
            | vda_supported_virtio_features()
    }

    pub fn backend_supported_virtio_features(backend: VideoBackendType) -> u64 {
        match backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda | VideoBackendType::LibvdaVd => {
                vda_supported_virtio_features()
            }
            #[cfg(feature = "ffmpeg")]
            VideoBackendType::Ffmpeg => ffmpeg_supported_virtio_features(),
            #[cfg(feature = "vaapi")]
            VideoBackendType::Vaapi => vaapi_supported_virtio_features(),
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone)]
    pub struct virtio_video_config {
        pub version: Le32,
        pub max_caps_length: Le32,
        pub max_resp_length: Le32,
        pub device_name: [u8; 32],
    }
    // Safe because auto-generated structs have no implicit padding.
    unsafe impl DataInit for virtio_video_config {}
}
<commit_msg>crosvm: virtgpu: Increase queue size<commit_after>// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Contains constants and struct definitions used for implementing vhost-user
//! frontend devices without compile-time dependencies on their corresponding
//! backend devices.

use data_model::DataInit;
use data_model::Le16;
use data_model::Le32;
use data_model::Le64;

pub mod block {
    use super::*;

    pub const VIRTIO_BLK_T_IN: u32 = 0;
    pub const VIRTIO_BLK_T_OUT: u32 = 1;
    pub const VIRTIO_BLK_T_FLUSH: u32 = 4;
    pub const VIRTIO_BLK_T_GET_ID: u32 = 8;
    pub const VIRTIO_BLK_T_DISCARD: u32 = 11;
    pub const VIRTIO_BLK_T_WRITE_ZEROES: u32 = 13;

    pub const VIRTIO_BLK_S_OK: u8 = 0;
    pub const VIRTIO_BLK_S_IOERR: u8 = 1;
    pub const VIRTIO_BLK_S_UNSUPP: u8 = 2;

    pub const VIRTIO_BLK_F_SEG_MAX: u32 = 2;
    pub const VIRTIO_BLK_F_RO: u32 = 5;
    pub const VIRTIO_BLK_F_BLK_SIZE: u32 = 6;
    pub const VIRTIO_BLK_F_FLUSH: u32 = 9;
    pub const VIRTIO_BLK_F_MQ: u32 = 12;
    pub const VIRTIO_BLK_F_DISCARD: u32 = 13;
    pub const VIRTIO_BLK_F_WRITE_ZEROES: u32 = 14;

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub struct virtio_blk_geometry {
        cylinders: Le16,
        heads: u8,
        sectors: u8,
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_geometry {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub struct virtio_blk_topology {
        physical_block_exp: u8,
        alignment_offset: u8,
        min_io_size: Le16,
        opt_io_size: Le32,
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_topology {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C, packed)]
    pub struct virtio_blk_config {
        pub capacity: Le64,
        pub size_max: Le32,
        pub seg_max: Le32,
        pub geometry: virtio_blk_geometry,
        pub blk_size: Le32,
        pub topology: virtio_blk_topology,
        pub writeback: u8,
        pub unused0: u8,
        pub num_queues: Le16,
        pub max_discard_sectors: Le32,
        pub max_discard_seg: Le32,
        pub discard_sector_alignment: Le32,
        pub max_write_zeroes_sectors: Le32,
        pub max_write_zeroes_seg: Le32,
        pub write_zeroes_may_unmap: u8,
        pub unused1: [u8; 3],
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_config {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub(crate) struct virtio_blk_req_header {
        pub req_type: Le32,
        pub reserved: Le32,
        pub sector: Le64,
    }

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_req_header {}

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub(crate) struct virtio_blk_discard_write_zeroes {
        pub sector: Le64,
        pub num_sectors: Le32,
        pub flags: Le32,
    }

    pub(crate) const VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP: u32 = 1 << 0;

    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_blk_discard_write_zeroes {}
}

pub mod gpu {
    use super::*;

    // First queue is for virtio gpu commands. Second queue is for cursor commands, which we expect
    // there to be fewer of.
    pub const QUEUE_SIZES: &[u16] = &[512, 16];

    pub const VIRTIO_GPU_F_VIRGL: u32 = 0;
    pub const VIRTIO_GPU_F_EDID: u32 = 1;
    pub const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2;
    pub const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3;
    pub const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4;
    /* The following capabilities are not upstreamed. */
    pub const VIRTIO_GPU_F_RESOURCE_SYNC: u32 = 5;
    pub const VIRTIO_GPU_F_CREATE_GUEST_HANDLE: u32 = 6;

    pub const VIRTIO_GPU_SHM_ID_HOST_VISIBLE: u8 = 0x0001;

    #[derive(Copy, Clone, Debug, Default)]
    #[repr(C)]
    pub struct virtio_gpu_config {
        pub events_read: Le32,
        pub events_clear: Le32,
        pub num_scanouts: Le32,
        pub num_capsets: Le32,
    }

    unsafe impl DataInit for virtio_gpu_config {}
}

pub mod snd {
    use super::*;

    #[derive(Copy, Clone, Default)]
    #[repr(C, packed)]
    pub struct virtio_snd_config {
        pub jacks: Le32,
        pub streams: Le32,
        pub chmaps: Le32,
    }
    // Safe because it only has data and has no implicit padding.
    unsafe impl DataInit for virtio_snd_config {}
}

pub mod video {
    use data_model::DataInit;
    use data_model::Le32;
    use serde::Deserialize;
    use serde::Serialize;
    use serde_keyvalue::FromKeyValues;

    // CMD_QUEUE_SIZE = max number of command descriptors for input and output queues
    // Experimentally, it appears a stream allocates 16 input and 26 output buffers = 42 total
    // For 8 simultaneous streams, 2 descs per buffer * 42 buffers * 8 streams = 672 descs
    // Allocate 1024 to give some headroom in case of extra streams/buffers
    //
    // TODO(b/204055006): Make cmd queue size dependent of
    // (max buf cnt for input + max buf cnt for output) * max descs per buffer * max nb of streams
    const CMD_QUEUE_SIZE: u16 = 1024;
    pub const CMD_QUEUE_INDEX: usize = 0;
    // EVENT_QUEUE_SIZE = max number of event descriptors for stream events like resolution changes
    const EVENT_QUEUE_SIZE: u16 = 256;
    pub const EVENT_QUEUE_INDEX: usize = 1;
    pub const QUEUE_SIZES: &[u16] = &[CMD_QUEUE_SIZE, EVENT_QUEUE_SIZE];

    pub const VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES: u32 = 0;
    pub const VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG: u32 = 1;
    pub const VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT: u32 = 2;

    #[derive(Debug, Clone, Copy)]
    pub enum VideoDeviceType {
        Decoder,
        Encoder,
    }

    #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
    #[serde(rename_all = "kebab-case")]
    pub enum VideoBackendType {
        #[cfg(feature = "libvda")]
        Libvda,
        #[cfg(feature = "libvda")]
        LibvdaVd,
        #[cfg(feature = "ffmpeg")]
        Ffmpeg,
        #[cfg(feature = "vaapi")]
        Vaapi,
    }

    #[derive(Debug, Serialize, Deserialize, FromKeyValues)]
    pub struct VideoDeviceConfig {
        pub backend: VideoBackendType,
    }

    /// The same set of virtio features is supported by the ffmpeg decoder and encoder.
    pub fn ffmpeg_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }

    /// The same set of virtio features is supported by the vaapi decoder and encoder.
    pub fn vaapi_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG
            | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }

    /// The same set of virtio features is supported by the vda decoder and encoder.
    pub fn vda_supported_virtio_features() -> u64 {
        1u64 << VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG | 1u64 << VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT
    }

    /// Union of the supported features of all decoder and encoder backends.
    pub fn all_backend_virtio_features() -> u64 {
        ffmpeg_supported_virtio_features()
            | vaapi_supported_virtio_features()
            | vda_supported_virtio_features()
    }

    pub fn backend_supported_virtio_features(backend: VideoBackendType) -> u64 {
        match backend {
            #[cfg(feature = "libvda")]
            VideoBackendType::Libvda | VideoBackendType::LibvdaVd => {
                vda_supported_virtio_features()
            }
            #[cfg(feature = "ffmpeg")]
            VideoBackendType::Ffmpeg => ffmpeg_supported_virtio_features(),
            #[cfg(feature = "vaapi")]
            VideoBackendType::Vaapi => vaapi_supported_virtio_features(),
        }
    }

    #[repr(C)]
    #[derive(Debug, Default, Copy, Clone)]
    pub struct virtio_video_config {
        pub version: Le32,
        pub max_caps_length: Le32,
        pub max_resp_length: Le32,
        pub device_name: [u8; 32],
    }
    // Safe because auto-generated structs have no implicit padding.
    unsafe impl DataInit for virtio_video_config {}
}
<|endoftext|>