mirror of
				https://github.com/roc-lang/roc.git
				synced 2025-10-31 05:04:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| #[path = "../src/helpers/mod.rs"]
 | |
| mod helpers;
 | |
| 
 | |
| // defines roc_alloc and friends
 | |
| pub use helpers::platform_functions::*;
 | |
| 
 | |
| use bumpalo::Bump;
 | |
| use criterion::{black_box, criterion_group, criterion_main, Criterion};
 | |
| use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult, run_roc_dylib};
 | |
| use roc_mono::ir::OptLevel;
 | |
| use roc_std::RocList;
 | |
| 
 | |
| // results April 9, 2023
 | |
| //
 | |
| // > pure roc quicksort      time:   [106.97 us 107.27 us 107.63 us]
 | |
| // > roc zig quicksort       time:   [34.765 us 35.301 us 35.865 us]
 | |
| // > rust std sort           time:   [20.413 us 20.623 us 20.838 us]
 | |
| 
 | |
| type Input = RocList<i64>;
 | |
| type Output = RocList<i64>;
 | |
| 
 | |
| type Main<I, O> = unsafe extern "C" fn(I, *mut RocCallResult<O>);
 | |
| 
 | |
| const ZIG_ROC_QUICKSORT: &str = indoc::indoc!(
 | |
|     r#"
 | |
|     app "bench" provides [main] to "./platform"
 | |
| 
 | |
|     main : List I64 -> List I64
 | |
|     main = \originalList -> List.sortAsc originalList
 | |
|     "#
 | |
| );
 | |
| 
 | |
| const PURE_ROC_QUICKSORT: &str = indoc::indoc!(
 | |
|     r#"
 | |
|     app "bench" provides [main] to "./platform"
 | |
| 
 | |
|     main : List I64 -> List I64
 | |
|     main = \originalList ->
 | |
|         n = List.len originalList
 | |
| 
 | |
|         quicksortHelp originalList 0 (n - 1)
 | |
| 
 | |
|     quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
 | |
|     quicksortHelp = \list, low, high ->
 | |
|         if low < high then
 | |
|             when partition low high list is
 | |
|                 Pair partitionIndex partitioned ->
 | |
|                     partitioned
 | |
|                     |> quicksortHelp low (partitionIndex - 1)
 | |
|                     |> quicksortHelp (partitionIndex + 1) high
 | |
|         else
 | |
|             list
 | |
| 
 | |
|     partition : Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]
 | |
|     partition = \low, high, initialList ->
 | |
|         when List.get initialList high is
 | |
|             Ok pivot ->
 | |
|                 when partitionHelp low low initialList high pivot is
 | |
|                     Pair newI newList ->
 | |
|                         Pair newI (List.swap newList newI high)
 | |
| 
 | |
|             Err _ ->
 | |
|                 Pair low initialList
 | |
| 
 | |
|     partitionHelp : Nat, Nat, List (Num c), Nat, Num c -> [Pair Nat (List (Num c))]
 | |
|     partitionHelp = \i, j, list, high, pivot ->
 | |
|         if j < high then
 | |
|             when List.get list j is
 | |
|                 Ok value ->
 | |
|                     if value <= pivot then
 | |
|                         partitionHelp (i + 1) (j + 1) (List.swap list i j) high pivot
 | |
|                     else
 | |
|                         partitionHelp i (j + 1) list high pivot
 | |
| 
 | |
|                 Err _ ->
 | |
|                     Pair i list
 | |
|         else
 | |
|             Pair i list
 | |
|     "#
 | |
| );
 | |
| 
 | |
| fn roc_function<'a>(
 | |
|     arena: &'a Bump,
 | |
|     source: &str,
 | |
| ) -> libloading::Symbol<'a, Main<*mut Input, Output>> {
 | |
|     let config = helpers::llvm::HelperConfig {
 | |
|         mode: LlvmBackendMode::GenTest,
 | |
|         ignore_problems: false,
 | |
|         add_debug_info: true,
 | |
|         opt_level: OptLevel::Optimize,
 | |
|     };
 | |
| 
 | |
|     let context = inkwell::context::Context::create();
 | |
|     let (main_fn_name, errors, lib) =
 | |
|         helpers::llvm::helper(arena, config, source, arena.alloc(context));
 | |
| 
 | |
|     assert!(errors.is_empty(), "Encountered errors:\n{}", errors);
 | |
| 
 | |
|     run_roc_dylib!(arena.alloc(lib), main_fn_name, *mut Input, Output)
 | |
| }
 | |
| 
 | |
| pub fn criterion_benchmark(c: &mut Criterion) {
 | |
|     let arena = Bump::new();
 | |
| 
 | |
|     let pure_roc_quicksort_main = roc_function(&arena, PURE_ROC_QUICKSORT);
 | |
|     let roc_zig_quicksort_main = roc_function(&arena, ZIG_ROC_QUICKSORT);
 | |
| 
 | |
|     let input_numbers: Vec<_> = std::iter::repeat([1, 2, 3, 4, 5, 6, 7, 8])
 | |
|         .flatten()
 | |
|         .take(1000)
 | |
|         .collect();
 | |
| 
 | |
|     let input = arena.alloc(RocList::from_slice(&input_numbers));
 | |
| 
 | |
|     c.bench_function("pure roc quicksort", |b| {
 | |
|         b.iter(|| unsafe {
 | |
|             let mut main_result = RocCallResult::default();
 | |
| 
 | |
|             assert!(input.is_unique());
 | |
| 
 | |
|             // reset_input
 | |
|             input.copy_from_slice(&input_numbers);
 | |
| 
 | |
|             pure_roc_quicksort_main(black_box(input), &mut main_result);
 | |
|         })
 | |
|     });
 | |
| 
 | |
|     c.bench_function("roc zig quicksort", |b| {
 | |
|         b.iter(|| unsafe {
 | |
|             let mut main_result = RocCallResult::default();
 | |
| 
 | |
|             assert!(input.is_unique());
 | |
| 
 | |
|             // reset_input
 | |
|             input.copy_from_slice(&input_numbers);
 | |
| 
 | |
|             roc_zig_quicksort_main(black_box(input), &mut main_result);
 | |
|         })
 | |
|     });
 | |
| 
 | |
|     c.bench_function("rust std sort", |b| {
 | |
|         b.iter(|| unsafe {
 | |
|             assert!(input.is_unique());
 | |
| 
 | |
|             // reset_input
 | |
|             input.copy_from_slice(&input_numbers);
 | |
| 
 | |
|             // an attempt to block optimizing based on the input list
 | |
|             let ptr = black_box(input.as_mut_ptr());
 | |
|             let input = std::slice::from_raw_parts_mut(ptr, 1000);
 | |
| 
 | |
|             input.sort()
 | |
|         })
 | |
|     });
 | |
| }
 | |
| 
 | |
| criterion_group!(quicksort_benches, criterion_benchmark);
 | |
| criterion_main!(quicksort_benches);
 | 
