123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- ;
- ; GCOld.sch x.x 00/08/03
- ; translated from GCOld.java 2.0a 00/08/23
- ;
- ; Copyright 2000 Sun Microsystems, Inc. All rights reserved.
- ;
- ;
- ; Should be good enough for this benchmark.
- (define (newRandom)
- (letrec ((random14
- (lambda (n)
- (set! x (remainder (+ (* a x) c) m))
- (remainder (quotient x 8) n)))
- (a 701)
- (x 1)
- (c 743483)
- (m 524288)
- (loop
- (lambda (q r n)
- (if (zero? q)
- (remainder r n)
- (loop (quotient q 16384)
- (+ (* 16384 r) (random14 16384))
- n)))))
- (lambda (n)
- (if (and (exact? n) (integer? n) (< n 16384))
- (random14 n)
- (loop n (random14 16384) n)))))
- ; A TreeNode is a record with three fields: left, right, val.
- ; The left and right fields contain a TreeNode or 0, and the
- ; val field will contain the integer height of the tree.
- (define-syntax newTreeNode
- (syntax-rules ()
- ((newTreeNode left right val)
- (vector left right val))
- ((newTreeNode)
- (vector 0 0 0))))
- (define-syntax TreeNode.left
- (syntax-rules ()
- ((TreeNode.left node)
- (vector-ref node 0))))
- (define-syntax TreeNode.right
- (syntax-rules ()
- ((TreeNode.right node)
- (vector-ref node 1))))
- (define-syntax TreeNode.val
- (syntax-rules ()
- ((TreeNode.val node)
- (vector-ref node 2))))
- (define-syntax setf
- (syntax-rules (TreeNode.left TreeNode.right TreeNode.val)
- ((setf (TreeNode.left node) x)
- (vector-set! node 0 x))
- ((setf (TreeNode.right node) x)
- (vector-set! node 1 x))
- ((setf (TreeNode.val node) x)
- (vector-set! node 2 x))))
- ; Args:
- ; live-data-size: in megabytes.
- ; work: units of mutator non-allocation work per byte allocated,
- ; (in unspecified units. This will affect the promotion rate
- ; printed at the end of the run: more mutator work per step implies
- ; fewer steps per second implies fewer bytes promoted per second.)
- ; short/long ratio: ratio of short-lived bytes allocated to long-lived
- ; bytes allocated.
- ; pointer mutation rate: number of pointer mutations per step.
- ; steps: number of steps to do.
- ;
- (define (GCOld size workUnits promoteRate ptrMutRate steps)
- (define (println . args)
- (for-each display args)
- (newline))
- ; Rounds an inexact real to two decimal places.
- (define (round2 x)
- (/ (round (* 100.0 x)) 100.0))
- ; Returns the height of the given tree.
- (define (height t)
- (if (eqv? t 0)
- 0
- (+ 1 (max (height (TreeNode.left t))
- (height (TreeNode.right t))))))
- ; Returns the length of the shortest path in the given tree.
- (define (shortestPath t)
- (if (eqv? t 0)
- 0
- (+ 1 (min (shortestPath (TreeNode.left t))
- (shortestPath (TreeNode.right t))))))
- ; Returns the number of nodes in a balanced tree of the given height.
- (define (heightToNodes h)
- (- (expt 2 h) 1))
- ; Returns the height of the largest balanced tree
- ; that has no more than the given number of nodes.
- (define (nodesToHeight nodes)
- (do ((h 1 (+ h 1))
- (n 1 (+ n n)))
- ((> (+ n n -1) nodes)
- (- h 1))))
- (let* (
- ; Constants.
- (null 0) ; Java's null
- (pathBits 65536) ; to generate 16 random bits
- (MEG 1000000)
- (INSIGNIFICANT 999) ; this many bytes don't matter
- (bytes/word 4)
- (bytes/node 20) ; bytes per tree node in typical JVM
- (words/dead 100) ; size of young garbage objects
- ; Returns the number of bytes in a balanced tree of the given height.
- (heightToBytes
- (lambda (h)
- (* bytes/node (heightToNodes h))))
- ; Returns the height of the largest balanced tree
- ; that occupies no more than the given number of bytes.
- (bytesToHeight
- (lambda (bytes)
- (nodesToHeight (/ bytes bytes/node))))
- (treeHeight 14)
- (treeSize (heightToBytes treeHeight))
- (msg1 "Usage: java GCOld <size> <work> <ratio> <mutation> <steps>")
- (msg2 " where <size> is the live storage in megabytes")
- (msg3 " <work> is the mutator work per step (arbitrary units)")
- (msg4 " <ratio> is the ratio of short-lived to long-lived allocation")
- (msg5 " <mutation> is the mutations per step")
- (msg6 " <steps> is the number of steps")
- ; Counters (and global variables that discourage optimization).
- (youngBytes 0)
- (nodes 0)
- (actuallyMut 0)
- (mutatorSum 0)
- (aexport '#())
- ; Global variables.
- (trees '#())
- (where 0)
- (rnd (newRandom))
- )
- ; Returns a newly allocated balanced binary tree of height h.
- (define (makeTree h)
- (if (zero? h)
- null
- (let ((res (newTreeNode)))
- (set! nodes (+ nodes 1))
- (setf (TreeNode.left res) (makeTree (- h 1)))
- (setf (TreeNode.right res) (makeTree (- h 1)))
- (setf (TreeNode.val res) h)
- res)))
- ; Allocates approximately size megabytes of trees and stores
- ; them into a global array.
- (define (init)
- ; Each tree will be about a megabyte.
- (let ((ntrees (quotient (* size MEG) treeSize)))
- (set! trees (make-vector ntrees null))
- (println "Allocating " ntrees " trees.")
- (println " (" (* ntrees treeSize) " bytes)")
- (do ((i 0 (+ i 1)))
- ((>= i ntrees))
- (vector-set! trees i (makeTree treeHeight))
- (doYoungGenAlloc (* promoteRate ntrees treeSize) words/dead))
- (println " (" nodes " nodes)")))
- ; Confirms that all trees are balanced and have the correct height.
- (define (checkTrees)
- (let ((ntrees (vector-length trees)))
- (do ((i 0 (+ i 1)))
- ((>= i ntrees))
- (let* ((t (vector-ref trees i))
- (h1 (height t))
- (h2 (shortestPath t)))
- (if (or (not (= h1 treeHeight))
- (not (= h2 treeHeight)))
- (println "*****BUG: " h1 " " h2))))))
- ; Called only by replaceTree (below) and by itself.
- (define (replaceTreeWork full partial dir)
- (let ((canGoLeft (and (not (eq? (TreeNode.left full) null))
- (> (TreeNode.val (TreeNode.left full))
- (TreeNode.val partial))))
- (canGoRight (and (not (eq? (TreeNode.right full) null))
- (> (TreeNode.val (TreeNode.right full))
- (TreeNode.val partial)))))
- (cond ((and canGoLeft canGoRight)
- (if dir
- (replaceTreeWork (TreeNode.left full)
- partial
- (not dir))
- (replaceTreeWork (TreeNode.right full)
- partial
- (not dir))))
- ((and (not canGoLeft) (not canGoRight))
- (if dir
- (setf (TreeNode.left full) partial)
- (setf (TreeNode.right full) partial)))
- ((not canGoLeft)
- (setf (TreeNode.left full) partial))
- (else
- (setf (TreeNode.right full) partial)))))
- ; Given a balanced tree full and a smaller balanced tree partial,
- ; replaces an appropriate subtree of full by partial, taking care
- ; to preserve the shape of the full tree.
- (define (replaceTree full partial)
- (let ((dir (zero? (modulo (TreeNode.val partial) 2))))
- (set! actuallyMut (+ actuallyMut 1))
- (replaceTreeWork full partial dir)))
- ; Allocates approximately n bytes of long-lived storage,
- ; replacing oldest existing long-lived storage.
- (define (oldGenAlloc n)
- (let ((full (quotient n treeSize))
- (partial (modulo n treeSize)))
- ;(println "In oldGenAlloc, doing "
- ; full
- ; " full trees and one partial tree of size "
- ; partial)
- (do ((i 0 (+ i 1)))
- ((>= i full))
- (vector-set! trees where (makeTree treeHeight))
- (set! where
- (modulo (+ where 1) (vector-length trees))))
- (let loop ((partial partial))
- (if (> partial INSIGNIFICANT)
- (let* ((h (bytesToHeight partial))
- (newTree (makeTree h)))
- (replaceTree (vector-ref trees where) newTree)
- (set! where
- (modulo (+ where 1) (vector-length trees)))
- (loop (- partial (heightToBytes h))))))))
- ; Interchanges two randomly selected subtrees (of same size and depth).
- (define (oldGenSwapSubtrees)
- ; Randomly pick:
- ; * two tree indices
- ; * A depth
- ; * A path to that depth.
- (let* ((index1 (rnd (vector-length trees)))
- (index2 (rnd (vector-length trees)))
- (depth (rnd treeHeight))
- (path (rnd pathBits))
- (tn1 (vector-ref trees index1))
- (tn2 (vector-ref trees index2)))
- (do ((i 0 (+ i 1)))
- ((>= i depth))
- (if (even? path)
- (begin (set! tn1 (TreeNode.left tn1))
- (set! tn2 (TreeNode.left tn2)))
- (begin (set! tn1 (TreeNode.right tn1))
- (set! tn2 (TreeNode.right tn2))))
- (set! path (quotient path 2)))
- (if (even? path)
- (let ((tmp (TreeNode.left tn1)))
- (setf (TreeNode.left tn1) (TreeNode.left tn2))
- (setf (TreeNode.left tn2) tmp))
- (let ((tmp (TreeNode.right tn1)))
- (setf (TreeNode.right tn1) (TreeNode.right tn2))
- (setf (TreeNode.right tn2) tmp)))
- (set! actuallyMut (+ actuallyMut 2))))
- ; Update "n" old-generation pointers.
- (define (oldGenMut n)
- (do ((i 0 (+ i 1)))
- ((>= i (quotient n 2)))
- (oldGenSwapSubtrees)))
- ; Does the amount of mutator work appropriate for n bytes of young-gen
- ; garbage allocation.
- (define (doMutWork n)
- (let ((limit (quotient (* workUnits n) 10)))
- (do ((k 0 (+ k 1))
- (sum 0 (+ sum 1)))
- ((>= k limit)
- ; We don't want dead code elimination to eliminate this loop.
- (set! mutatorSum (+ mutatorSum sum))))))
- ; Allocate n bytes of young-gen garbage, in units of "nwords"
- ; words.
- (define (doYoungGenAlloc n nwords)
- (let ((nbytes (* nwords bytes/word)))
- (do ((allocated 0 (+ allocated nbytes)))
- ((>= allocated n)
- (set! youngBytes (+ youngBytes allocated)))
- (set! aexport (make-vector nwords 0)))))
- ; Allocate "n" bytes of young-gen data; and do the
- ; corresponding amount of old-gen allocation and pointer
- ; mutation.
- ; oldGenAlloc may perform some mutations, so this code
- ; takes those mutations into account.
- (define (doStep n)
- (let ((mutations actuallyMut))
- (doYoungGenAlloc n words/dead)
- (doMutWork n)
- ; Now do old-gen allocation
- (oldGenAlloc (quotient n promoteRate))
- (oldGenMut (max 0 (- (+ mutations ptrMutRate) actuallyMut)))))
- (println size " megabytes")
- (println workUnits " work units per step.")
- (println "promotion ratio is 1:" promoteRate)
- (println "pointer mutation rate is " ptrMutRate)
- (println steps " steps")
- (init)
- (checkTrees)
- (set! youngBytes 0)
- (set! nodes 0)
- (println "Initialization complete...")
- (run-benchmark "GCOld"
- 1
- (lambda ()
- (lambda ()
- (do ((step 0 (+ step 1)))
- ((>= step steps))
- (doStep MEG))))
- (lambda (result) #t))
- (checkTrees)
- (println "Allocated " steps " Mb of young gen garbage")
- (println " (actually allocated "
- (round2 (/ youngBytes MEG))
- " megabytes)")
- (println "Promoted " (round2 (/ steps promoteRate)) " Mb")
- (println " (actually promoted "
- (round2 (/ (* nodes bytes/node) MEG))
- " megabytes)")
- (if (not (zero? ptrMutRate))
- (println "Mutated " actuallyMut " pointers"))
- ; This output serves mainly to discourage optimization.
- (+ mutatorSum (vector-length aexport))))
- (define (gcold-benchmark . args)
- (define gcold-iters 1)
- (GCOld 25 0 10 10 gcold-iters))
|