On Mon, Nov 22, 2010 at 5:00 AM, Ralph <grkunt...@gmail.com> wrote:

> On the Programming Languages Comparison Site (http://
> shootout.alioth.debian.org/u64/benchmark.php?
> test=all&lang=clojure&lang2=fsharp), if you run the Clojure vs. F#
> comparison, Clojure scores about the same in speed as F# (but does use
> more memory).
>

As a preview of things to come soon, I've been focusing on adding
instrumentation to my clojure-benchmarks github repository that measure
memory usage.  I realized some time ago that the reason many of the Clojure
benchmark programs use so much memory is that the default JVM heap size is
quite large.  Thus if a Clojure program allocates memory *at all* in the
main loop, and if you run that main loop long enough, it will fill up the
available heap before a garbage collection is triggered.  Such a program
will be measured as using all of that memory, even though it didn't "need
it".  The memory use measurements on the benchmark can in many cases be
significantly reduced, with little or no increase in run time, by selecting
an appropriate value for the JVM -Xmx maximum heap size parameter.

I have some Perl programs I've hacked together that on Windows + Cygwin, Mac
OS X, and Linux, will run a program multiple times while varying the -Xmx
heap size limit.  It first uses binary search to find the smallest heap size
at which the program produces correct output, and then it does a "sweep"
starting at that value X, and runs the program for several somewhat larger
limits, to see if a small amount of additional heap space will reduce the GC
time noticeably.

While doing that, it is saving all of the details of the runs in an XML
file, and printing summaries of a few statistics on the console.  Below is
an example of the console output running the k-nucleotide benchmark program
on an input that is significantly smaller than the official benchmark input
(I often run these programs on smaller input sizes during testing so I can
get results without growing too much older in the process).  I give a pretty
detailed explanation of what this output means below that, in case you are
curious.

All of this is in the clojure-benchmarks github repo now, although I will be
improving it some more for a while (parsing HotSpot GC log files better,
parsing GC logs for JRockit, correcting the Max RSS calculations on Mac OS X
10.6.x, etc.)  I'll warn you that the command line options are pretty
numerous, but mostly documented.  Testing so far has been limited to Mac OS
X, Ubuntu Linux, and Windows + Cygwin.

https://github.com/jafingerhut/clojure-benchmarks

git clone git://github.com/jafingerhut/clojure-benchmarks.git

Andy Fingerhut


Example output from "tmcurve" program, with line numbers prepended for
reference:

 1  % ../bin/tmcurve --verbose --jvm-gc-stats --delta 8 --sorted-summary
--results-file results.xml --min 1 --precision 1 --input
input/medium-input.txt --output output/medium-clj-1.2-output.txt --check
'diff --strip-trailing-cr --brief output/medium-expected-output.txt %o' java
-server -Xmx%mbm -classpath
/Users/andy/lein/swank-clj-1.2.0/lib/clojure-1.2.0.jar:./obj/clj-1.2
knucleotide 1
 2  Looking for smallest memory size that succeeds.
 3
 4  Max heap=128 MB succeed  cpu=19.3 sec  Max RSS=125.4 MB  RSS-heap=-2.6
MB  GC tot space=2847.5 MB time=0.7 sec max live=63.1 MB
 5  Max heap=64 MB succeed  cpu=20.517 sec  Max RSS=103.9 MB  RSS-heap=39.9
MB  GC tot space=2860.7 MB time=1.0 sec max live=44.9 MB
 6  Max heap=32 MB succeed  cpu=62.947 sec  Max RSS=87.8 MB  RSS-heap=55.8
MB  GC tot space=2871.1 MB time=43.7 sec max live=25.0 MB
 7  Files output/medium-expected-output.txt and
output/medium-clj-1.2-output.txt differ
 8  check output cmd 'diff --strip-trailing-cr --brief
output/medium-expected-output.txt output/medium-clj-1.2-output.txt' exited
with error status 1
 9  Copy of output file 'output/medium-clj-1.2-output.txt' (length 0 bytes)
