I came across some interesting benchmark results recently, and I figured I'd give a short writeup.

The benchmark is based on a subset of wc's functionality - we wish to traverse a directory, ignoring hidden files, and printing out the number of lines in each file as well as a total.

Our ATS implementation is taken from the documentation, with a couple small changes to make it faster.

%{^ #ifdef ATS_MEMALLOC_GCBDW #undef GC_H #define GC_THREADS #endif %}

#include "prelude/DATS/filebas.dats" #include "share/atspre_staload.hats" #include "share/atspre_staload_libats_ML.hats" #include "libats/libc/DATS/dirent.dats" #include "libats/ML/DATS/filebas_dirent.dats" #include "libats/DATS/athread_posix.dats" #include "$PATSHOMELOCS/atscntrb-bucs320-divideconquerpar/mylibies.hats" #include "$PATSHOMELOCS/atscntrb-bucs320-divideconquerpar/mydepies.hats" #include "$PATSHOMELOCS/ats-linecount-0.2.3/lines.dats"

#staload $DivideConquer #staload $DivideConquerPar #staload FWS = $FWORKSHOP_chanlst

assume input_t0ype = string assume output_t0ype = int

typedef fworkshop = $FWS.fworkshop

fun as_char(s : string) : charNZ = $UN.ptr0_get(string2ptr(s))

fun dir_skipped(dir : string) : bool = case+ dir of | "." => true | ".." => true | _ when length(dir) > 0 => as_char(dir) = '.' | _ => false

fun DirWalk(fws : fworkshop, fname : string, fopr : cfun(string, int)) : int = let val () = $tempenver(fws) val () = $tempenver(fopr)

implement DivideConquer$base_test<> (fname) =
  (test_file_isdir(fname) = 0)

implement DivideConquer$base_solve<> (fname) =
  fopr(fname)

implement DivideConquer$divide<> (dir) =
  (let
    var files = streamize_dirname_fname(dir)
    var files = stream_vt_filter_cloptr<string>( files
                                               , lam (x) => ~dir\_skipped(x)
                                               )
    var files = stream_vt_map_cloptr<string><string>( files
                                                    , lam (file) =>
                                                        string\_append3(dir, "/", file)
                                                    )
  in
    list0_of_list_vt(stream2list_vt(files))
  end)

implement DivideConquer$conquer$combine<> (_, rs) =
  (list0_foldleft<int><int>(rs, 0, lam (res, r) => res + r))

implement DivideConquerPar$fworkshop<> () =
  FWORKSHOP_chanlst(fws)

in DivideConquer$solve<>(fname) end

#define NCPU 4

implement main0 (argc, argv) = { var fws = $FWS.fworkshopcreateexn() var added = $FWS.fworkshopaddnworker(fws, NCPU) var root = (if argc >= 2 then argv[1] else ".") : string var nfile = DirWalk(fws, root, lam (fname) => let var nline = wc_line(fname) val _ = println!(fname, ": ", nline) in nline end) val () = println!("Total number of lines:\n ", nfile) }

You can see the full code here; it is built with atspkg.

The equivalent Rust code:

extern crate ignore;

use ignore::WalkBuilder; use std::sync::atomic::{AtomicUsize, Ordering}; use std::fs::File; use std::io::prelude::*; use ignore::WalkState::*; use std::sync::Arc; use std::env::args;

fn main() { let dir = match args().skip(1).next() { Some(x) => x, _ => ".".to_string(), }; let acc = Arc::new(AtomicUsize::new(0)); let _ = WalkBuilder::new(dir) .ignore(false) .threads(4) .git_global(false) .git_ignore(false) .git_exclude(false) .parents(false) .build_parallel() .run(|| { let acc_in = Arc::clone(&acc); Box::new(move |result| { let pp = result.unwrap(); let p = pp.path(); let file = File::open(&p); match file { Ok(mut f) => { let mut contents = String::new(); let lines = match f.readtostring(&mut contents) { Ok(_) => contents.lines().count(), _ => 0, }; println!("{}: {}", p.display(), lines); acc_in.fetch_add(lines, Ordering::SeqCst); } _ => (), }; Continue }) }); let res = Arc::try_unwrap(acc).unwrap().into_inner(); println!("Total number of lines:\n {}", res); }

And finally results:

Command Lanuage Time
awc ATS 173.7 ms
wc -l C 291.4 ms
rs-wc Rust 76.76 ms

As we can see, Rust remains queen of concurrency. ATS surpasses wc even with garbage collection, which is impressive, but it does not approach Rust.