1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; |
---|---|

2 | use itertools::Itertools; |

3 | use itertools::free::cloned; |

4 | use itertools::iproduct; |

5 | |

6 | use std::iter::repeat; |

7 | use std::cmp; |

8 | use std::ops::{Add, Range}; |

9 | |

10 | mod extra; |

11 | |

12 | use crate::extra::ZipSlices; |

13 | |

14 | fn slice_iter(c: &mut Criterion) { |

15 | let xs: Vec<_> = repeat(1i32).take(20).collect(); |

16 | |

17 | c.bench_function("slice iter", move |b| { |

18 | b.iter(|| for elt in xs.iter() { |

19 | black_box(elt); |

20 | }) |

21 | }); |

22 | } |

23 | |

24 | fn slice_iter_rev(c: &mut Criterion) { |

25 | let xs: Vec<_> = repeat(1i32).take(20).collect(); |

26 | |

27 | c.bench_function("slice iter rev", move |b| { |

28 | b.iter(|| for elt in xs.iter().rev() { |

29 | black_box(elt); |

30 | }) |

31 | }); |

32 | } |

33 | |

34 | fn zip_default_zip(c: &mut Criterion) { |

35 | let xs = vec![0; 1024]; |

36 | let ys = vec![0; 768]; |

37 | let xs = black_box(xs); |

38 | let ys = black_box(ys); |

39 | |

40 | c.bench_function("zip default zip", move |b| { |

41 | b.iter(|| { |

42 | for (&x, &y) in xs.iter().zip(&ys) { |

43 | black_box(x); |

44 | black_box(y); |

45 | } |

46 | }) |

47 | }); |

48 | } |

49 | |

50 | fn zipdot_i32_default_zip(c: &mut Criterion) { |

51 | let xs = vec![2; 1024]; |

52 | let ys = vec![2; 768]; |

53 | let xs = black_box(xs); |

54 | let ys = black_box(ys); |

55 | |

56 | c.bench_function("zipdot i32 default zip", move |b| { |

57 | b.iter(|| { |

58 | let mut s = 0; |

59 | for (&x, &y) in xs.iter().zip(&ys) { |

60 | s += x * y; |

61 | } |

62 | s |

63 | }) |

64 | }); |

65 | } |

66 | |

67 | fn zipdot_f32_default_zip(c: &mut Criterion) { |

68 | let xs = vec![2f32; 1024]; |

69 | let ys = vec![2f32; 768]; |

70 | let xs = black_box(xs); |

71 | let ys = black_box(ys); |

72 | |

73 | c.bench_function("zipdot f32 default zip", move |b| { |

74 | b.iter(|| { |

75 | let mut s = 0.; |

76 | for (&x, &y) in xs.iter().zip(&ys) { |

77 | s += x * y; |

78 | } |

79 | s |

80 | }) |

81 | }); |

82 | } |

83 | |

84 | fn zip_default_zip3(c: &mut Criterion) { |

85 | let xs = vec![0; 1024]; |

86 | let ys = vec![0; 768]; |

87 | let zs = vec![0; 766]; |

88 | let xs = black_box(xs); |

89 | let ys = black_box(ys); |

90 | let zs = black_box(zs); |

91 | |

92 | c.bench_function("zip default zip3", move |b| { |

93 | b.iter(|| { |

94 | for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) { |

95 | black_box(x); |

96 | black_box(y); |

97 | black_box(z); |

98 | } |

99 | }) |

100 | }); |

101 | } |

102 | |

103 | fn zip_slices_ziptuple(c: &mut Criterion) { |

104 | let xs = vec![0; 1024]; |

105 | let ys = vec![0; 768]; |

106 | |

107 | c.bench_function("zip slices ziptuple", move |b| { |

108 | b.iter(|| { |

109 | let xs = black_box(&xs); |

110 | let ys = black_box(&ys); |

111 | for (&x, &y) in itertools::multizip((xs, ys)) { |

112 | black_box(x); |

113 | black_box(y); |

114 | } |

115 | }) |

116 | }); |

117 | } |

118 | |

119 | fn zipslices(c: &mut Criterion) { |

120 | let xs = vec![0; 1024]; |

121 | let ys = vec![0; 768]; |

122 | let xs = black_box(xs); |

123 | let ys = black_box(ys); |

124 | |

125 | c.bench_function("zipslices", move |b| { |

126 | b.iter(|| { |

127 | for (&x, &y) in ZipSlices::new(&xs, &ys) { |

128 | black_box(x); |

129 | black_box(y); |

130 | } |

131 | }) |

132 | }); |

133 | } |

