A test no longer fails.
[sbcl.git] / tests / solist.pure.lisp
blob12ba19de9c83597b6b378b415fce37f8ea04055b
1 (shadowing-import 'sb-lockless::endp)
2 (import 'sb-int::(aver fixnump unbound-marker-p))
3 (import 'sb-sys:with-pinned-objects)
4 (import 'sb-kernel::(generation-of get-lisp-obj-address))
5 (import 'sb-lockless::(+hash-nbits+ %node-next
6 get-next node-hash
7 so-head so-bins so-key so-data so-count
8 so-key-node-p
9 so-insert so-delete so-find so-find/string so-maplist
10 make-so-map/string make-so-set/string make-so-map/addr
11 make-marked-ref))
13 ;;; Make sure no promotions occur so that objects will be movable
14 ;;; throughout these tests.
15 (setf (generation-number-of-gcs-before-promotion 0) 1000000)
17 (defun dummy-node-p (node) (evenp (node-hash node)))
19 ;;; Show all nodes including dummies.
20 (defun show-list (solist)
21 (let ((node (so-head solist)))
22 (loop (format t "~s~%" node)
23 (when (endp node) (return))
24 (setq node (%node-next node)))))
26 (defun show-bin (solist i)
27 (let ((node (aref (car (so-bins solist)) i))
28 (bin-nbits (- +hash-nbits+ (cdr (so-bins solist))))
29 (count 0))
30 (flet ((bit-string (hash)
31 (let ((s (format nil " ~v,'0b" +hash-nbits+ hash)))
32 (replace s s :end1 bin-nbits :start2 1)
33 (setf (char s bin-nbits) #\.)
34 s)))
35 (cond
36 ((unbound-marker-p node)
37 (values 0 0))
39 (let ((node node))
40 (loop (let ((next (get-next node)))
41 (when (or (endp next) (evenp (node-hash next)))
42 (return))
43 (incf count)
44 (setq node next))))
45 (format t " ~5d [~2d] = ~a" i count (bit-string (node-hash node)))
46 (loop (let ((next (get-next node)))
47 (when (or (endp next) (evenp (node-hash next)))
48 (return))
49 (setq node next)
50 (if (= count 1)
51 (format t " ~a=~s"
52 (bit-string (node-hash node)) (so-key node))
53 (format t "~% ~a=~s"
54 (bit-string (node-hash node)) (so-key node)))))
55 (terpri)
56 (values 1 count))))))
58 (defun show-bins (solist)
59 (let ((bins (car (so-bins solist)))
60 (bin-nbits (- +hash-nbits+ (cdr (so-bins solist))))
61 (n-occupied-bins 0)
62 (sum-chainlengths 0)
63 (max-chainlength 0))
64 (aver (= (length bins) (ash 1 bin-nbits)))
65 (format t "Bins (~d total, ~d leading bits):~%"
66 (length bins) bin-nbits)
67 (dotimes (i (length bins))
68 (multiple-value-bind (occupied count) (show-bin solist i)
69 (incf n-occupied-bins occupied)
70 (incf sum-chainlengths count)
71 (setq max-chainlength (max count max-chainlength))))
72 (let ((avg-chainlength (/ sum-chainlengths n-occupied-bins)))
73 (format t "~&Total ~D items, avg ~F items/bin~%"
74 (so-count solist) avg-chainlength)
75 (values max-chainlength (float avg-chainlength)))))
77 (defun print-hashes (solist)
78 (do ((node (%node-next (so-head solist)) (%node-next node)))
79 ((endp node))
80 (format t "~16x~@[ ~s~]~%"
81 (node-hash node)
82 (if (so-key-node-p node) (type-of (so-key node))))))
85 ;;; Our SXHASH has _extremely_ bad behavior for the split-order algorithm,
86 ;;; which consumes high bits before low bits. The high bits tend not to get
87 ;;; randomized at all.
88 ;;; Perhaps we should actually try to hash FIXNUMs better for users. Example:
89 * (dotimes (i 20)
90 (let ((a (+ sb-vm:dynamic-space-start (* i 32768))))
91 (format t "~4d ~x ~v,'0b~%" i a (or #+64-bit 64 32) (sxhash a))))
92 0 1000000000 0001000010010001101110100101010000110101100010111010111001001010
93 1 1000008000 0001000010010001101110100101010000110101100000111110111001001010
94 2 1000010000 0001000010010001101110100101010000110101100110110010111001001010
95 3 1000018000 0001000010010001101110100101010000110101100100110110111001001010
96 4 1000020000 0001000010010001101110100101010000110101101010101010111001001010
97 5 1000028000 0001000010010001101110100101010000110101101000101110111001001010
98 6 1000030000 0001000010010001101110100101010000110101101110100010111001001010
99 7 1000038000 0001000010010001101110100101010000110101101100100110111001001010
100 8 1000040000 0001000010010001101110100101010000110101110010011010111001001010
101 9 1000048000 0001000010010001101110100101010000110101110000011110111001001010
102 10 1000050000 0001000010010001101110100101010000110101110110010010111001001010
103 11 1000058000 0001000010010001101110100101010000110101110100010110111001001010
104 12 1000060000 0001000010010001101110100101010000110101111010001010111001001010
105 13 1000068000 0001000010010001101110100101010000110101111000001110111001001010
106 14 1000070000 0001000010010001101110100101010000110101111110000010111001001010
107 15 1000078000 0001000010010001101110100101010000110101111100000110111001001010
111 (defparameter *strings*
112 (let ((h (make-hash-table :test 'equal)))
113 (dolist (str (sb-vm:list-allocated-objects :all :test #'simple-string-p))
114 (setf (gethash (string str) h) t))
115 (loop for str being each hash-key of h collect str)))
117 (defun fill-table-from (table list)
118 (dolist (key list table)
119 (if (hash-table-p table)
120 (setf (gethash key table) t)
121 (so-insert table key t))))
123 (defun make-threads (nwriters nreaders sem strings-holder writer-fn reader-fn)
124 (format t "~&GCing...~%")
125 (gc :full t)
126 (format t "~&Starting test...~%")
127 (append
128 (loop for i below nwriters
129 collect
130 (sb-thread:make-thread
131 (lambda (&aux (ct 0))
132 (sb-thread:wait-on-semaphore sem)
133 (loop
134 (let ((string (pop (car strings-holder))))
135 (unless string (return ct))
136 (incf ct)
137 (funcall writer-fn string))))
138 :name (format nil "writer ~D" i)))
139 (loop for i below nreaders
140 collect
141 (sb-thread:make-thread
142 (lambda (&aux (found 0))
143 (sb-thread:wait-on-semaphore sem)
144 (loop
145 ;; just read every string
146 (dolist (str *strings*)
147 (when (funcall reader-fn str) (incf found)))
148 (when (null (car strings-holder)) (return found))))
149 :name (format nil "reader ~d" i)))))
151 (defun test-insert-to-synchronized-table (ntrials nwriters nreaders)
152 (let* ((h (make-hash-table :test 'equal :synchronized t))
153 (sem (sb-thread:make-semaphore))
154 (strings-holder (list *strings*))
155 (threads
156 (make-threads nwriters nreaders sem strings-holder
157 (lambda (str) (setf (gethash str h) t)) ; writer action
158 (lambda (str) (gethash str h)))) ; reader action
159 (results))
160 (sb-thread:signal-semaphore sem (+ nwriters nreaders))
161 (time (dolist (thread threads)
162 (push (sb-thread:join-thread thread) results)))
163 (assert (= (hash-table-count h) (length *strings*)))
164 (if (> ntrials 1)
165 (test-insert-to-synchronized-table (1- ntrials) nwriters nreaders)
166 (values h results))))
168 (defun test-insert-to-lockfree-table (ntrials nwriters nreaders)
169 (let* ((h (make-so-map/string))
170 (sem (sb-thread:make-semaphore))
171 (strings-holder (list *strings*))
172 (threads
173 (make-threads nwriters nreaders sem strings-holder
174 (lambda (str) (so-insert h str t))
175 (lambda (str) (so-find/string h str))))
176 (results))
177 (sb-thread:signal-semaphore sem (+ nwriters nreaders))
178 (time (dolist (thread threads)
179 (push (sb-thread:join-thread thread) results)))
180 (assert (= (so-count h) (length *strings*)))
181 (dolist (str *strings*)
182 (assert (so-find/string h str)))
183 (if (> ntrials 1)
184 (test-insert-to-lockfree-table (1- ntrials) nwriters nreaders)
185 (values h results))))
187 (defun test-remove-from-synchronized-table (ntrials nthreads)
188 (let* ((h (fill-table-from (make-hash-table :test 'equal :synchronized t)
189 *strings*))
190 (sem (sb-thread:make-semaphore))
191 (strings-holder (list *strings*))
192 (threads
193 (loop for i below nthreads
194 collect
195 (sb-thread:make-thread
196 (lambda (&aux (ct 0))
197 (sb-thread:wait-on-semaphore sem)
198 (loop
199 (let ((string (pop (car strings-holder))))
200 (unless string (return ct))
201 (incf ct)
202 (remhash string h)))))))
203 (results))
204 (sb-thread:signal-semaphore sem nthreads)
205 (time (dolist (thread threads)
206 (push (sb-thread:join-thread thread) results)))
207 (assert (= (hash-table-count h) 0))
208 (if (> ntrials 1)
209 (test-remove-from-synchronized-table nthreads (1- ntrials))
210 results)))
212 (defun test-remove-from-lockfree-table (ntrials nthreads)
213 (let* ((h (fill-table-from (make-so-map/string)
214 *strings*))
215 (sem (sb-thread:make-semaphore))
216 (strings-holder (list *strings*))
217 (threads
218 (loop for i below nthreads
219 collect
220 (sb-thread:make-thread
221 (lambda (&aux (ct 0))
222 (sb-thread:wait-on-semaphore sem)
223 (loop
224 (let ((string (pop (car strings-holder))))
225 (unless string (return ct))
226 (incf ct)
227 (so-delete h string)))))))
228 (results))
229 (sb-thread:signal-semaphore sem nthreads)
230 (time (dolist (thread threads)
231 (push (sb-thread:join-thread thread) results)))
232 (assert (= (so-count h) 0))
233 (if (> ntrials 1)
234 (test-remove-from-lockfree-table nthreads (1- ntrials))
235 results)))
237 ;;; Smoke test:
238 ;;; - Table starts out with some number of keys (all symbol names)
239 ;;; - One mutator thread removes from the table and notifies a semaphore
240 ;;; each time it has removed one key.
241 ;;; - One mutator thread adds keys and notifies a semaphore.
242 ;;; - The reader asserts that after each semaphore notification,
243 ;;; the table has/doesn't-have the expected key
245 ;; Build a collection of strings to try inserting
246 (defparameter *symbol-names*
247 (let ((h (make-hash-table :test 'equal)))
248 (do-all-symbols (s)
249 (let ((name (string s)))
250 (when (and (find-if #'upper-case-p name)
251 (not (find-if #'lower-case-p name)))
252 (setf (gethash name h) t))))
253 (loop for str being each hash-key of h collect str)))
255 (defun inserter (start-sem msg-sem tbl msgs)
256 (sb-thread:wait-on-semaphore start-sem)
257 (dolist (string *symbol-names*)
258 (let ((key (string-downcase string)))
259 (so-insert tbl key)
260 (atomic-push `(:inserted ,key) (svref msgs 0))
261 (sb-thread:signal-semaphore msg-sem)))
262 (atomic-push `(:done) (svref msgs 0))
263 (sb-thread:signal-semaphore msg-sem))
264 (defun deleter (start-sem msg-sem tbl msgs)
265 (sb-thread:wait-on-semaphore start-sem)
266 (dolist (string *symbol-names*)
267 (so-delete tbl string)
268 (atomic-push `(:deleted ,string) (svref msgs 0))
269 (sb-thread:signal-semaphore msg-sem))
270 (atomic-push `(:done) (svref msgs 0))
271 (sb-thread:signal-semaphore msg-sem))
272 (defun reader (start-sem msg-sem tbl msgs &aux (done-count 0))
273 (sb-thread:wait-on-semaphore start-sem)
274 (loop
275 (sb-thread:wait-on-semaphore msg-sem)
276 (let ((action (atomic-pop (svref msgs 0))))
277 (ecase (car action)
278 (:inserted
279 (let ((key (second action)))
280 (assert (so-find/string tbl key))))
281 (:deleted
282 (let ((key (second action)))
283 (assert (not (so-find/string tbl key)))))
284 (:done
285 (when (= (incf done-count) 2) (return)))))))
287 (defun smoke-test ()
288 (let* ((tbl (make-so-set/string))
289 (start-sem (sb-thread:make-semaphore))
290 (msg-sem (sb-thread:make-semaphore))
291 (msgs (make-array 1 :initial-element nil))
292 (args (list start-sem msg-sem tbl msgs))
293 (threads
294 (list (sb-thread:make-thread #'inserter :arguments args)
295 (sb-thread:make-thread #'deleter :arguments args)
296 (sb-thread:make-thread #'reader :arguments args))))
297 (dolist (string *symbol-names*)
298 (so-insert tbl string))
299 (let ((initial-count (so-count tbl)))
300 (sb-thread:signal-semaphore start-sem 3)
301 (mapc 'sb-thread:join-thread threads)
302 (assert (= (so-count tbl) initial-count)))
303 tbl))
305 (test-util:with-test (:name :basic-functionality :skipped-on (not :sb-thread))
306 (smoke-test))
308 ;;; All threads try to insert each key. At most one thread wins,
309 ;;; and the others increment a count associated with the key.
310 ;;; The final count per key should be the number of threads,
311 ;;; and total number of actual insertions performed across threads
312 ;;; should equal the total number of keys.
313 (defun test-insert-same-keys-concurrently (tbl keys
314 &key (nthreads (floor test-util:*n-cpus* 2))
315 ((:delete keys-to-delete)))
316 (flet ((worker (sem &aux inserted)
317 (sb-thread:wait-on-semaphore sem)
318 (dolist (key keys)
319 (when keys-to-delete
320 (let ((delete (atomic-pop (cdr keys-to-delete))))
321 (when delete
322 (so-delete tbl delete))))
323 (multiple-value-bind (node foundp) (so-insert tbl key (list 1))
324 (if foundp
325 (atomic-incf (car (so-data node)))
326 (push key inserted))))
327 ;; Return the list of keys that this worker inserted
328 inserted))
329 (let* ((start-sem (sb-thread:make-semaphore))
330 (args (list start-sem))
331 (threads
332 (loop repeat nthreads
333 collect (sb-thread:make-thread #'worker :arguments args))))
334 (sb-thread:signal-semaphore start-sem nthreads)
335 (let* ((results (mapcar 'sb-thread:join-thread threads))
336 (counts (mapcar 'length results)))
337 (format t "~&Insertion counts: ~S~%" counts)
338 (assert (= (reduce #'+ counts) (length keys)))
339 (dolist (key keys)
340 (let ((node (so-find tbl key)))
341 (assert (= (car (so-data node)) nthreads))))))))
343 (defun assert-not-found (tbl keys)
344 ;; no key in keys-to-delete should be in the table
345 (dolist (k keys)
346 (assert (not (so-find tbl k)))))
348 (test-util:with-test (:name :concurrently-insert-same-keys/string
349 :skipped-on (not :sb-thread))
350 (let* ((objects *strings*)
351 (tbl (make-so-map/string))
352 (keys-to-delete
353 (loop for i from 1 to (length objects)
354 collect (let ((key (concatenate 'string
355 ;; avoid colliding with anything
356 ;; in *STRINGS*
357 (string #+sb-unicode #\blue_heart
358 #-sb-unicode (code-char 255))
359 (write-to-string i))))
360 (so-insert tbl key i)
361 key))))
362 (test-insert-same-keys-concurrently tbl objects :delete (cons nil keys-to-delete))
363 (assert-not-found tbl keys-to-delete)
364 tbl))
366 ;;; sb-eval gets
367 ;;; UNEXPECTED-FAILURE :CONCURRENTLY-INSERT-SAME-KEYS/OBJECT
368 ;;; due to UNBOUND-VARIABLE: "The variable X is unbound."
369 ;;; It's talking about the X in the REMOVE-IF lambda.
370 ;;; I tried renaming it to BLAHBLAH and sure enough got
371 ;;; due to UNBOUND-VARIABLE: "The variable BLAHBLAH is unbound."
372 ;;; Based on that I know what the problem was: sb-eval uses a certain magic uninterned
373 ;;; symbol in a LET binding frame to indicate that the variable is special.
374 ;;; To read the binding, it examines the value in the storage location, and if it sees
375 ;;; the magic symbol, it calls SYMBOL-VALUE instead. So sb-eval can't actually represent
376 ;;; a lexical var whose _actual_ _value_ is that magic uninterned symbol.
377 ;;; Instead you'll (potentially) get an error that the variable you referenced is
378 ;;; unbound, unless it really is specially bound also.
379 ;;; Naturally MAP-ALLOCATED-OBJECTS produces that symbol, and so this test can't run,
380 ;;; because we "don't know" what the magic symbol is, since it's uninterned and
381 ;;; therefore can't easily weed it out from the list.
382 ;;; sb-fasteval does not use that same technique to represent special bindings,
383 ;;; and has no problem iterating over all symbols.
384 (test-util:with-test (:name :concurrently-insert-same-keys/object
385 :skipped-on (or (not :sb-thread)
386 (and :interpreter (not :sb-fasteval))))
387 (let* ((objects
388 (remove-if (lambda (x)
389 (not (eql (generation-of x) sb-vm:+pseudo-static-generation+)))
390 (sb-vm:list-allocated-objects :all :type sb-vm:symbol-widetag)))
391 (tbl (make-so-map/addr))
392 (keys-to-delete
393 ;; preload the hashset with some keys that will be deleted
394 ;; concurrently with all the insertions
395 (loop for i from 1 to (length objects)
396 do (so-insert tbl i i)
397 collect i)))
398 (test-insert-same-keys-concurrently tbl objects :delete (cons nil keys-to-delete))
399 (assert-not-found tbl keys-to-delete)))
401 (defun logical-delete (node &aux (succ (%node-next node)))
402 (unless (fixnump succ)
403 (with-pinned-objects (succ)
404 (cas (%node-next node) succ (make-marked-ref succ))))
405 node)
407 (defparameter *so-map*
408 (let ((tbl (make-so-map/string)))
409 (loop for i from (char-code #\a) to (char-code #\z)
410 do (so-insert tbl (string (code-char i)) (char-upcase (code-char i))))
411 tbl))
412 (defparameter *keys-in-table-order* nil)
413 (defparameter *deleted-nodes* nil)
414 (defparameter *node-addresses* nil)
416 (let ((x 0))
417 (sb-int:collect ((allkeys) (addresses) (deleted))
418 (so-maplist
419 (lambda (node)
420 (let ((key (so-key node)))
421 (allkeys key)
422 (when (evenp (incf x))
423 (deleted node)
424 (logical-delete node))
425 (addresses (get-lisp-obj-address node))))
426 *so-map*)
427 (setf *keys-in-table-order* (allkeys)
428 *deleted-nodes* (deleted)
429 *node-addresses* (addresses))))
431 (gc)
432 ;;; Most of the node addresses should have changed,
433 ;;; but the list should still be fully intact.
434 (test-util:with-test (:name :solist-integrity)
435 (let ((node (so-head *so-map*))
436 (addr-change 0)
437 (addresses *node-addresses*)
438 (keys *keys-in-table-order*))
439 (loop
440 (cond ((endp node) (return))
441 ((dummy-node-p node) ; skip
442 (setq node (get-next node)))
444 (assert (eq (so-key node) (pop keys)))
445 (unless (= (get-lisp-obj-address node) (pop addresses))
446 (incf addr-change))
447 (multiple-value-bind (next next-bits) (get-next node)
448 (let ((node-deletedp (fixnump next-bits))
449 (found (so-find *so-map* (so-key node))))
450 (assert (eq (not (null (find node *deleted-nodes*)))
451 node-deletedp))
452 (if node-deletedp
453 (assert (not found))
454 (assert (eq found node))))
455 (setq node next)))))
456 #-mark-region-gc
457 (assert (>= addr-change 22)))) ; seems about right
459 ;;; SO-MAPLIST does not include deleted nodes.
460 ;;; Nodes marked for deletion should still be marked after GC
461 ;;; (though it should be possible to modify GC to finish deletion)
462 (test-util:with-test (:name :solist-mid-deletion)
463 (let ((present-keys
464 (remove-if
465 (lambda (string)
466 (member string *deleted-nodes* :key #'so-key :test #'string=))
467 *keys-in-table-order*)))
468 (so-maplist (lambda (node)
469 (assert (string= (so-key node) (pop present-keys))))
470 *so-map*)))
472 (defvar *example-objects*
473 (subseq (append
474 (remove-if (lambda (x) (/= (sb-kernel:generation-of x) sb-vm:+pseudo-static-generation+))
475 (sb-vm:list-allocated-objects :dynamic :type sb-vm:simple-base-string-widetag))
476 (sb-vm:list-allocated-objects :read-only :type sb-vm:simple-base-string-widetag))
477 0 1000))
479 (test-util:with-test (:name :c-find-in-solist)
480 (let ((set (sb-lockless:make-so-set/addr)) )
481 (dolist (x *example-objects*)
482 (sb-lockless:so-insert set x))
483 (assert (not (sb-lockless:c-so-find/addr set 'random)))
484 (dolist (x *example-objects*)
485 (let ((node (sb-lockless:c-so-find/addr set x)))
486 (assert node)
487 (assert (eq (sb-lockless:so-key node) x))))))
489 (test-util:with-test (:name :solist-2-phase-insert)
490 (let ((set (sb-lockless:make-so-set/addr))
491 (example-objects *example-objects*)
492 (n-deleted 0)
493 (nodes))
494 ;; This example is artificial. The real usage would allocate one object and perform
495 ;; both insert phases in the following pattern:
496 ;; begin pseudo-atomic
497 ;; allocate split-order node 'n'
498 ;; allocate off-heap large unboxed object
499 ;; phase1 insert node 'n' pointing to large-object
500 ;; end pseudo-atomic
501 ;; phase2 insert
502 ;; If GC occurs just after the pseudo-atomic section, it is possible to test each stack word
503 ;; as being a conservative pointer to an off-heap object based on its presence in the table.
504 (dolist (object example-objects)
505 (let ((node (sb-lockless::%make-so-set-node 0 0)))
506 (push node nodes)
507 (sb-lockless::%so-eq-set-phase1-insert set node object)))
508 ;; It has no bearing on currectness that the table count is understated and that
509 ;; the number of bins may be too few prior to running the second step.
510 ;; This is evident from the loop below which shows that each example-object can be found.
511 (dolist (node nodes)
512 (sb-lockless::%so-eq-set-phase2-insert set node)
513 ;; delete some keys at random. This could occur only after the node is fully inserted.
514 (when (zerop (random 10))
515 (sb-lockless:so-delete set (sb-lockless:so-key node))
516 (incf n-deleted))
517 (let ((table-count
518 (loop for object in example-objects
519 count (sb-lockless:so-find set object))))
520 (assert (= table-count (- 1000 n-deleted)))))
521 ;; Finally the table count should be correct
522 (assert (= (sb-lockless::so-count set) (- 1000 n-deleted)))
523 set))
526 ;; Speedup: 4x
527 Small test: 20k keys, 8 writers, 2 readers
528 ==========================================
529 * (test-insert-to-synchronized-table 1 8 2)
530 GCing...
531 Starting test...
532 Evaluation took:
533 0.048 seconds of real time
534 0.261340 seconds of total run time (0.091142 user, 0.170198 system)
535 543.75% CPU
536 123,504,864 processor cycles
537 4,029,824 bytes consed
538 #<HASH-TABLE :TEST EQUAL :COUNT 24141 {10010A2803}>
539 * (test-insert-to-lockfree-table 1 8 2)
540 GCing...
541 Starting test...
542 Evaluation took:
543 0.011 seconds of real time
544 0.096867 seconds of total run time (0.096867 user, 0.000000 system)
545 881.82% CPU
546 33,070,828 processor cycles
547 4,924,544 bytes consed
548 #<SPLIT-ORDERED-LIST 24141 keys, 16384 bins {1003CA0373}>
550 ;; Speedup: 7x
551 Large test: 96k keys, 8 writers, 4 readers
552 ==========================================
553 * (test-insert-to-synchronized-table 1 8 4)
554 GCing...
555 Starting test...
556 Evaluation took:
557 0.344 seconds of real time
558 2.180249 seconds of total run time (0.689017 user, 1.491232 system)
559 633.72% CPU
560 963,461,936 processor cycles
561 15,657,312 bytes consed
562 #<HASH-TABLE :TEST EQUAL :COUNT 95949 {10010A56B3}>
563 * (test-insert-to-lockfree-table 1 8 4)
564 GCing...
565 Starting test...
566 Evaluation took:
567 0.047 seconds of real time
568 0.453098 seconds of total run time (0.453098 user, 0.000000 system)
569 963.83% CPU
570 136,186,892 processor cycles
571 12,143,696 bytes consed
572 #<SPLIT-ORDERED-LIST 95949 keys, 32768 bins {10010E2C83}>
574 ;; Speedup: 14x
575 Huge test: 122k keys, 8 writers, 10 readers
576 ============================================
577 * (test-insert-to-synchronized-table 1 8 10)
578 GCing...
579 Starting test...
580 Evaluation took:
581 1.007 seconds of real time
582 10.534241 seconds of total run time (2.623577 user, 7.910664 system)
583 1046.08% CPU
584 2,815,228,188 processor cycles
585 29,103,872 bytes consed
586 * (test-insert-to-lockfree-table 1 8 10)
587 GCing...
588 Starting test...
589 Evaluation took:
590 0.068 seconds of real time
591 1.069891 seconds of total run time (1.069891 user, 0.000000 system)
592 1573.53% CPU
593 187,631,304 processor cycles
594 22,077,904 bytes consed