saved as 'measureproc-3JpxmO/5A7grwwKdK'
10  Max heap=16 MB fail  cpu=4.077 sec  Max RSS=58.7 MB  RSS-heap=42.7 MB
GC tot space=97.1 MB time=0.6 sec max live=11.6 MB
11  Now perform binary search on range [16,32]
12  Files output/medium-expected-output.txt and
output/medium-clj-1.2-output.txt differ
13  check output cmd 'diff --strip-trailing-cr --brief
output/medium-expected-output.txt output/medium-clj-1.2-output.txt' exited
with error status 1
14  Copy of output file 'output/medium-clj-1.2-output.txt' (length 0 bytes)
saved as 'measureproc-wzd8KX/_pSTbtcZc3'
15  Max heap=24 MB fail  cpu=4.456 sec  Max RSS=77.2 MB  RSS-heap=53.2 MB
GC tot space=97.1 MB time=0.8 sec max live=17.1 MB  new range [24,32]
16  Files output/medium-expected-output.txt and
output/medium-clj-1.2-output.txt differ
17  check output cmd 'diff --strip-trailing-cr --brief
output/medium-expected-output.txt output/medium-clj-1.2-output.txt' exited
with error status 1
18  Copy of output file 'output/medium-clj-1.2-output.txt' (length 0 bytes)
saved as 'measureproc-BNjL9y/tLMKZ_tXVq'
19  Max heap=28 MB fail  cpu=4.131 sec  Max RSS=72.2 MB  RSS-heap=44.2 MB
GC tot space=135.8 MB time=0.6 sec max live=21.9 MB  new range [28,32]
20  Files output/medium-expected-output.txt and
output/medium-clj-1.2-output.txt differ
21  check output cmd 'diff --strip-trailing-cr --brief
output/medium-expected-output.txt output/medium-clj-1.2-output.txt' exited
with error status 1
22  Copy of output file 'output/medium-clj-1.2-output.txt' (length 0 bytes)
saved as 'measureproc-sWmPCJ/S1SB7br3Hv'
23  Max heap=30 MB fail  cpu=4.063 sec  Max RSS=75.8 MB  RSS-heap=45.8 MB
GC tot space=135.8 MB time=0.5 sec max live=25.8 MB  new range [30,32]
24  Max heap=31 MB succeed  cpu=63.264 sec  Max RSS=76.4 MB  RSS-heap=45.4
MB  GC tot space=2871.9 MB time=44.5 sec max live=25.5 MB  new range [30,31]
25
26  Succeeded at 31 MB, failed at 30 MB
27
28  Sweep phase MB values to use: 31 39 47 55 63
29  Max heap=31 MB succeed  cpu=64.21 sec  Max RSS=80.0 MB  RSS-heap=49.0
MB  GC tot space=2868.8 MB time=45.6 sec max live=26.6 MB
30  Max heap=31 MB succeed  cpu=63.626 sec  Max RSS=79.9 MB  RSS-heap=48.9
MB  GC tot space=2875.1 MB time=44.4 sec max live=24.9 MB
31  Max heap=31 MB succeed  cpu=65.422 sec  Max RSS=80.0 MB  RSS-heap=49.0
MB  GC tot space=2869.7 MB time=46.3 sec max live=26.6 MB
32  Max heap=31 MB succeed  cpu=64.325 sec  Max RSS=75.3 MB  RSS-heap=44.3
MB  GC tot space=2875.1 MB time=45.8 sec max live=26.6 MB
33  Max heap=39 MB succeed  cpu=21.034 sec  Max RSS=83.4 MB  RSS-heap=44.4
MB  GC tot space=2861.7 MB time=1.4 sec max live=35.4 MB
34  Max heap=39 MB succeed  cpu=20.939 sec  Max RSS=82.5 MB  RSS-heap=43.5
MB  GC tot space=2858.2 MB time=1.5 sec max live=35.4 MB
35  Max heap=39 MB succeed  cpu=21.3 sec  Max RSS=90.6 MB  RSS-heap=51.6 MB
GC tot space=2863.2 MB time=1.4 sec max live=35.5 MB
36  Max heap=39 MB succeed  cpu=21.661 sec  Max RSS=91.1 MB  RSS-heap=52.1
MB  GC tot space=2864.3 MB time=1.5 sec max live=35.7 MB
37  Max heap=47 MB succeed  cpu=21.504 sec  Max RSS=98.9 MB  RSS-heap=51.9
MB  GC tot space=2854.2 MB time=1.9 sec max live=40.0 MB
38  Could not parse line 26 of file
/var/folders/dO/dOizZatdFUiWd11ofxhhPU+++TI/-Tmp-/Du7UdDBzIQ/qyTKNgBLn0.txt:
39  3.506: [GC-- 42528K->46648K(46656K), 0.0422814 secs]
40
/var/folders/dO/dOizZatdFUiWd11ofxhhPU+++TI/-Tmp-/VBRRJnGxyt/P7aYOLF3di:1:
parser error : Start tag expected, '<' not found
41  Exit 2

Line 1 is the invocation of one of my Perl programs, called tmcurve for
"time memory curve".

Line 4 shows summary statistics for one run of the benchmark program.

 4  Max heap=128 MB succeed  cpu=19.3 sec  Max RSS=125.4 MB  RSS-heap=-2.6
MB  GC tot space=2847.5 MB time=0.7 sec max live=63.1 MB

