gcbench.scm 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. ; This is adapted from a benchmark written by John Ellis and Pete Kovac
  2. ; of Post Communications.
  3. ; It was modified by Hans Boehm of Silicon Graphics.
  4. ; It was translated into Scheme by William D Clinger of Northeastern Univ;
  5. ; the Scheme version uses (RUN-BENCHMARK <string> <thunk>)
  6. ; Last modified 30 May 1997.
  7. ;
  8. ; This is no substitute for real applications. No actual application
  9. ; is likely to behave in exactly this way. However, this benchmark was
  10. ; designed to be more representative of real applications than other
  11. ; Java GC benchmarks of which we are aware.
  12. ; It attempts to model those properties of allocation requests that
  13. ; are important to current GC techniques.
  14. ; It is designed to be used either to obtain a single overall performance
  15. ; number, or to give a more detailed estimate of how collector
  16. ; performance varies with object lifetimes. It prints the time
  17. ; required to allocate and collect balanced binary trees of various
  18. ; sizes. Smaller trees result in shorter object lifetimes. Each cycle
  19. ; allocates roughly the same amount of memory.
  20. ; Two data structures are kept around during the entire process, so
  21. ; that the measured performance is representative of applications
  22. ; that maintain some live in-memory data. One of these is a tree
  23. ; containing many pointers. The other is a large array containing
  24. ; double precision floating point numbers. Both should be of comparable
  25. ; size.
  26. ;
  27. ; The results are only really meaningful together with a specification
  28. ; of how much memory was used. It is possible to trade memory for
  29. ; better time performance. This benchmark should be run in a 32 MB
  30. ; heap, though we don't currently know how to enforce that uniformly.
  31. ; In the Java version, this routine prints the heap size and the amount
  32. ; of free memory. There is no portable way to do this in Scheme; each
  33. ; implementation needs its own version.
  34. (use-modules (ice-9 syncase))
  35. (define (PrintDiagnostics)
  36. (display " Total memory available= ???????? bytes")
  37. (display " Free memory= ???????? bytes")
  38. (newline))
  39. (define (run-benchmark str thu)
  40. (display str)
  41. (thu))
  42. ; Should we implement a Java class as procedures or hygienic macros?
  43. ; Take your pick.
  44. (define-syntax let-class
  45. (syntax-rules
  46. ()
  47. ;; Put this rule first to implement a class using procedures.
  48. ((let-class (((method . args) . method-body) ...) . body)
  49. (let () (define (method . args) . method-body) ... . body))
  50. ;; Put this rule first to implement a class using hygienic macros.
  51. ((let-class (((method . args) . method-body) ...) . body)
  52. (letrec-syntax ((method (syntax-rules () ((method . args) (begin . method-body))))
  53. ...)
  54. . body))
  55. ))
  56. (define (gcbench kStretchTreeDepth)
  57. ; Nodes used by a tree of a given size
  58. (define (TreeSize i)
  59. (- (expt 2 (+ i 1)) 1))
  60. ; Number of iterations to use for a given tree depth
  61. (define (NumIters i)
  62. (quotient (* 2 (TreeSize kStretchTreeDepth))
  63. (TreeSize i)))
  64. ; Parameters are determined by kStretchTreeDepth.
  65. ; In Boehm's version the parameters were fixed as follows:
  66. ; public static final int kStretchTreeDepth = 18; // about 16Mb
  67. ; public static final int kLongLivedTreeDepth = 16; // about 4Mb
  68. ; public static final int kArraySize = 500000; // about 4Mb
  69. ; public static final int kMinTreeDepth = 4;
  70. ; public static final int kMaxTreeDepth = 16;
  71. ; In Larceny the storage numbers above would be 12 Mby, 3 Mby, 6 Mby.
  72. (let* ((kLongLivedTreeDepth (- kStretchTreeDepth 2))
  73. (kArraySize (* 4 (TreeSize kLongLivedTreeDepth)))
  74. (kMinTreeDepth 4)
  75. (kMaxTreeDepth kLongLivedTreeDepth))
  76. ; Elements 3 and 4 of the allocated vectors are useless.
  77. (let-class (((make-node l r)
  78. (let ((v (make-empty-node)))
  79. (vector-set! v 0 l)
  80. (vector-set! v 1 r)
  81. v))
  82. ((make-empty-node) (make-vector 4 0))
  83. ((node.left node) (vector-ref node 0))
  84. ((node.right node) (vector-ref node 1))
  85. ((node.left-set! node x) (vector-set! node 0 x))
  86. ((node.right-set! node x) (vector-set! node 1 x)))
  87. ; Build tree top down, assigning to older objects.
  88. (define (Populate iDepth thisNode)
  89. (if (<= iDepth 0)
  90. #f
  91. (let ((iDepth (- iDepth 1)))
  92. (node.left-set! thisNode (make-empty-node))
  93. (node.right-set! thisNode (make-empty-node))
  94. (Populate iDepth (node.left thisNode))
  95. (Populate iDepth (node.right thisNode)))))
  96. ; Build tree bottom-up
  97. (define (MakeTree iDepth)
  98. (if (<= iDepth 0)
  99. (make-empty-node)
  100. (make-node (MakeTree (- iDepth 1))
  101. (MakeTree (- iDepth 1)))))
  102. (define (TimeConstruction depth)
  103. (let ((iNumIters (NumIters depth)))
  104. (display (string-append "Creating "
  105. (number->string iNumIters)
  106. " trees of depth "
  107. (number->string depth)))
  108. (newline)
  109. (run-benchmark "GCBench: Top down construction"
  110. (lambda ()
  111. (do ((i 0 (+ i 1)))
  112. ((>= i iNumIters))
  113. (Populate depth (make-empty-node)))))
  114. (run-benchmark "GCBench: Bottom up construction"
  115. (lambda ()
  116. (do ((i 0 (+ i 1)))
  117. ((>= i iNumIters))
  118. (MakeTree depth))))))
  119. (define (main)
  120. (display "Garbage Collector Test")
  121. (newline)
  122. (display (string-append
  123. " Stretching memory with a binary tree of depth "
  124. (number->string kStretchTreeDepth)))
  125. (newline)
  126. (run-benchmark "GCBench: Main"
  127. (lambda ()
  128. ; Stretch the memory space quickly
  129. (MakeTree kStretchTreeDepth)
  130. ; Create a long lived object
  131. (display (string-append
  132. " Creating a long-lived binary tree of depth "
  133. (number->string kLongLivedTreeDepth)))
  134. (newline)
  135. (let ((longLivedTree (make-empty-node)))
  136. (Populate kLongLivedTreeDepth longLivedTree)
  137. ; Create long-lived array, filling half of it
  138. (display (string-append
  139. " Creating a long-lived array of "
  140. (number->string kArraySize)
  141. " inexact reals"))
  142. (newline)
  143. (let ((array (make-vector kArraySize 0.0)))
  144. (do ((i 0 (+ i 1)))
  145. ((>= i (quotient kArraySize 2)))
  146. (vector-set! array i (/ 1.0 (exact->inexact i))))
  147. (PrintDiagnostics)
  148. (do ((d kMinTreeDepth (+ d 2)))
  149. ((> d kMaxTreeDepth))
  150. (TimeConstruction d))
  151. (if (or (eq? longLivedTree '())
  152. (let ((n (min 1000
  153. (- (quotient (vector-length array)
  154. 2)
  155. 1))))
  156. (not (= (vector-ref array n)
  157. (/ 1.0 (exact->inexact
  158. n))))))
  159. (begin (display "Failed") (newline)))
  160. ; fake reference to LongLivedTree
  161. ; and array
  162. ; to keep them from being optimized away
  163. ))))
  164. (PrintDiagnostics))
  165. (main))))
  166. (define (gc-benchmark . rest)
  167. (let ((k (if (null? rest) 18 (car rest))))
  168. (display "The garbage collector should touch about ")
  169. (display (expt 2 (- k 13)))
  170. (display " megabytes of heap storage.")
  171. (newline)
  172. (display "The use of more or less memory will skew the results.")
  173. (newline)
  174. (run-benchmark (string-append "GCBench" (number->string k))
  175. (lambda () (gcbench k)))))
  176. (gc-benchmark )
  177. (display (gc-stats))