134 | |

135 | fn zipslices_mut(c: &mut Criterion) { |

136 | let xs = vec![0; 1024]; |

137 | let ys = vec![0; 768]; |

138 | let xs = black_box(xs); |

139 | let mut ys = black_box(ys); |

140 | |

141 | c.bench_function("zipslices mut", move |b| { |

142 | b.iter(|| { |

143 | for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { |

144 | black_box(x); |

145 | black_box(y); |

146 | } |

147 | }) |

148 | }); |

149 | } |

150 | |

151 | fn zipdot_i32_zipslices(c: &mut Criterion) { |

152 | let xs = vec![2; 1024]; |

153 | let ys = vec![2; 768]; |

154 | let xs = black_box(xs); |

155 | let ys = black_box(ys); |

156 | |

157 | c.bench_function("zipdot i32 zipslices", move |b| { |

158 | b.iter(|| { |

159 | let mut s = 0i32; |

160 | for (&x, &y) in ZipSlices::new(&xs, &ys) { |

161 | s += x * y; |

162 | } |

163 | s |

164 | }) |

165 | }); |

166 | } |

167 | |

168 | fn zipdot_f32_zipslices(c: &mut Criterion) { |

169 | let xs = vec![2f32; 1024]; |

170 | let ys = vec![2f32; 768]; |

171 | let xs = black_box(xs); |

172 | let ys = black_box(ys); |

173 | |

174 | c.bench_function("zipdot f32 zipslices", move |b| { |

175 | b.iter(|| { |

176 | let mut s = 0.; |

177 | for (&x, &y) in ZipSlices::new(&xs, &ys) { |

178 | s += x * y; |

179 | } |

180 | s |

181 | }) |

182 | }); |

183 | } |

184 | |

185 | fn zip_checked_counted_loop(c: &mut Criterion) { |

186 | let xs = vec![0; 1024]; |

187 | let ys = vec![0; 768]; |

188 | let xs = black_box(xs); |

189 | let ys = black_box(ys); |

190 | |

191 | c.bench_function("zip checked counted loop", move |b| { |

192 | b.iter(|| { |

193 | // Must slice to equal lengths, and then bounds checks are eliminated! |

194 | let len = cmp::min(xs.len(), ys.len()); |

195 | let xs = &xs[..len]; |

196 | let ys = &ys[..len]; |

197 | |

198 | for i in 0..len { |

199 | let x = xs[i]; |

200 | let y = ys[i]; |

201 | black_box(x); |

202 | black_box(y); |

203 | } |

204 | }) |

205 | }); |

206 | } |

207 | |

208 | fn zipdot_i32_checked_counted_loop(c: &mut Criterion) { |

209 | let xs = vec![2; 1024]; |

210 | let ys = vec![2; 768]; |

211 | let xs = black_box(xs); |

212 | let ys = black_box(ys); |

213 | |

214 | c.bench_function("zipdot i32 checked counted loop", move |b| { |

215 | b.iter(|| { |

216 | // Must slice to equal lengths, and then bounds checks are eliminated! |

217 | let len = cmp::min(xs.len(), ys.len()); |

218 | let xs = &xs[..len]; |

219 | let ys = &ys[..len]; |

220 | |

221 | let mut s = 0i32; |

222 | |

223 | for i in 0..len { |

224 | s += xs[i] * ys[i]; |

225 | } |

226 | s |

227 | }) |

228 | }); |

229 | } |

230 | |

231 | fn zipdot_f32_checked_counted_loop(c: &mut Criterion) { |

232 | let xs = vec![2f32; 1024]; |

233 | let ys = vec![2f32; 768]; |

234 | let xs = black_box(xs); |

235 | let ys = black_box(ys); |

236 | |

237 | c.bench_function("zipdot f32 checked counted loop", move |b| { |

238 | b.iter(|| { |

239 | // Must slice to equal lengths, and then bounds checks are eliminated! |

240 | let len = cmp::min(xs.len(), ys.len()); |

241 | let xs = &xs[..len]; |

242 | let ys = &ys[..len]; |

243 | |

244 | let mut s = 0.; |

245 | |

246 | for i in 0..len { |

247 | s += xs[i] * ys[i]; |

248 | } |

249 | s |

250 | }) |

251 | }); |

252 | } |

