Skip to content

Instantly share code, notes, and snippets.

@KeenS
Last active March 19, 2018 11:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KeenS/35345a4661dc696f467abd2de830568d to your computer and use it in GitHub Desktop.
Save KeenS/35345a4661dc696f467abd2de830568d to your computer and use it in GitHub Desktop.
$ smlsharp -v
SML# 3.4.0 (2017-08-31 19:31:44 JST) for x86_64-pc-linux-gnu with LLVM 3.7.1
$ smlsharp -O3 inner_prod.sml -o inner_prod_smlsharp
$ ./inner_prod_smlsharp
compose
Time:
[Total] 9101 ms/10calls
[Average] 910.1 ms/call
loop
Time:
[Total] 935 ms/10calls
[Average] 93.5 ms/call
$ smlsharp -dinsertCheckGC=no -O3 inner_prod.sml -o inner_prod_smlsharp
$ ./inner_prod_smlsharp
compose
Time:
[Total] 3264 ms/10calls
[Average] 326.4 ms/call
loop
Time:
[Total] 732 ms/10calls
[Average] 73.2 ms/call
$ mlton
MLton 20130715 (built Fri Apr 28 06:06:34 UTC 2017 on lcy01-11)
$ mlton -output inner_prod_mlton inner_prod.sml
$ ./inner_prod_mlton
compose
Time:
[Total] 650 ms/10calls
[Average] 65 ms/call
loop
Time:
[Total] 48 ms/10calls
[Average] 4.8 ms/call
$ mlton -output inner_prod_mlton_opt -link-opt -O3 -cc-opt -O3 -codegen native inner_prod.sml
$ ./inner_prod_mlton_opt
compose
Time:
[Total] 654 ms/10calls
[Average] 65.4 ms/call
loop
Time:
[Total] 48 ms/10calls
[Average] 4.8 ms/call
$ sml inner_prod.sml
Standard ML of New Jersey v110.79 [built: Tue Aug 8 23:21:20 2017]
[opening inner_prod.sml]
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
compose
Time:
[Total] 3292 ms/10calls
[Average] 329.2 ms/call
loop
Time:
[Total] 32 ms/10calls
[Average] 3.2 ms/call
# data size is /10 ed to avoid stack overflow
$ ocamlopt --version
4.06.0
$ ocamlfind ocamlopt -O3 -o inner_product_ocaml -thread -linkpkg -package core_bench,core inner_prod.ml
$ ./inner_product_ocaml
Estimated testing time 20s (2 benchmarks x 10s). Change using -quota SECS.
┌─────────┬─────────────┬──────────┬──────────┬──────────┬────────────┐
│ Name │ Time/Run │ mWd/Run │ mjWd/Run │ Prom/Run │ Percentage │
├─────────┼─────────────┼──────────┼──────────┼──────────┼────────────┤
│ compose │ 13_845.52us │ 900.04kw │ 648.95kw │ 648.95kw │ 100.00% │
│ loop │ 299.47us │ │ │ │ 2.16% │
└─────────┴─────────────┴──────────┴──────────┴──────────┴────────────┘
# data size is x10 ed for measure accuracy
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.0.2
$ ghc -O3 inner_prod.hs -o inner_prod_hs
[1 of 1] Compiling Main ( inner_prod.hs, inner_prod.o )
Linking inner_prod_hs ...
$ ./inner_prod_hs
compose (foldr): 0.829559656s
compose (foldl): 0.056206145s
loop : 0.055309029s
import Control.Exception
import Data.Time
innerProd1 :: [Int] -> [Int] -> Int
innerProd1 l1 l2 = foldr (+) 0 $ map (uncurry (*)) $ zip l1 l2
innerProd1' :: [Int] -> [Int] -> Int
innerProd1' l1 l2 = foldl (+) 0 $ map (uncurry (*)) $ zip l1 l2
innerProd2 :: [Int] -> [Int] -> Int
innerProd2 l1 l2 = loop l1 l2 0
where loop [] _ acc = acc
loop _ [] acc = acc
loop (x:xs) (y:ys) acc = loop xs ys (acc + x*y)
clockSomething :: String -> a -> IO ()
clockSomething name something = do
putStr $ name ++ ": "
start <- getCurrentTime
_ <- evaluate something
end <- getCurrentTime
print (diffUTCTime end start)
main :: IO ()
main = do
clockSomething "compose (foldr)" $ innerProd1 list list
clockSomething "compose (foldl)" $ innerProd1' list list
clockSomething "loop " $ innerProd2 list list
where list = take (10 * 1000 * 1000) [1,1..]
let inner_prod1 (l1, l2) = List.fold_left (+) 0 (List.map (fun (a, b) -> a * b) (List.combine l1 l2))
let inner_prod2 (l1, l2) = List.fold_left2 (fun acc a b -> acc + a * b) 0 l1 l2
open Core_bench
let () = let list = let rec loop acc = function
0 -> acc
| n -> loop (1::acc) (n-1)
in loop [] (100 * 1000)
in
Core.Command.run (Bench.make_command [
Bench.Test.create ~name: "compose"
(fun () -> inner_prod1 (list, list));
Bench.Test.create ~name: "loop"
(fun () -> inner_prod2 (list, list))
])
_require "basis.smi"
structure Benchmark =
struct
fun repeat 0 f = ()
| repeat n f = (f ();repeat (n - 1) f)
fun bench n f = let
val startTime = Time.now ()
val _ = repeat n f
val endTime = Time.now ()
in
Time.toMilliseconds (Time.-(endTime, startTime))
end
fun benchmark name n f = let
val time = bench n f
in
print (name ^ "\n");
print (" Time:\n");
print (" [Total] " ^ (LargeInt.toString time) ^ " ms/" ^ (Int.toString n) ^ "calls\n");
print (" [Average] " ^ (Real.toString((Real.fromLargeInt time) / (Real.fromInt n))) ^ " ms/call\n")
end
fun nChars n char = CharArray.vector(CharArray.array(n, char))
fun toWidth width str = let
val len = String.size str
in
if len < width
then str ^ (nChars (width - len) #" ")
else str
end
fun histLine width base value =
(nChars (Int.fromLarge(width * value div base)) #"*") ^ "\n"
fun benchset name n fs = let
val res = List.map (fn (label, f) => (label, bench n f)) fs
val max = List.foldl (fn ((_, time), m) => LargeInt.max(time, m)) 0 res
val maxLen = List.foldl (fn ((label, _), m) => Int.max(String.size label, m)) 0 fs
in
print "name:\n";
print ((nChars ((String.size " ") + maxLen) #"-") ^ "+" ^ (nChars ((String.size "|") + 50) #"-") ^ "\n");
app (fn (label, time) => print(" " ^ (toWidth maxLen label) ^ "|" ^(histLine (50:LargeInt.int) max time))) res;
print ((nChars ((String.size " ") + maxLen) #"-") ^ "+" ^ (nChars ((String.size "|") + 50) #"-") ^ "\n")
end
end
val inner_product1 = List.foldl op+ 0 o List.map op* o ListPair.zip
fun inner_product2 (l1, l2) = let
fun loop [] _ acc = acc
| loop _ [] acc = acc
| loop (x::xs) (y::ys) acc = loop xs ys (acc + x*y)
in
loop l1 l2 0
end
val _ = let
(* [1, 1, 1, ...] *)
val list = List.tabulate(1000 * 1000, fn _ => 1)
in
Benchmark.benchmark "compose" 10 (fn _ => inner_product1(list, list));
Benchmark.benchmark "loop" 10 (fn _ => inner_product2(list, list))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment