perm.sch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ; File: perm9.sch
  3. ; Description: memory system benchmark using Zaks's permutation generator
  4. ; Author: Lars Hansen, Will Clinger, and Gene Luks
  5. ; Created: 18-Mar-94
  6. ; Language: Scheme
  7. ; Status: Public Domain
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  9. ; 940720 / lth Added some more benchmarks for the thesis paper.
  10. ; 970215 / wdc Increased problem size from 8 to 9; improved tenperm9-benchmark.
  11. ; 970531 / wdc Cleaned up for public release.
  12. ; 000820 / wdc Added the MpermNKL benchmark; revised for new run-benchmark.
  13. ; This benchmark is in four parts. Each tests a different aspect of
  14. ; the memory system.
  15. ;
  16. ; perm storage allocation
  17. ; 10perm storage allocation and garbage collection
  18. ; sumperms traversal of a large, linked, self-sharing structure
  19. ; mergesort! side effects and write barrier
  20. ;
  21. ; The perm9 benchmark generates a list of all 362880 permutations of
  22. ; the first 9 integers, allocating 1349288 pairs (typically 10,794,304
  23. ; bytes), all of which goes into the generated list. (That is, the
  24. ; perm9 benchmark generates absolutely no garbage.) This represents
  25. ; a savings of about 63% over the storage that would be required by
  26. ; an unshared list of permutations. The generated permutations are
  27. ; in order of a grey code that bears no obvious relationship to a
  28. ; lexicographic order.
  29. ;
  30. ; The 10perm9 benchmark repeats the perm9 benchmark 10 times, so it
  31. ; allocates and reclaims 13492880 pairs (typically 107,943,040 bytes).
  32. ; The live storage peaks at twice the storage that is allocated by the
  33. ; perm9 benchmark. At the end of each iteration, the oldest half of
  34. ; the live storage becomes garbage. Object lifetimes are distributed
  35. ; uniformly between 10.3 and 20.6 megabytes.
  36. ;
  37. ; The 10perm9 benchmark is the 10perm9:2:1 special case of the
  38. ; MpermNKL benchmark, which allocates a queue of size K and then
  39. ; performs M iterations of the following operation: Fill the queue
  40. ; with individually computed copies of all permutations of a list of
  41. ; size N, and then remove the oldest L copies from the queue. At the
  42. ; end of each iteration, the oldest L/K of the live storage becomes
  43. ; garbage, and object lifetimes are distributed uniformly between two
  44. ; volumes that depend upon N, K, and L.
  45. ;
  46. ; The sumperms benchmark computes the sum of the permuted integers
  47. ; over all permutations.
  48. ;
  49. ; The mergesort! benchmark destructively sorts the generated permutations
  50. ; into lexicographic order, allocating no storage whatsoever.
  51. ;
  52. ; The benchmarks are run by calling the following procedures:
  53. ;
  54. ; (perm-benchmark n)
  55. ; (tenperm-benchmark n)
  56. ; (sumperms-benchmark n)
  57. ; (mergesort-benchmark n)
  58. ;
  59. ; The argument n may be omitted, in which case it defaults to 9.
  60. ;
  61. ; These benchmarks assume that
  62. ;
  63. ; (RUN-BENCHMARK <string> <thunk> <count>)
  64. ; (RUN-BENCHMARK <string> <count> <thunk> <predicate>)
  65. ;
  66. ; reports the time required to call <thunk> the number of times
  67. ; specified by <count>, and uses <predicate> to test whether the
  68. ; result returned by <thunk> is correct.
  69. ; Date: Thu, 17 Mar 94 19:43:32 -0800
  70. ; From: luks@sisters.cs.uoregon.edu
  71. ; To: will
  72. ; Subject: Pancake flips
  73. ;
  74. ; Procedure P_n generates a grey code of all perms of n elements
  75. ; on top of stack ending with reversal of starting sequence
  76. ;
  77. ; F_n is flip of top n elements.
  78. ;
  79. ;
  80. ; procedure P_n
  81. ;
  82. ; if n>1 then
  83. ; begin
  84. ; repeat P_{n-1},F_n n-1 times;
  85. ; P_{n-1}
  86. ; end
  87. ;
  88. (define (permutations x)
  89. (let ((x x)
  90. (perms (list x)))
  91. (define (P n)
  92. (if (> n 1)
  93. (do ((j (- n 1) (- j 1)))
  94. ((zero? j)
  95. (P (- n 1)))
  96. (P (- n 1))
  97. (F n))))
  98. (define (F n)
  99. (set! x (revloop x n (list-tail x n)))
  100. (set! perms (cons x perms)))
  101. (define (revloop x n y)
  102. (if (zero? n)
  103. y
  104. (revloop (cdr x)
  105. (- n 1)
  106. (cons (car x) y))))
  107. (define (list-tail x n)
  108. (if (zero? n)
  109. x
  110. (list-tail (cdr x) (- n 1))))
  111. (P (length x))
  112. perms))
  113. ; Given a list of lists of numbers, returns the sum of the sums
  114. ; of those lists.
  115. ;
  116. ; for (; x != NULL; x = x->rest)
  117. ; for (y = x->first; y != NULL; y = y->rest)
  118. ; sum = sum + y->first;
  119. (define (sumlists x)
  120. (do ((x x (cdr x))
  121. (sum 0 (do ((y (car x) (cdr y))
  122. (sum sum (+ sum (car y))))
  123. ((null? y) sum))))
  124. ((null? x) sum)))
  125. ; Destructive merge of two sorted lists.
  126. ; From Hansen's MS thesis.
  127. (define (merge!! a b less?)
  128. (define (loop r a b)
  129. (if (less? (car b) (car a))
  130. (begin (set-cdr! r b)
  131. (if (null? (cdr b))
  132. (set-cdr! b a)
  133. (loop b a (cdr b)) ))
  134. ;; (car a) <= (car b)
  135. (begin (set-cdr! r a)
  136. (if (null? (cdr a))
  137. (set-cdr! a b)
  138. (loop a (cdr a) b)) )) )
  139. (cond ((null? a) b)
  140. ((null? b) a)
  141. ((less? (car b) (car a))
  142. (if (null? (cdr b))
  143. (set-cdr! b a)
  144. (loop b a (cdr b)))
  145. b)
  146. (else ; (car a) <= (car b)
  147. (if (null? (cdr a))
  148. (set-cdr! a b)
  149. (loop a (cdr a) b))
  150. a)))
  151. ;; Stable sort procedure which copies the input list and then sorts
  152. ;; the new list imperatively. On the systems we have benchmarked,
  153. ;; this generic list sort has been at least as fast and usually much
  154. ;; faster than the library's sort routine.
  155. ;; Due to Richard O'Keefe; algorithm attributed to D.H.D. Warren.
  156. (define (sort!! seq less?)
  157. (define (step n)
  158. (cond ((> n 2)
  159. (let* ((j (quotient n 2))
  160. (a (step j))
  161. (k (- n j))
  162. (b (step k)))
  163. (merge!! a b less?)))
  164. ((= n 2)
  165. (let ((x (car seq))
  166. (y (cadr seq))
  167. (p seq))
  168. (set! seq (cddr seq))
  169. (if (less? y x)
  170. (begin
  171. (set-car! p y)
  172. (set-car! (cdr p) x)))
  173. (set-cdr! (cdr p) '())
  174. p))
  175. ((= n 1)
  176. (let ((p seq))
  177. (set! seq (cdr seq))
  178. (set-cdr! p '())
  179. p))
  180. (else
  181. '())))
  182. (step (length seq)))
  183. (define lexicographically-less?
  184. (lambda (x y)
  185. (define (lexicographically-less? x y)
  186. (cond ((null? x) (not (null? y)))
  187. ((null? y) #f)
  188. ((< (car x) (car y)) #t)
  189. ((= (car x) (car y))
  190. (lexicographically-less? (cdr x) (cdr y)))
  191. (else #f)))
  192. (lexicographically-less? x y)))
  193. ; This procedure isn't used by the benchmarks,
  194. ; but is provided as a public service.
  195. (define (internally-imperative-mergesort list less?)
  196. (define (list-copy l)
  197. (define (loop l prev)
  198. (if (null? l)
  199. #t
  200. (let ((q (cons (car l) '())))
  201. (set-cdr! prev q)
  202. (loop (cdr l) q))))
  203. (if (null? l)
  204. l
  205. (let ((first (cons (car l) '())))
  206. (loop (cdr l) first)
  207. first)))
  208. (sort!! (list-copy list) less?))
  209. (define *perms* '())
  210. (define (one..n n)
  211. (do ((n n (- n 1))
  212. (p '() (cons n p)))
  213. ((zero? n) p)))
  214. (define (perm-benchmark . rest)
  215. (let ((n (if (null? rest) 9 (car rest))))
  216. (set! *perms* '())
  217. (run-benchmark (string-append "Perm" (number->string n))
  218. 1
  219. (lambda ()
  220. (set! *perms* (permutations (one..n n)))
  221. #t)
  222. (lambda (x) #t))))
  223. (define (tenperm-benchmark . rest)
  224. (let ((n (if (null? rest) 9 (car rest))))
  225. (set! *perms* '())
  226. (MpermNKL-benchmark 10 n 2 1)))
  227. (define (MpermNKL-benchmark m n k ell)
  228. (if (and (<= 0 m)
  229. (positive? n)
  230. (positive? k)
  231. (<= 0 ell k))
  232. (let ((id (string-append (number->string m)
  233. "perm"
  234. (number->string n)
  235. ":"
  236. (number->string k)
  237. ":"
  238. (number->string ell)))
  239. (queue (make-vector k '())))
  240. ; Fills queue positions [i, j).
  241. (define (fill-queue i j)
  242. (if (< i j)
  243. (begin (vector-set! queue i (permutations (one..n n)))
  244. (fill-queue (+ i 1) j))))
  245. ; Removes ell elements from queue.
  246. (define (flush-queue)
  247. (let loop ((i 0))
  248. (if (< i k)
  249. (begin (vector-set! queue
  250. i
  251. (let ((j (+ i ell)))
  252. (if (< j k)
  253. (vector-ref queue j)
  254. '())))
  255. (loop (+ i 1))))))
  256. (fill-queue 0 (- k ell))
  257. (run-benchmark id
  258. m
  259. (lambda ()
  260. (fill-queue (- k ell) k)
  261. (flush-queue)
  262. queue)
  263. (lambda (q)
  264. (let ((q0 (vector-ref q 0))
  265. (qi (vector-ref q (max 0 (- k ell 1)))))
  266. (or (and (null? q0) (null? qi))
  267. (and (pair? q0)
  268. (pair? qi)
  269. (equal? (car q0) (car qi))))))))
  270. (begin (display "Incorrect arguments to MpermNKL-benchmark")
  271. (newline))))
  272. (define (sumperms-benchmark . rest)
  273. (let ((n (if (null? rest) 9 (car rest))))
  274. (if (or (null? *perms*)
  275. (not (= n (length (car *perms*)))))
  276. (set! *perms* (permutations (one..n n))))
  277. (run-benchmark (string-append "Sumperms" (number->string n))
  278. 1
  279. (lambda ()
  280. (sumlists *perms*))
  281. (lambda (x) #t))))
  282. (define (mergesort-benchmark . rest)
  283. (let ((n (if (null? rest) 9 (car rest))))
  284. (if (or (null? *perms*)
  285. (not (= n (length (car *perms*)))))
  286. (set! *perms* (permutations (one..n n))))
  287. (run-benchmark (string-append "Mergesort!" (number->string n))
  288. 1
  289. (lambda ()
  290. (sort!! *perms* lexicographically-less?)
  291. #t)
  292. (lambda (x) #t))))