tree_fold1.rs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. use criterion::{criterion_group, criterion_main, Criterion};
  2. use itertools::{Itertools, cloned};
  3. trait IterEx : Iterator {
  4. // Another efficient implementation against which to compare,
  5. // but needs `std` so is less desirable.
  6. fn tree_fold1_vec<F>(self, mut f: F) -> Option<Self::Item>
  7. where F: FnMut(Self::Item, Self::Item) -> Self::Item,
  8. Self: Sized,
  9. {
  10. let hint = self.size_hint().0;
  11. let cap = std::mem::size_of::<usize>() * 8 - hint.leading_zeros() as usize;
  12. let mut stack = Vec::with_capacity(cap);
  13. self.enumerate().for_each(|(mut i, mut x)| {
  14. while (i & 1) != 0 {
  15. x = f(stack.pop().unwrap(), x);
  16. i >>= 1;
  17. }
  18. stack.push(x);
  19. });
  20. stack.into_iter().fold1(f)
  21. }
  22. }
  23. impl<T:Iterator> IterEx for T {}
  24. macro_rules! def_benchs {
  25. ($N:expr,
  26. $FUN:ident,
  27. $BENCH_NAME:ident,
  28. ) => (
  29. mod $BENCH_NAME {
  30. use super::*;
  31. pub fn sum(c: &mut Criterion) {
  32. let v: Vec<u32> = (0.. $N).collect();
  33. c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " sum"), move |b| {
  34. b.iter(|| {
  35. cloned(&v).$FUN(|x, y| x + y)
  36. })
  37. });
  38. }
  39. pub fn complex_iter(c: &mut Criterion) {
  40. let u = (3..).take($N / 2);
  41. let v = (5..).take($N / 2);
  42. let it = u.chain(v);
  43. c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " complex iter"), move |b| {
  44. b.iter(|| {
  45. it.clone().map(|x| x as f32).$FUN(f32::atan2)
  46. })
  47. });
  48. }
  49. pub fn string_format(c: &mut Criterion) {
  50. // This goes quadratic with linear `fold1`, so use a smaller
  51. // size to not waste too much time in travis. The allocations
  52. // in here are so expensive anyway that it'll still take
  53. // way longer per iteration than the other two benchmarks.
  54. let v: Vec<u32> = (0.. ($N/4)).collect();
  55. c.bench_function(&(stringify!($BENCH_NAME).replace('_', " ") + " string format"), move |b| {
  56. b.iter(|| {
  57. cloned(&v).map(|x| x.to_string()).$FUN(|x, y| format!("{} + {}", x, y))
  58. })
  59. });
  60. }
  61. }
  62. criterion_group!(
  63. $BENCH_NAME,
  64. $BENCH_NAME::sum,
  65. $BENCH_NAME::complex_iter,
  66. $BENCH_NAME::string_format,
  67. );
  68. )
  69. }
  70. def_benchs!{
  71. 10_000,
  72. fold1,
  73. fold1_10k,
  74. }
  75. def_benchs!{
  76. 10_000,
  77. tree_fold1,
  78. tree_fold1_stack_10k,
  79. }
  80. def_benchs!{
  81. 10_000,
  82. tree_fold1_vec,
  83. tree_fold1_vec_10k,
  84. }
  85. def_benchs!{
  86. 100,
  87. fold1,
  88. fold1_100,
  89. }
  90. def_benchs!{
  91. 100,
  92. tree_fold1,
  93. tree_fold1_stack_100,
  94. }
  95. def_benchs!{
  96. 100,
  97. tree_fold1_vec,
  98. tree_fold1_vec_100,
  99. }
  100. def_benchs!{
  101. 8,
  102. fold1,
  103. fold1_08,
  104. }
  105. def_benchs!{
  106. 8,
  107. tree_fold1,
  108. tree_fold1_stack_08,
  109. }
  110. def_benchs!{
  111. 8,
  112. tree_fold1_vec,
  113. tree_fold1_vec_08,
  114. }
  115. criterion_main!(
  116. fold1_10k,
  117. tree_fold1_stack_10k,
  118. tree_fold1_vec_10k,
  119. fold1_100,
  120. tree_fold1_stack_100,
  121. tree_fold1_vec_100,
  122. fold1_08,
  123. tree_fold1_stack_08,
  124. tree_fold1_vec_08,
  125. );