253 | |

254 | fn zipdot_f32_checked_counted_unrolled_loop(c: &mut Criterion) { |

255 | let xs = vec![2f32; 1024]; |

256 | let ys = vec![2f32; 768]; |

257 | let xs = black_box(xs); |

258 | let ys = black_box(ys); |

259 | |

260 | c.bench_function("zipdot f32 checked counted unrolled loop", move |b| { |

261 | b.iter(|| { |

262 | // Must slice to equal lengths, and then bounds checks are eliminated! |

263 | let len = cmp::min(xs.len(), ys.len()); |

264 | let mut xs = &xs[..len]; |

265 | let mut ys = &ys[..len]; |

266 | |

267 | let mut s = 0.; |

268 | let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) = |

269 | (0., 0., 0., 0., 0., 0., 0., 0.); |

270 | |

271 | // how to unroll and have bounds checks eliminated (by cristicbz) |

272 | // split sum into eight parts to enable vectorization (by bluss) |

273 | while xs.len() >= 8 { |

274 | p0 += xs[0] * ys[0]; |

275 | p1 += xs[1] * ys[1]; |

276 | p2 += xs[2] * ys[2]; |

277 | p3 += xs[3] * ys[3]; |

278 | p4 += xs[4] * ys[4]; |

279 | p5 += xs[5] * ys[5]; |

280 | p6 += xs[6] * ys[6]; |

281 | p7 += xs[7] * ys[7]; |

282 | |

283 | xs = &xs[8..]; |

284 | ys = &ys[8..]; |

285 | } |

286 | s += p0 + p4; |

287 | s += p1 + p5; |

288 | s += p2 + p6; |

289 | s += p3 + p7; |

290 | |

291 | for i in 0..xs.len() { |

292 | s += xs[i] * ys[i]; |

293 | } |

294 | s |

295 | }) |

296 | }); |

297 | } |

298 | |

299 | fn zip_unchecked_counted_loop(c: &mut Criterion) { |

300 | let xs = vec![0; 1024]; |

301 | let ys = vec![0; 768]; |

302 | let xs = black_box(xs); |

303 | let ys = black_box(ys); |

304 | |

305 | c.bench_function("zip unchecked counted loop", move |b| { |

306 | b.iter(|| { |

307 | let len = cmp::min(xs.len(), ys.len()); |

308 | for i in 0..len { |

309 | unsafe { |

310 | let x = *xs.get_unchecked(i); |

311 | let y = *ys.get_unchecked(i); |

312 | black_box(x); |

313 | black_box(y); |

314 | } |

315 | } |

316 | }) |

317 | }); |

318 | } |

319 | |

320 | fn zipdot_i32_unchecked_counted_loop(c: &mut Criterion) { |

321 | let xs = vec![2; 1024]; |

322 | let ys = vec![2; 768]; |

323 | let xs = black_box(xs); |

324 | let ys = black_box(ys); |

325 | |

326 | c.bench_function("zipdot i32 unchecked counted loop", move |b| { |

327 | b.iter(|| { |

328 | let len = cmp::min(xs.len(), ys.len()); |

329 | let mut s = 0i32; |

330 | for i in 0..len { |

331 | unsafe { |

332 | let x = *xs.get_unchecked(i); |

333 | let y = *ys.get_unchecked(i); |

334 | s += x * y; |

335 | } |

336 | } |

337 | s |

338 | }) |

339 | }); |

340 | } |

341 | |

342 | fn zipdot_f32_unchecked_counted_loop(c: &mut Criterion) { |

343 | let xs = vec![2.; 1024]; |

344 | let ys = vec![2.; 768]; |

345 | let xs = black_box(xs); |

346 | let ys = black_box(ys); |

347 | |

348 | c.bench_function("zipdot f32 unchecked counted loop", move |b| { |

349 | b.iter(|| { |

350 | let len = cmp::min(xs.len(), ys.len()); |

351 | let mut s = 0f32; |

352 | for i in 0..len { |

353 | unsafe { |

354 | let x = *xs.get_unchecked(i); |

355 | let y = *ys.get_unchecked(i); |

356 | s += x * y; |

357 | } |

358 | } |

359 | s |

360 | }) |

361 | }); |

362 | } |