Let's break down this summary output line into its parts:

    Max heap=128 MB - It was given a max heap (-Xmx) parameter of 128
    MB (-Xmx128m).

    succeed - The benchmark program's output was checked, and was
    correct.

    cpu=19.3 sec - It used 19.3 sec of total cpu time (the user+system
    cpu times reported by the Unix '/usr/bin/time' command added
    together).

    Max RSS=125.4 MB - The maximum memory ever resident in RAM during
    the process's run was Max RSS=125.4 MB, as reported by the
    getrusage() system call.

    RSS-heap=-2.6 MB - This is just RSS with heap subtracted out.
    This number can be positive, because the JVM has memory it needs
    to run that is not in the program's heap.

    GC - Everything after that is statistics collected from parsing
    the HotSpot logs you get with the -verbose:gc argument to the JVM.

    tot space=2847.5 MB - The total amount of memory collected by all
    GC invocations was 2847.5 MB.

    time=0.7 sec - This took a total of 0.7 sec

    max live=63.1 MB - The maximum heap size before any GC invocation
    was 63.1 MB.  The name "max live" is probably not the best name
    for that value, since objects in heap before a GC begins are often
    not all live.

Lines 4-24 show the results of multiple runs, while tmcurve is doing a
binary search to find the smallest heap size for which the program
gives correct output.

26  Succeeded at 31 MB, failed at 30 MB

Line 26 summarizes the results of the binary search.

28  Sweep phase MB values to use: 31 39 47 55 63

Line 28 shows the MB values that will be used in the "sweep" phase.
The amount that each value is larger than the previous one can be
controlled by tmcurve command line arguments.  In this case --delta 8
means that each value will be 8 MB larger than the one before.  Other
tmcurve options can be used to choose how many such values are used
(in this case 5), and how many times the benchmark program will be run
for each of these MB values (in this case 4).

29  Max heap=31 MB succeed  cpu=64.21 sec  Max RSS=80.0 MB  RSS-heap=49.0
MB  GC tot space=2868.8 MB time=45.6 sec max live=26.6 MB
30  Max heap=31 MB succeed  cpu=63.626 sec  Max RSS=79.9 MB  RSS-heap=48.9
MB  GC tot space=2875.1 MB time=44.4 sec max live=24.9 MB
31  Max heap=31 MB succeed  cpu=65.422 sec  Max RSS=80.0 MB  RSS-heap=49.0
MB  GC tot space=2869.7 MB time=46.3 sec max live=26.6 MB
32  Max heap=31 MB succeed  cpu=64.325 sec  Max RSS=75.3 MB  RSS-heap=44.3
MB  GC tot space=2875.1 MB time=45.8 sec max live=26.6 MB
33  Max heap=39 MB succeed  cpu=21.034 sec  Max RSS=83.4 MB  RSS-heap=44.4
MB  GC tot space=2861.7 MB time=1.4 sec max live=35.4 MB
34  Max heap=39 MB succeed  cpu=20.939 sec  Max RSS=82.5 MB  RSS-heap=43.5
MB  GC tot space=2858.2 MB time=1.5 sec max live=35.4 MB
35  Max heap=39 MB succeed  cpu=21.3 sec  Max RSS=90.6 MB  RSS-heap=51.6 MB
GC tot space=2863.2 MB time=1.4 sec max live=35.5 MB
36  Max heap=39 MB succeed  cpu=21.661 sec  Max RSS=91.1 MB  RSS-heap=52.1
MB  GC tot space=2864.3 MB time=1.5 sec max live=35.7 MB

Lines 29-32 show the results of 4 runs with the same maximum heap size
of 31 MB.  In all cases, we see that the GC time is about 2/3 of the
total cpu time.

Lines 33-36 show that when we increase the max heap size to 39 MB,
total GC time goes way down to 1.4 or 1.5 sec, and the total cpu time
thus goes down to about 21 sec.  Obviously for this program, you get
much lower time with just a little bit more memory than the minimum
required to succeed.

38  Could not parse line 26 of file
/var/folders/dO/dOizZatdFUiWd11ofxhhPU+++TI/-Tmp-/Du7UdDBzIQ/qyTKNgBLn0.txt:
39  3.506: [GC-- 42528K->46648K(46656K), 0.0422814 secs]
40
/var/folders/dO/dOizZatdFUiWd11ofxhhPU+++TI/-Tmp-/VBRRJnGxyt/P7aYOLF3di:1:
parser error : Start tag expected, '<' not found
41  Exit 2

Lines 38-41 show that I still have more work to do on parsing the
output of -verbose:gc :-) I am fairly conservative in my code for
parsing log files, spitting out an error and quitting rather than
silently guessing what the line might mean, so this is normal for me
when I have not yet seen all possible formats of log file lines.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to