an ocaml performance test

Mark Hayden (hayden@cs.cornell.edu)
Thu, 4 Jul 1996 02:55:45 -0400

Date: Thu, 4 Jul 1996 02:55:45 -0400
Message-Id: <199607040655.CAA13173@verdandi.cs.cornell.edu>
From: Mark Hayden <hayden@cs.cornell.edu>
To: caml-list@pauillac.inria.fr
Subject: an ocaml performance test

Several months back I asked this mailing list
if anyone had any tests for gauging the
performance of basic operations in ocaml. I got
some responses, but no data, so I put together a
test program, which I'm posting for others who
might be interested. The tests are intended to
give a sense of relative costs of similar
operations within ocaml. The output was
gathered by running the program on a
sparcstation 10 from Ocaml 1.01, compiled with
the "ocamlopt -unsafe".
The numbers in the table are meaningless on
their own. The test program below should also
be examined to see exactly what is being
measured.
Many of the tests are straightforward to
interpret. For example, it appears that
scanning an array with Array.iter is
considerably slow than with a for loop. I'm not
sure, however, how to interpret the tests
measuring the performance of function
application to various kinds of closures (marked
"partial" in the table). I have some guesses,
but I would appreciate an explanation from
someone who knows what is going on.

thanks, Mark Hayden

OUTPUT

null : 000.2958 usec

1 arg : 000.0782 usec
2 arg : 000.0978 usec
3 arg : 000.1236 usec
partial : 000.2286 usec
partial(a) : 000.2326 usec
partial(b) : 000.2247 usec
partial(c) : 000.0899 usec
magic : -00.0032 usec
let : -00.0001 usec
succ : 000.0140 usec
hashtbl:int : 002.5633 usec
array:for:0000 : 000.1085 usec
Array.iter:let:0000 : 000.3845 usec
Array.iter:fun:0000 : 000.8096 usec
array:for:0010 : 000.7928 usec
Array.iter:let:0010 : 004.7812 usec
Array.iter:fun:0010 : 005.4675 usec
array:vect:1000 : 090.7683 usec
Array.iter:let:1000 : 440.9373 usec
Array.iter:fun:1000 : 453.8632 usec
let rec list:1000 : 100.0212 usec
List.iter:let:1000 : 307.8812 usec
List.iter:fun:1000 : 312.9682 usec
gettimeofday : 011.4198 usec
select : 118.0977 usec

TESTPERF.ML:

open Printf

let i a = a
let v0 = Array.create 0 ()
let v10 = Array.create 10 ()
let v1000 = Array.create 1000 ()
let l1000 = Array.to_list v1000

let f1 a = a
let f2 a b = a
let f3 a b c = a

let f2a = fun () -> fun () -> ()
let f2b = fun a -> fun b -> a
let f2c = fun a -> let c = () in fun b -> a

let f2p = f2 ()
let f2pa = f2a ()
let f2pb = f2b ()
let f2pc = f2c ()

let h = Hashtbl.create 10
let hi = 234
let hv = 123
let _ = Hashtbl.add h hi hv

let zero = 0.0

let tests = [
1E7, "null", i ;

1E6, "1 arg",
(fun () -> f1 ()) ;

1E6, "2 arg",
(fun () -> f2 () ()) ;

1E6, "3 arg",
(fun () -> f3 () () ()) ;

1E6, "partial",
(fun () -> f2p ()) ;

1E6, "partial(a)",
(fun () -> f2pa ()) ;

1E6, "partial(b)",
(fun () -> f2pb ()) ;

1E6, "partial(c)",
(fun () -> f2pc ()) ;

1E6, "magic",
(fun () -> Obj.magic (Obj.repr ())) ;

1E6, "let",
(fun () -> let a = () in a) ;

1E6, "succ",
(fun () -> succ 5 ; ()) ;

1E5, "hashtbl:int",
(fun () -> Hashtbl.find h hi ; ()) ;

1E5, "array:for:0000",
(fun () -> for i = 0 to pred (Array.length v0) do () done) ;

1E5, "Array.iter:let:0000",
(fun () -> Array.iter i v0) ;

1E5, "Array.iter:fun:0000",
(fun () -> Array.iter (fun a -> a) v0) ;

1E4, "array:for:0010",
(fun () -> for i = 0 to pred (Array.length v10) do () done) ;

1E4, "Array.iter:let:0010",
(fun () -> Array.iter i v10) ;

1E4, "Array.iter:fun:0010",
(fun () -> Array.iter (fun a -> a) v10) ;

1E3, "array:for:1000",
(fun () -> for i = 0 to pred (Array.length v1000) do () done) ;

1E3, "Array.iter:let:1000",
(fun () -> Array.iter i v1000) ;

1E3, "Array.iter:fun:1000",
(fun () -> Array.iter (fun a -> a) v1000) ;

1E3, "let rec list:1000",
(fun () -> let rec loop = function [] -> () | hd::tl -> loop tl in loop l1000) ;

1E3, "List.iter:let:1000",
(fun () -> List.iter i l1000) ;

1E3, "List.iter:fun:1000",
(fun () -> List.iter (fun a -> a) l1000) ;

1E4, "gettimeofday",
(fun () -> Unix.gettimeofday () ; ()) ;

1E4, "select",
(fun () -> Unix.select [] [] [] zero ; ())
]

let ntests = 1000

let run () =
let adjust = ref 0.0 in
List.iter (fun (ntests,name,f) ->
let ntests = truncate ntests in
let start = Unix.gettimeofday () in
for i = 1 to ntests do f () done ;
let stop = Unix.gettimeofday () in
let time = ((stop -. start) /. (float ntests)) *. 1000000.0 in
printf "%30s : %08.4f usec\n" name (time -. !adjust) ;
flush stdout ;
if name = "null" then (
adjust := time ;
printf "\n"
)
) tests

let _ = run ()

COMPILE

testperf: testperf.ml
ocamlopt -unsafe -o testperf unix.cmxa testperf.ml -cclib -lunix