363 | |

364 | fn zip_unchecked_counted_loop3(c: &mut Criterion) { |

365 | let xs = vec![0; 1024]; |

366 | let ys = vec![0; 768]; |

367 | let zs = vec![0; 766]; |

368 | let xs = black_box(xs); |

369 | let ys = black_box(ys); |

370 | let zs = black_box(zs); |

371 | |

372 | c.bench_function("zip unchecked counted loop3", move |b| { |

373 | b.iter(|| { |

374 | let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len())); |

375 | for i in 0..len { |

376 | unsafe { |

377 | let x = *xs.get_unchecked(i); |

378 | let y = *ys.get_unchecked(i); |

379 | let z = *zs.get_unchecked(i); |

380 | black_box(x); |

381 | black_box(y); |

382 | black_box(z); |

383 | } |

384 | } |

385 | }) |

386 | }); |

387 | } |

388 | |

389 | fn group_by_lazy_1(c: &mut Criterion) { |

390 | let mut data = vec![0; 1024]; |

391 | for (index, elt) in data.iter_mut().enumerate() { |

392 | *elt = index / 10; |

393 | } |

394 | |

395 | let data = black_box(data); |

396 | |

397 | c.bench_function("group by lazy 1", move |b| { |

398 | b.iter(|| { |

399 | for (_key, group) in &data.iter().group_by(|elt| **elt) { |

400 | for elt in group { |

401 | black_box(elt); |

402 | } |

403 | } |

404 | }) |

405 | }); |

406 | } |

407 | |

408 | fn group_by_lazy_2(c: &mut Criterion) { |

409 | let mut data = vec![0; 1024]; |

410 | for (index, elt) in data.iter_mut().enumerate() { |

411 | *elt = index / 2; |

412 | } |

413 | |

414 | let data = black_box(data); |

415 | |

416 | c.bench_function("group by lazy 2", move |b| { |

417 | b.iter(|| { |

418 | for (_key, group) in &data.iter().group_by(|elt| **elt) { |

419 | for elt in group { |

420 | black_box(elt); |

421 | } |

422 | } |

423 | }) |

424 | }); |

425 | } |

426 | |

427 | fn slice_chunks(c: &mut Criterion) { |

428 | let data = vec![0; 1024]; |

429 | |

430 | let data = black_box(data); |

431 | let sz = black_box(10); |

432 | |

433 | c.bench_function("slice chunks", move |b| { |

434 | b.iter(|| { |

435 | for group in data.chunks(sz) { |

436 | for elt in group { |

437 | black_box(elt); |

438 | } |

439 | } |

440 | }) |

441 | }); |

442 | } |

443 | |

444 | fn chunks_lazy_1(c: &mut Criterion) { |

445 | let data = vec![0; 1024]; |

446 | |

447 | let data = black_box(data); |

448 | let sz = black_box(10); |

449 | |

450 | c.bench_function("chunks lazy 1", move |b| { |

451 | b.iter(|| { |

452 | for group in &data.iter().chunks(sz) { |

453 | for elt in group { |

454 | black_box(elt); |

455 | } |

456 | } |

457 | }) |

458 | }); |

459 | } |

460 | |

461 | fn equal(c: &mut Criterion) { |

462 | let data = vec![7; 1024]; |

463 | let l = data.len(); |

464 | let alpha = black_box(&data[1..]); |

465 | let beta = black_box(&data[..l - 1]); |

466 | |

467 | c.bench_function("equal", move |b| { |

468 | b.iter(|| { |

469 | itertools::equal(alpha, beta) |

470 | }) |

471 | }); |

472 | } |

473 | |

474 | fn merge_default(c: &mut Criterion) { |

475 | let mut data1 = vec![0; 1024]; |

476 | let mut data2 = vec![0; 800]; |

477 | let mut x = 0; |

478 | for (_, elt) in data1.iter_mut().enumerate() { |

479 | *elt = x; |

480 | x += 1; |

481 | } |

482 | |

483 | let mut y = 0; |

484 | for (i, elt) in data2.iter_mut().enumerate() { |

485 | *elt += y; |

486 | if i % 3 == 0 { |

487 | y += 3; |

488 | } else { |

489 | y += 0; |

490 | } |

491 | } |

492 | let data1 = black_box(data1); |

493 | let data2 = black_box(data2); |

494 | |

495 | c.bench_function("merge default", move |b| { |

496 | b.iter(|| { |

497 | data1.iter().merge(&data2).count() |

498 | }) |

499 | }); |

500 | } |

