Roger said:
Well, actually I used BigDecimal, but that made no difference for the
test. I also made a version using long instead of BigDecimal. With longs
10000000 iterations took about .54 seconds, so about twice as fast. I'm
not sure how to correctly rewrite the Ocaml program to use the native
int. I'll post my program rewritten for long instead, so if you also
post the Ocaml program, then we can both compare relative performance.
Jon gave me a Ocaml version that uses native integers (I tried writing
it myself, but is is a long time since I used a functional language, an
Haskell isn't quite the same as Ocaml). Anyway, here are my results.
(the Ocaml version is posted below).
taskset -c 0 \time -v ./simplifyint 10000000 5
[* x [+ [+ [* 12 0] [+ 23 8]] y]]
Bench 1
Took 0.635466s
Bench 2
Took 0.634575s
Bench 3
Took 0.634284s
Bench 4
Took 0.633329s
Bench 5
Took 0.633333s
[* x [+ 31 y]]
Command being timed: "./simplifyint 10000000 5"
User time (seconds): 3.17
System time (seconds): 0.00
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.17
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 0
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 287
Voluntary context switches: 1
Involuntary context switches: 8
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
[roger@pooh Reduce]$ taskset -c 0 \time -v java SimplifyLong 10000000 5
[* x [+ [+ [* 12 0] [+ 23 8]] y]]
Bench 0
Took 0.626 seconds
Bench 1
Took 0.546 seconds
Bench 2
Took 0.541 seconds
Bench 3
Took 0.556 seconds
Bench 4
Took 0.551 seconds
[* x [+ 31 y]]
Command being timed: "java SimplifyLong 10000000 5"
User time (seconds): 2.80
System time (seconds): 0.07
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.90
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 0
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 1
Minor (reclaiming a frame) page faults: 17429
Voluntary context switches: 2178
Involuntary context switches: 3483
Swaps: 0
File system inputs: 0
File system outputs: 64
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
[roger@pooh Reduce]$ \time -v ./simplifyint 10000000 5
[* x [+ [+ [* 12 0] [+ 23 8]] y]]
Bench 1
Took 0.612540s
Bench 2
Took 0.610459s
Bench 3
Took 0.611671s
Bench 4
Took 0.613096s
Bench 5
Took 0.611549s
[* x [+ 31 y]]
Command being timed: "./simplifyint 10000000 5"
User time (seconds): 3.05
System time (seconds): 0.00
Percent of CPU this job got: 99%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.06
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 0
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 287
Voluntary context switches: 1
Involuntary context switches: 19
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
[roger@pooh Reduce]$ \time -v java SimplifyLong 10000000 5
[* x [+ [+ [* 12 0] [+ 23 8]] y]]
Bench 0
Took 0.606 seconds
Bench 1
Took 0.554 seconds
Bench 2
Took 0.557 seconds
Bench 3
Took 0.561 seconds
Bench 4
Took 0.559 seconds
[* x [+ 31 y]]
Command being timed: "java SimplifyLong 10000000 5"
User time (seconds): 2.88
System time (seconds): 0.06
Percent of CPU this job got: 101%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.90
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 0
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 1
Minor (reclaiming a frame) page faults: 17509
Voluntary context switches: 2278
Involuntary context switches: 87
Swaps: 0
File system inputs: 0
File system outputs: 64
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
So on my system the Java version is slightly faster.
simplifyint.ml (All credit to Jon Harrop)
type t =
| Int of int
| Var of char
| Add of t * t
| Mul of t * t
let rec ( +: ) f g = match f, g with
| Int n, Int m -> Int (n + m)
| Int 0, e | e, Int 0 -> e
| f, Add(g, h) -> f +: g +: h
| f, g -> Add(f, g)
let rec ( *: ) f g = match f, g with
| Int n, Int m -> Int (n * m)
| Int 0, e | e, Int 0 -> Int 0
| Int 1, e | e, Int 1 -> e
| f, Mul(g, h) -> f *: g *: h
| f, g -> Mul(f, g)
let rec simplify = function
| Int _ | Var _ as f -> f
| Add (f, g) -> simplify f +: simplify g
| Mul (f, g) -> simplify f *: simplify g
open Format
let rec print ff = function
| Var x -> fprintf ff "%c" x
| Int n -> fprintf ff "%d" n
| Add(f, g) -> fprintf ff "[+ %a %a]" print f print g
| Mul(f, g) -> fprintf ff "[* %a %a]" print f print g
let e =
Mul(Var 'x', Add(Add(Mul(Int 12, Int 0), Add(Int 23, Int 8)), Var 'y'))
let n, m =
try
match Sys.argv with
| [|_; n; m|] -> int_of_string n, int_of_string m
| _ -> raise Exit
with _ -> 10000000, 10
let () =
fprintf std_formatter "%a\n%!" print e;
for i=1 to m do
Printf.printf "Bench %d\n%!" i;
let t = Unix.gettimeofday() in
for j=1 to n do
ignore(simplify e)
done;
Printf.printf "Took %fs\n%!" (Unix.gettimeofday() -. t)
done;
fprintf std_formatter "%a\n%!" print (simplify e)