Re: [cmucl-help] 19d pre1 tagged, binaries coming soon.

Lynn Quam <[email protected]>
Newsgroups gmane.lisp.cmucl.devel,gmane.lisp.cmucl.general
Message-ID <[email protected]>
My testing has been confined to the previous tests that I sent you and
the (somewhat limited) use of weak-pointers and finalizations in
FREEDIUS.  Here is the latest version of the
weak-pointer/weak-hashtable test code:

_____________________________________________________________

#+cmu 
(eval-when (eval load compile)
  (pushnew :hack-swank *features*)
  )

#+hack-swank
(in-package :swank)

#+hack-swank
(eval-when (eval load compile)
(import '(ext::weak-pointer-p ext::weak-pointer-value ext::make-weak-pointer))
) ; end eval-when

#+hack-swank
(progn

(defun weak-value-gethash (key ht &optional default)  
  "Access hash-table with weak value."
  (multiple-value-bind (val foundp) (gethash key ht)
    (if foundp
	(values (if (weak-pointer-p val)
		    (weak-pointer-value val)
		    val)
		foundp)
	default)))

(defun (setf weak-value-gethash) (object key ht &optional default)  
  (declare (ignore default))
  "Access hash-table with weak value."
  (if (and object (not (weak-pointer-p object))) ; FIXME to selectively wrap with a weak-pointer.
      (setf (gethash key ht) (make-weak-pointer object))
      (setf (gethash key ht) object))
  object)

(defun save-presented-object (object)
  "Save OBJECT and return the assigned id.
If OBJECT was saved previously return the old id."
  (or (gethash object *object-to-presentation-id*)
      (let ((id (incf *presentation-counter*)))
        (setf (weak-value-gethash id *presentation-id-to-object*) object)
        (setf (gethash object *object-to-presentation-id*) id)
        id)))

(defun lookup-presented-object (id)
  "Retrieve the object corresponding to ID.
The secondary value indicates the absence of an entry."
  (weak-value-gethash id *presentation-id-to-object*))

) ; end #+hack-swank progn

(in-package :cl-user)

#+cmu
(progn

(import '(ext::make-weak-pointer ext::weak-pointer-p))

(defun make-weak-hash-table ()
  (make-hash-table :test #'eql :weak-p t))

(defun full-gc ()
  ;(time  (ext:gc :full t))
  (ext:gc :full t))

) ; end #+cmu progn

#+allegro
(progn

(defun make-weak-pointer (x)
  (let ((wv (excl::weak-vector 1)))
    (setf (aref wv 0) x)
    wv))

(defun make-weak-hash-table ()
  (make-hash-table :weak-keys t))

(defun full-gc ()
  (excl:gc t))

) ; end #+allegro progn

;; When CMUCL garbages a weak-pointer, this allows printing to be more informative.
(defun carefully-print-sexpr (x)
  (handler-case (format t "   ~s~%" x)
    (error ()
      (if (listp x)
	  (progn (write-char #\()
		 (loop for y in x
		       do (carefully-print-sexpr y)
			  (write-char #\space)
			  (write-char #\))))
	  (handler-case (progn (format t "<bad element: type = ~a>" (type-of x)) (force-output))
	    (error () (format t "<very bad type>") (force-output)))))))

(defun print-hash-table (ht)
  (maphash #'(lambda (key val) 
	       (format t "~s = " key)
	       (carefully-print-sexpr val))
	   ht))

(defparameter *WEAK-EVAL-CACHE-KEY-HT* (make-hash-table :test #'equal))

(defvar *key-lists* t)

(defun make-weak-eval-cache-key (key)
  (if *key-lists*
      (let ((key (list key)))
	;; make sure EQUAL keys are EQ.
	(or (gethash key *WEAK-EVAL-CACHE-KEY-HT*)
	    (setf (gethash key *WEAK-EVAL-CACHE-KEY-HT*) key)))
      key))


(defclass foo () ())

(defparameter *foo-instance-counter* 0)

;;; These make-a-foo varients are attempts to understand the nature of the bug.
;;; See test results below.

(defun make-a-foo (ht)
  (let* ((id (incf *foo-instance-counter*))
	 (key (make-weak-eval-cache-key id))
	 (o (make-instance 'foo)))
    (setf (gethash key ht) 
	  (make-weak-pointer o))
    o))

(defun make-a-foo-list-val (ht)
  (let* ((id (incf *foo-instance-counter*))
	 (o (make-instance 'foo))
	 (key (make-weak-eval-cache-key id)))
    (setf (gethash key ht) 
	  (list (make-weak-pointer o)))
    o))

(defparameter *foo-alist* nil)

;;; This builds the association of id with foo instance in an alist rather than a hash-table.
(defun alist-make-a-foo (ignore)
  (declare (ignore ignore))
  (let* ((id (incf *foo-instance-counter*))
	 (o (make-instance 'foo))
	 (key (make-weak-eval-cache-key id)))
    (push (cons key (make-weak-pointer o))
	  *foo-alist*)
    o))

(defun alist-make-a-foo-list-val (ignore) 
  (declare (ignore ignore))
  (let* ((id (incf *foo-instance-counter*))(o (make-instance 'foo))
	 (key (make-weak-eval-cache-key id)))
    (push (cons key (list (make-weak-pointer o)))
	  *foo-alist*)
    o))

(defvar *foo-ht*)

(defparameter *n-foos* 2)

(defun print-foos ()
  (if *foo-ht*
      (print-hash-table *foo-ht*)
      (carefully-print-sexpr *foo-alist*)))

(defparameter *cons-cnt* 100000)

(defun cons-a-lot (&optional (n *cons-cnt*))
  (loop repeat n collect nil))

;; This version (usually) works in all combinations of CMUCL/Allegro and SLIME/not SLIME.
;;   For some reason, CMUCL/not-SLIME fails all cases except (foo-test 'make-a-foo (make-hash-table))
;; With the call to print-foos removed , weak-pointers get broken.
;; Running interpreted runs sucessfully, compiled (sometimes) fails.
(defun foo-test (maker-fn &key (weak-p nil) (n *n-foos*) (key-lists t))
  (format t "Running (foo-test ~a :weak-p=~a :key-lists=~a)~%" maker-fn weak-p key-lists)
  (setq *foo-ht* (unless (eq maker-fn 'alist-make-a-foo)
		   (if weak-p (make-weak-hash-table ) (make-hash-table )))
	*foo-alist* nil)
  (let* ((*key-lists* key-lists)
	 (foos (loop for i from 0 below n
		     collect (funcall maker-fn *foo-ht*))))
    
    )
  (cons-a-lot) ; this is needed in order for the weak-pointers to break(recurse-deeply-to-clean-stack)
  ;;(recurse-deeply-to-clean-stack) ; this doesn't help
  (full-gc)
  *foo-ht*)

(defun print-one-foo ()
  (if *foo-ht*
      (loop for val being the hash-values of *foo-ht*
	    using (hash-key key)
	    repeat 1 
	    do (format t "~s =~%" key)
	       (carefully-print-sexpr val))
      (carefully-print-sexpr (first *foo-alist*))))

(defun recurse-deeply-to-clean-stack (&optional (n 100))
  (declare (optimize (debug 3))) ; force tail-call optimization off
  (when (> n 0)
    (recurse-deeply-to-clean-stack (1- n))))

(defun gc-and-print-foos (n)
  (progn (setq * nil ** nil *** nil 
	       ;; $ nil $$ nil $$$ nil 
	       / nil // nil /// nil)
	 (clrhash swank::*object-to-presentation-id*)
	 (clrhash swank::*presentation-id-to-object*) 
	 (swank::reset-inspector))
  (loop repeat n
	do (cons-a-lot)
	   (full-gc)
	   (print-foos)))


#|
(load (compile-file "/homedir/quam/lisp/cmucl-bugs/20060704-weak-bug6.lisp"))
#+cmu (setq ext::*gc-verbose* nil)

(foo-test 'alist-make-a-foo)
(gc-and-print-foos 5)

(foo-test 'alist-make-a-foo :key-lists nil)
(gc-and-print-foos 5)

(foo-test 'make-a-foo)
(gc-and-print-foos 5)

(foo-test 'make-a-foo-list-val)
(gc-and-print-foos 5)

(foo-test 'make-a-foo :key-lists nil)
(gc-and-print-foos 5)

(foo-test 'make-a-foo-list-val :key-lists nil)
(gc-and-print-foos 5)

(foo-test 'make-a-foo :weak-p t)
(gc-and-print-foos 5)

(foo-test 'make-a-foo-list-val :weak-p t)
(gc-and-print-foos 5)

|#
__________________________________________________________

>  
>  >>>>> "Lynn" == Lynn Quam <[email protected]> writes:
>  
>      Lynn> I wish to report that cmucl-19d-pre1-x86-linux (and
>      Lynn> cmucl-2006-10-x86-linux) appears to function properly with FREEDIUS, a
>      Lynn> large image/graphics intensive system.  My tests included the previous
>      Lynn> ones using weak pointers, weak hashtables, and finalization.
>  
>  That's really great news!  Are you only using weak key hashtables?  Or
>  are you also using some of the other weak hashtables?
>  
>  Thanks for testing this!
>  
>  Ray
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.