501 | |

502 | fn merge_by_cmp(c: &mut Criterion) { |

503 | let mut data1 = vec![0; 1024]; |

504 | let mut data2 = vec![0; 800]; |

505 | let mut x = 0; |

506 | for (_, elt) in data1.iter_mut().enumerate() { |

507 | *elt = x; |

508 | x += 1; |

509 | } |

510 | |

511 | let mut y = 0; |

512 | for (i, elt) in data2.iter_mut().enumerate() { |

513 | *elt += y; |

514 | if i % 3 == 0 { |

515 | y += 3; |

516 | } else { |

517 | y += 0; |

518 | } |

519 | } |

520 | let data1 = black_box(data1); |

521 | let data2 = black_box(data2); |

522 | |

523 | c.bench_function("merge by cmp", move |b| { |

524 | b.iter(|| { |

525 | data1.iter().merge_by(&data2, PartialOrd::le).count() |

526 | }) |

527 | }); |

528 | } |

529 | |

530 | fn merge_by_lt(c: &mut Criterion) { |

531 | let mut data1 = vec![0; 1024]; |

532 | let mut data2 = vec![0; 800]; |

533 | let mut x = 0; |

534 | for (_, elt) in data1.iter_mut().enumerate() { |

535 | *elt = x; |

536 | x += 1; |

537 | } |

538 | |

539 | let mut y = 0; |

540 | for (i, elt) in data2.iter_mut().enumerate() { |

541 | *elt += y; |

542 | if i % 3 == 0 { |

543 | y += 3; |

544 | } else { |

545 | y += 0; |

546 | } |

547 | } |

548 | let data1 = black_box(data1); |

549 | let data2 = black_box(data2); |

550 | |

551 | c.bench_function("merge by lt", move |b| { |

552 | b.iter(|| { |

553 | data1.iter().merge_by(&data2, |a, b| a <= b).count() |

554 | }) |

555 | }); |

556 | } |

557 | |

558 | fn kmerge_default(c: &mut Criterion) { |

559 | let mut data1 = vec![0; 1024]; |

560 | let mut data2 = vec![0; 800]; |

561 | let mut x = 0; |

562 | for (_, elt) in data1.iter_mut().enumerate() { |

563 | *elt = x; |

564 | x += 1; |

565 | } |

566 | |

567 | let mut y = 0; |

568 | for (i, elt) in data2.iter_mut().enumerate() { |

569 | *elt += y; |

570 | if i % 3 == 0 { |

571 | y += 3; |

572 | } else { |

573 | y += 0; |

574 | } |

575 | } |

576 | let data1 = black_box(data1); |

577 | let data2 = black_box(data2); |

578 | let its = &[data1.iter(), data2.iter()]; |

579 | |

580 | c.bench_function("kmerge default", move |b| { |

581 | b.iter(|| { |

582 | its.iter().cloned().kmerge().count() |

583 | }) |

584 | }); |

585 | } |

586 | |

587 | fn kmerge_tenway(c: &mut Criterion) { |

588 | let mut data = vec![0; 10240]; |

589 | |

590 | let mut state = 1729u16; |

591 | fn rng(state: &mut u16) -> u16 { |

592 | let new = state.wrapping_mul(31421) + 6927; |

593 | *state = new; |

594 | new |

595 | } |

596 | |

597 | for elt in &mut data { |

598 | *elt = rng(&mut state); |

599 | } |

600 | |

601 | let mut chunks = Vec::new(); |

602 | let mut rest = &mut data[..]; |

603 | while rest.len() > 0 { |

604 | let chunk_len = 1 + rng(&mut state) % 512; |

605 | let chunk_len = cmp::min(rest.len(), chunk_len as usize); |

606 | let (fst, tail) = {rest}.split_at_mut(chunk_len); |

607 | fst.sort(); |

608 | chunks.push(fst.iter().cloned()); |

609 | rest = tail; |

610 | } |

611 | |

612 | // println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len()))); |

613 | |

614 | c.bench_function("kmerge tenway", move |b| { |

615 | b.iter(|| { |

616 | chunks.iter().cloned().kmerge().count() |

617 | }) |

618 | }); |

619 | } |

620 | |

