gcold.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. ;
  2. ; GCOld.sch x.x 00/08/03
  3. ; translated from GCOld.java 2.0a 00/08/23
  4. ;
  5. ; Copyright 2000 Sun Microsystems, Inc. All rights reserved.
  6. ;
  7. ;
  8. ; Should be good enough for this benchmark.
  9. (define (newRandom)
  10. (letrec ((random14
  11. (lambda (n)
  12. (set! x (remainder (+ (* a x) c) m))
  13. (remainder (quotient x 8) n)))
  14. (a 701)
  15. (x 1)
  16. (c 743483)
  17. (m 524288)
  18. (loop
  19. (lambda (q r n)
  20. (if (zero? q)
  21. (remainder r n)
  22. (loop (quotient q 16384)
  23. (+ (* 16384 r) (random14 16384))
  24. n)))))
  25. (lambda (n)
  26. (if (and (exact? n) (integer? n) (< n 16384))
  27. (random14 n)
  28. (loop n (random14 16384) n)))))
  29. ; A TreeNode is a record with three fields: left, right, val.
  30. ; The left and right fields contain a TreeNode or 0, and the
  31. ; val field will contain the integer height of the tree.
  32. (define-syntax newTreeNode
  33. (syntax-rules ()
  34. ((newTreeNode left right val)
  35. (vector left right val))
  36. ((newTreeNode)
  37. (vector 0 0 0))))
  38. (define-syntax TreeNode.left
  39. (syntax-rules ()
  40. ((TreeNode.left node)
  41. (vector-ref node 0))))
  42. (define-syntax TreeNode.right
  43. (syntax-rules ()
  44. ((TreeNode.right node)
  45. (vector-ref node 1))))
  46. (define-syntax TreeNode.val
  47. (syntax-rules ()
  48. ((TreeNode.val node)
  49. (vector-ref node 2))))
  50. (define-syntax setf
  51. (syntax-rules (TreeNode.left TreeNode.right TreeNode.val)
  52. ((setf (TreeNode.left node) x)
  53. (vector-set! node 0 x))
  54. ((setf (TreeNode.right node) x)
  55. (vector-set! node 1 x))
  56. ((setf (TreeNode.val node) x)
  57. (vector-set! node 2 x))))
  58. ; Args:
  59. ; live-data-size: in megabytes.
  60. ; work: units of mutator non-allocation work per byte allocated,
  61. ; (in unspecified units. This will affect the promotion rate
  62. ; printed at the end of the run: more mutator work per step implies
  63. ; fewer steps per second implies fewer bytes promoted per second.)
  64. ; short/long ratio: ratio of short-lived bytes allocated to long-lived
  65. ; bytes allocated.
  66. ; pointer mutation rate: number of pointer mutations per step.
  67. ; steps: number of steps to do.
  68. ;
  69. (define (GCOld size workUnits promoteRate ptrMutRate steps)
  70. (define (println . args)
  71. (for-each display args)
  72. (newline))
  73. ; Rounds an inexact real to two decimal places.
  74. (define (round2 x)
  75. (/ (round (* 100.0 x)) 100.0))
  76. ; Returns the height of the given tree.
  77. (define (height t)
  78. (if (eqv? t 0)
  79. 0
  80. (+ 1 (max (height (TreeNode.left t))
  81. (height (TreeNode.right t))))))
  82. ; Returns the length of the shortest path in the given tree.
  83. (define (shortestPath t)
  84. (if (eqv? t 0)
  85. 0
  86. (+ 1 (min (shortestPath (TreeNode.left t))
  87. (shortestPath (TreeNode.right t))))))
  88. ; Returns the number of nodes in a balanced tree of the given height.
  89. (define (heightToNodes h)
  90. (- (expt 2 h) 1))
  91. ; Returns the height of the largest balanced tree
  92. ; that has no more than the given number of nodes.
  93. (define (nodesToHeight nodes)
  94. (do ((h 1 (+ h 1))
  95. (n 1 (+ n n)))
  96. ((> (+ n n -1) nodes)
  97. (- h 1))))
  98. (let* (
  99. ; Constants.
  100. (null 0) ; Java's null
  101. (pathBits 65536) ; to generate 16 random bits
  102. (MEG 1000000)
  103. (INSIGNIFICANT 999) ; this many bytes don't matter
  104. (bytes/word 4)
  105. (bytes/node 20) ; bytes per tree node in typical JVM
  106. (words/dead 100) ; size of young garbage objects
  107. ; Returns the number of bytes in a balanced tree of the given height.
  108. (heightToBytes
  109. (lambda (h)
  110. (* bytes/node (heightToNodes h))))
  111. ; Returns the height of the largest balanced tree
  112. ; that occupies no more than the given number of bytes.
  113. (bytesToHeight
  114. (lambda (bytes)
  115. (nodesToHeight (/ bytes bytes/node))))
  116. (treeHeight 14)
  117. (treeSize (heightToBytes treeHeight))
  118. (msg1 "Usage: java GCOld <size> <work> <ratio> <mutation> <steps>")
  119. (msg2 " where <size> is the live storage in megabytes")
  120. (msg3 " <work> is the mutator work per step (arbitrary units)")
  121. (msg4 " <ratio> is the ratio of short-lived to long-lived allocation")
  122. (msg5 " <mutation> is the mutations per step")
  123. (msg6 " <steps> is the number of steps")
  124. ; Counters (and global variables that discourage optimization).
  125. (youngBytes 0)
  126. (nodes 0)
  127. (actuallyMut 0)
  128. (mutatorSum 0)
  129. (aexport '#())
  130. ; Global variables.
  131. (trees '#())
  132. (where 0)
  133. (rnd (newRandom))
  134. )
  135. ; Returns a newly allocated balanced binary tree of height h.
  136. (define (makeTree h)
  137. (if (zero? h)
  138. null
  139. (let ((res (newTreeNode)))
  140. (set! nodes (+ nodes 1))
  141. (setf (TreeNode.left res) (makeTree (- h 1)))
  142. (setf (TreeNode.right res) (makeTree (- h 1)))
  143. (setf (TreeNode.val res) h)
  144. res)))
  145. ; Allocates approximately size megabytes of trees and stores
  146. ; them into a global array.
  147. (define (init)
  148. ; Each tree will be about a megabyte.
  149. (let ((ntrees (quotient (* size MEG) treeSize)))
  150. (set! trees (make-vector ntrees null))
  151. (println "Allocating " ntrees " trees.")
  152. (println " (" (* ntrees treeSize) " bytes)")
  153. (do ((i 0 (+ i 1)))
  154. ((>= i ntrees))
  155. (vector-set! trees i (makeTree treeHeight))
  156. (doYoungGenAlloc (* promoteRate ntrees treeSize) words/dead))
  157. (println " (" nodes " nodes)")))
  158. ; Confirms that all trees are balanced and have the correct height.
  159. (define (checkTrees)
  160. (let ((ntrees (vector-length trees)))
  161. (do ((i 0 (+ i 1)))
  162. ((>= i ntrees))
  163. (let* ((t (vector-ref trees i))
  164. (h1 (height t))
  165. (h2 (shortestPath t)))
  166. (if (or (not (= h1 treeHeight))
  167. (not (= h2 treeHeight)))
  168. (println "*****BUG: " h1 " " h2))))))
  169. ; Called only by replaceTree (below) and by itself.
  170. (define (replaceTreeWork full partial dir)
  171. (let ((canGoLeft (and (not (eq? (TreeNode.left full) null))
  172. (> (TreeNode.val (TreeNode.left full))
  173. (TreeNode.val partial))))
  174. (canGoRight (and (not (eq? (TreeNode.right full) null))
  175. (> (TreeNode.val (TreeNode.right full))
  176. (TreeNode.val partial)))))
  177. (cond ((and canGoLeft canGoRight)
  178. (if dir
  179. (replaceTreeWork (TreeNode.left full)
  180. partial
  181. (not dir))
  182. (replaceTreeWork (TreeNode.right full)
  183. partial
  184. (not dir))))
  185. ((and (not canGoLeft) (not canGoRight))
  186. (if dir
  187. (setf (TreeNode.left full) partial)
  188. (setf (TreeNode.right full) partial)))
  189. ((not canGoLeft)
  190. (setf (TreeNode.left full) partial))
  191. (else
  192. (setf (TreeNode.right full) partial)))))
  193. ; Given a balanced tree full and a smaller balanced tree partial,
  194. ; replaces an appropriate subtree of full by partial, taking care
  195. ; to preserve the shape of the full tree.
  196. (define (replaceTree full partial)
  197. (let ((dir (zero? (modulo (TreeNode.val partial) 2))))
  198. (set! actuallyMut (+ actuallyMut 1))
  199. (replaceTreeWork full partial dir)))
  200. ; Allocates approximately n bytes of long-lived storage,
  201. ; replacing oldest existing long-lived storage.
  202. (define (oldGenAlloc n)
  203. (let ((full (quotient n treeSize))
  204. (partial (modulo n treeSize)))
  205. ;(println "In oldGenAlloc, doing "
  206. ; full
  207. ; " full trees and one partial tree of size "
  208. ; partial)
  209. (do ((i 0 (+ i 1)))
  210. ((>= i full))
  211. (vector-set! trees where (makeTree treeHeight))
  212. (set! where
  213. (modulo (+ where 1) (vector-length trees))))
  214. (let loop ((partial partial))
  215. (if (> partial INSIGNIFICANT)
  216. (let* ((h (bytesToHeight partial))
  217. (newTree (makeTree h)))
  218. (replaceTree (vector-ref trees where) newTree)
  219. (set! where
  220. (modulo (+ where 1) (vector-length trees)))
  221. (loop (- partial (heightToBytes h))))))))
  222. ; Interchanges two randomly selected subtrees (of same size and depth).
  223. (define (oldGenSwapSubtrees)
  224. ; Randomly pick:
  225. ; * two tree indices
  226. ; * A depth
  227. ; * A path to that depth.
  228. (let* ((index1 (rnd (vector-length trees)))
  229. (index2 (rnd (vector-length trees)))
  230. (depth (rnd treeHeight))
  231. (path (rnd pathBits))
  232. (tn1 (vector-ref trees index1))
  233. (tn2 (vector-ref trees index2)))
  234. (do ((i 0 (+ i 1)))
  235. ((>= i depth))
  236. (if (even? path)
  237. (begin (set! tn1 (TreeNode.left tn1))
  238. (set! tn2 (TreeNode.left tn2)))
  239. (begin (set! tn1 (TreeNode.right tn1))
  240. (set! tn2 (TreeNode.right tn2))))
  241. (set! path (quotient path 2)))
  242. (if (even? path)
  243. (let ((tmp (TreeNode.left tn1)))
  244. (setf (TreeNode.left tn1) (TreeNode.left tn2))
  245. (setf (TreeNode.left tn2) tmp))
  246. (let ((tmp (TreeNode.right tn1)))
  247. (setf (TreeNode.right tn1) (TreeNode.right tn2))
  248. (setf (TreeNode.right tn2) tmp)))
  249. (set! actuallyMut (+ actuallyMut 2))))
  250. ; Update "n" old-generation pointers.
  251. (define (oldGenMut n)
  252. (do ((i 0 (+ i 1)))
  253. ((>= i (quotient n 2)))
  254. (oldGenSwapSubtrees)))
  255. ; Does the amount of mutator work appropriate for n bytes of young-gen
  256. ; garbage allocation.
  257. (define (doMutWork n)
  258. (let ((limit (quotient (* workUnits n) 10)))
  259. (do ((k 0 (+ k 1))
  260. (sum 0 (+ sum 1)))
  261. ((>= k limit)
  262. ; We don't want dead code elimination to eliminate this loop.
  263. (set! mutatorSum (+ mutatorSum sum))))))
  264. ; Allocate n bytes of young-gen garbage, in units of "nwords"
  265. ; words.
  266. (define (doYoungGenAlloc n nwords)
  267. (let ((nbytes (* nwords bytes/word)))
  268. (do ((allocated 0 (+ allocated nbytes)))
  269. ((>= allocated n)
  270. (set! youngBytes (+ youngBytes allocated)))
  271. (set! aexport (make-vector nwords 0)))))
  272. ; Allocate "n" bytes of young-gen data; and do the
  273. ; corresponding amount of old-gen allocation and pointer
  274. ; mutation.
  275. ; oldGenAlloc may perform some mutations, so this code
  276. ; takes those mutations into account.
  277. (define (doStep n)
  278. (let ((mutations actuallyMut))
  279. (doYoungGenAlloc n words/dead)
  280. (doMutWork n)
  281. ; Now do old-gen allocation
  282. (oldGenAlloc (quotient n promoteRate))
  283. (oldGenMut (max 0 (- (+ mutations ptrMutRate) actuallyMut)))))
  284. (println size " megabytes")
  285. (println workUnits " work units per step.")
  286. (println "promotion ratio is 1:" promoteRate)
  287. (println "pointer mutation rate is " ptrMutRate)
  288. (println steps " steps")
  289. (init)
  290. (checkTrees)
  291. (set! youngBytes 0)
  292. (set! nodes 0)
  293. (println "Initialization complete...")
  294. (run-benchmark "GCOld"
  295. 1
  296. (lambda ()
  297. (lambda ()
  298. (do ((step 0 (+ step 1)))
  299. ((>= step steps))
  300. (doStep MEG))))
  301. (lambda (result) #t))
  302. (checkTrees)
  303. (println "Allocated " steps " Mb of young gen garbage")
  304. (println " (actually allocated "
  305. (round2 (/ youngBytes MEG))
  306. " megabytes)")
  307. (println "Promoted " (round2 (/ steps promoteRate)) " Mb")
  308. (println " (actually promoted "
  309. (round2 (/ (* nodes bytes/node) MEG))
  310. " megabytes)")
  311. (if (not (zero? ptrMutRate))
  312. (println "Mutated " actuallyMut " pointers"))
  313. ; This output serves mainly to discourage optimization.
  314. (+ mutatorSum (vector-length aexport))))
  315. (define (gcold-benchmark . args)
  316. (define gcold-iters 1)
  317. (GCOld 25 0 10 10 gcold-iters))