621 | fn fast_integer_sum<I>(iter: I) -> I::Item |

622 | where I: IntoIterator, |

623 | I::Item: Default + Add<Output=I::Item> |

624 | { |

625 | iter.into_iter().fold(<_>::default(), |x, y| x + y) |

626 | } |

627 | |

628 | fn step_vec_2(c: &mut Criterion) { |

629 | let v = vec![0; 1024]; |

630 | |

631 | c.bench_function("step vec 2", move |b| { |

632 | b.iter(|| { |

633 | fast_integer_sum(cloned(v.iter().step_by(2))) |

634 | }) |

635 | }); |

636 | } |

637 | |

638 | fn step_vec_10(c: &mut Criterion) { |

639 | let v = vec![0; 1024]; |

640 | |

641 | c.bench_function("step vec 10", move |b| { |

642 | b.iter(|| { |

643 | fast_integer_sum(cloned(v.iter().step_by(10))) |

644 | }) |

645 | }); |

646 | } |

647 | |

648 | fn step_range_2(c: &mut Criterion) { |

649 | let v = black_box(0..1024); |

650 | |

651 | c.bench_function("step range 2", move |b| { |

652 | b.iter(|| { |

653 | fast_integer_sum(v.clone().step_by(2)) |

654 | }) |

655 | }); |

656 | } |

657 | |

658 | fn step_range_10(c: &mut Criterion) { |

659 | let v = black_box(0..1024); |

660 | |

661 | c.bench_function("step range 10", move |b| { |

662 | b.iter(|| { |

663 | fast_integer_sum(v.clone().step_by(10)) |

664 | }) |

665 | }); |

666 | } |

667 | |

668 | fn cartesian_product_iterator(c: &mut Criterion) { |

669 | let xs = vec![0; 16]; |

670 | |

671 | c.bench_function("cartesian product iterator", move |b| { |

672 | b.iter(|| { |

673 | let mut sum = 0; |

674 | for (&x, &y, &z) in iproduct!(&xs, &xs, &xs) { |

675 | sum += x; |

676 | sum += y; |

677 | sum += z; |

678 | } |

679 | sum |

680 | }) |

681 | }); |

682 | } |

683 | |

684 | fn cartesian_product_fold(c: &mut Criterion) { |

685 | let xs = vec![0; 16]; |

686 | |

687 | c.bench_function("cartesian product fold", move |b| { |

688 | b.iter(|| { |

689 | let mut sum = 0; |

690 | iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| { |

691 | sum += x; |

692 | sum += y; |

693 | sum += z; |

694 | }); |

695 | sum |

696 | }) |

697 | }); |

698 | } |

699 | |

700 | fn multi_cartesian_product_iterator(c: &mut Criterion) { |

701 | let xs = [vec![0; 16], vec![0; 16], vec![0; 16]]; |

702 | |

703 | c.bench_function("multi cartesian product iterator", move |b| { |

704 | b.iter(|| { |

705 | let mut sum = 0; |

706 | for x in xs.iter().multi_cartesian_product() { |

707 | sum += x[0]; |

708 | sum += x[1]; |

709 | sum += x[2]; |

710 | } |

711 | sum |

712 | }) |

713 | }); |

714 | } |

715 | |

716 | fn multi_cartesian_product_fold(c: &mut Criterion) { |

717 | let xs = [vec![0; 16], vec![0; 16], vec![0; 16]]; |

718 | |

719 | c.bench_function("multi cartesian product fold", move |b| { |

720 | b.iter(|| { |

721 | let mut sum = 0; |

722 | xs.iter().multi_cartesian_product().fold((), |(), x| { |

723 | sum += x[0]; |

724 | sum += x[1]; |

725 | sum += x[2]; |

726 | }); |

727 | sum |

728 | }) |

729 | }); |

730 | } |

731 | |

732 | fn cartesian_product_nested_for(c: &mut Criterion) { |

733 | let xs = vec![0; 16]; |

734 | |

735 | c.bench_function("cartesian product nested for", move |b| { |

736 | b.iter(|| { |

737 | let mut sum = 0; |

738 | for &x in &xs { |

739 | for &y in &xs { |

740 | for &z in &xs { |

741 | sum += x; |

742 | sum += y; |

743 | sum += z; |

744 | } |

745 | } |

746 | } |

747 | sum |

748 | }) |

749 | }); |

750 | } |

751 | |

752 | fn all_equal(c: &mut Criterion) { |

753 | let mut xs = vec![0; 5_000_000]; |

754 | xs.extend(vec![1; 5_000_000]); |

755 | |

756 | c.bench_function("all equal", move |b| { |

757 | b.iter(|| xs.iter().all_equal()) |

758 | }); |

759 | } |

760 | |

761 | fn all_equal_for(c: &mut Criterion) { |

762 | let mut xs = vec![0; 5_000_000]; |

763 | xs.extend(vec![1; 5_000_000]); |

764 | |

765 | c.bench_function("all equal for", move |b| { |

766 | b.iter(|| { |

767 | for &x in &xs { |

768 | if x != xs[0] { |

769 | return false; |

770 | } |

771 | } |

772 | true |

773 | }) |

774 | }); |

775 | } |

776 | |

777 | fn all_equal_default(c: &mut Criterion) { |

778 | let mut xs = vec![0; 5_000_000]; |

779 | xs.extend(vec![1; 5_000_000]); |

780 | |

781 | c.bench_function("all equal default", move |b| { |

782 | b.iter(|| xs.iter().dedup().nth(1).is_none()) |

783 | }); |

784 | } |

785 | |

786 | const PERM_COUNT: usize = 6; |

787 | |

788 | fn permutations_iter(c: &mut Criterion) { |

789 | struct NewIterator(Range<usize>); |

790 | |

791 | impl Iterator for NewIterator { |

792 | type Item = usize; |

793 | |

794 | fn next(&mut self) -> Option<Self::Item> { |

795 | self.0.next() |

796 | } |

797 | } |

798 | |

799 | c.bench_function("permutations iter", move |b| { |

800 | b.iter(|| { |

801 | for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) { |

802 | |

803 | } |

804 | }) |

805 | }); |

806 | } |

807 | |

808 | fn permutations_range(c: &mut Criterion) { |

809 | c.bench_function("permutations range", move |b| { |

810 | b.iter(|| { |

811 | for _ in (0..PERM_COUNT).permutations(PERM_COUNT) { |

812 | |

813 | } |

814 | }) |

815 | }); |

816 | } |

817 | |

818 | fn permutations_slice(c: &mut Criterion) { |

819 | let v = (0..PERM_COUNT).collect_vec(); |

820 | |

821 | c.bench_function("permutations slice", move |b| { |

822 | b.iter(|| { |

823 | for _ in v.as_slice().iter().permutations(PERM_COUNT) { |

824 | |

825 | } |

826 | }) |

827 | }); |

828 | } |

829 | |

830 | criterion_group!( |

831 | benches, |

832 | slice_iter, |

833 | slice_iter_rev, |

834 | zip_default_zip, |

835 | zipdot_i32_default_zip, |

836 | zipdot_f32_default_zip, |

837 | zip_default_zip3, |

838 | zip_slices_ziptuple, |

839 | zipslices, |

840 | zipslices_mut, |

841 | zipdot_i32_zipslices, |

842 | zipdot_f32_zipslices, |

843 | zip_checked_counted_loop, |

844 | zipdot_i32_checked_counted_loop, |

845 | zipdot_f32_checked_counted_loop, |

846 | zipdot_f32_checked_counted_unrolled_loop, |

847 | zip_unchecked_counted_loop, |

848 | zipdot_i32_unchecked_counted_loop, |

849 | zipdot_f32_unchecked_counted_loop, |

850 | zip_unchecked_counted_loop3, |

851 | group_by_lazy_1, |

852 | group_by_lazy_2, |

853 | slice_chunks, |

854 | chunks_lazy_1, |

855 | equal, |

856 | merge_default, |

857 | merge_by_cmp, |

858 | merge_by_lt, |

859 | kmerge_default, |

860 | kmerge_tenway, |

861 | step_vec_2, |

862 | step_vec_10, |

863 | step_range_2, |

864 | step_range_10, |

865 | cartesian_product_iterator, |

866 | cartesian_product_fold, |

867 | multi_cartesian_product_iterator, |

868 | multi_cartesian_product_fold, |

869 | cartesian_product_nested_for, |

870 | all_equal, |

871 | all_equal_for, |

872 | all_equal_default, |

873 | permutations_iter, |

874 | permutations_range, |

875 | permutations_slice, |

876 | ); |

877 | criterion_main!(benches); |

878 |