enabled in customize-target-features.lisp. This will increase the core
size by about 5-6mb, though, so it's mostly interesting to SBCL
developers.
+ * new feature: various GENCGC tuning parameters have been experimentally
+ documented and exported from SB-EXT. See documentation for details.
* fixes and improvements related to Unicode and external formats:
** the Unicode character database has been upgraded to the
Unicode 5.2 standard, giving names and properties to a number of new
@node Garbage Collection
@comment node-name, next, previous, up
@section Garbage Collection
+@cindex Garbage collection
SBCL provides additional garbage collection functionality not
-specified by ANSI. Weak pointers allow references to objects to be
-maintained without keeping them from being garbage collected, and
-``finalization'' hooks are available to cause code to be executed when
-an object has been garbage collected. Additionally users can specify
-their own cleanup actions to be executed with garbage collection. See
-also @code{make-hash-table} for information on weak hash tables.
+specified by ANSI.
+
+@include var-sb-ext-star-after-gc-hooks-star.texinfo
+@include fun-sb-ext-gc.texinfo
+
+@subsection Finalization
+@cindex Finalization
+
+Finalization allows code to be executed after an object has been
+garbage collected. This is useful for example for releasing foreign
+memory associated with a Lisp object.
@include fun-sb-ext-finalize.texinfo
@include fun-sb-ext-cancel-finalization.texinfo
+
+@subsection Weak Pointers
+@cindex Weak pointers
+
+Weak pointers allow references to objects to be maintained without
+keeping them from being garbage collected: useful for building caches
+among other things.
+
+Hash tables can also have weak keys and values: @pxref{Hash Table
+Extensions}.
+
@include fun-sb-ext-make-weak-pointer.texinfo
@include fun-sb-ext-weak-pointer-value.texinfo
-@include var-sb-ext-star-after-gc-hooks-star.texinfo
+
+@subsection Introspection and Tuning
+
+@include var-sb-ext-star-gc-run-time-star.texinfo
+@include fun-sb-ext-bytes-consed-between-gcs.texinfo
+@include fun-sb-ext-generation-average-age.texinfo
+@include fun-sb-ext-generation-bytes-allocated.texinfo
+@include fun-sb-ext-generation-bytes-consed-between-gcs.texinfo
+@include fun-sb-ext-generation-minimum-age-before-gc.texinfo
+@include fun-sb-ext-generation-number-of-gcs-before-promotion.texinfo
+@include fun-sb-ext-generation-number-of-gcs.texinfo
+@include fun-sb-ext-get-bytes-consed.texinfo
@node Metaobject Protocol
@comment node-name, next, previous, up
@node Hash Table Extensions
@comment node-name, next, previous, up
@section Hash Table Extensions
+@cindex Hash tables
Hash table extensions supported by SBCL are all controlled by keyword
arguments to @code{make-hash-table}.
call to the constructor is bound to a variable declared
@code{dynamic-extent}.
-@strong{Note:} structures with ``raw'' slots can currently be
+@strong{Note}: structures with ``raw'' slots can currently be
stack-allocated only on x86 and x86-64.
@item
@c We use @&key, etc to escape & from TeX in lambda lists --
@c so we need to define them for info as well.
+@macro &allow-other-keys
+&allow-other-keys
+@end macro
@macro &optional
&optional
@end macro
"GC" "GET-BYTES-CONSED"
"*GC-RUN-TIME*"
"PURIFY"
+ ;; Gencgc only, but symbols exist for manual building
+ ;; convenience on all platforms.
+ "GENERATION-AVERAGE-AGE"
+ "GENERATION-BYTES-ALLOCATED"
+ "GENERATION-BYTES-CONSED-BETWEEN-GCS"
+ "GENERATION-MINIMUM-AGE-BEFORE-GC"
+ "GENERATION-NUMBER-OF-GCS"
+ "GENERATION-NUMBER-OF-GCS-BEFORE-PROMOTION"
;; Stack allocation control
"*STACK-ALLOCATE-DYNAMIC-EXTENT*"
structure representations"
:use ("CL" "SB!ALIEN" "SB!ALIEN-INTERNALS" "SB!ASSEM" "SB!C"
"SB!EXT" "SB!FASL" "SB!INT" "SB!KERNEL" "SB!SYS" "SB!UNIX")
- :export ("*ASSEMBLY-UNIT-LENGTH*"
+ :export ("*ALLOC-SIGNAL*"
+ "*ASSEMBLY-UNIT-LENGTH*"
"*PRIMITIVE-OBJECTS*"
+ "+HIGHEST-NORMAL-GENERATION+"
+ "+PSEUDO-STATIC-GENERATION+"
"AFTER-BREAKPOINT-TRAP"
- "*ALLOC-SIGNAL*"
"ANY-REG-SC-NUMBER" "ARRAY-DATA-SLOT" "ARRAY-DIMENSIONS-OFFSET"
"ARRAY-DISPLACED-P-SLOT" "ARRAY-DISPLACEMENT-SLOT"
"ARRAY-DISPLACED-FROM-SLOT"
Examples:
- ;;; good (assumes RELEASE-HANDLE is re-entrant)
+ ;;; GOOD, assuming RELEASE-HANDLE is re-entrant.
(let* ((handle (get-handle))
(object (make-object handle)))
(finalize object (lambda () (release-handle handle)))
object)
- ;;; bad, finalizer refers to object being finalized, causing
- ;;; it to be retained indefinitely
+ ;;; BAD, finalizer refers to object being finalized, causing
+ ;;; it to be retained indefinitely!
(let* ((handle (get-handle))
(object (make-object handle)))
- (finalize object (lambda () (release-handle (object-handle object)))))
+ (finalize object
+ (lambda ()
+ (release-handle (object-handle object)))))
- ;;; bad, not re-entrant
+ ;;; BAD, not re-entrant!
(defvar *rec* nil)
(defun oops ()
(progn
(finalize \"oops\" #'oops)
- (oops)) ; causes GC and re-entry to #'oops due to the finalizer
+ (oops)) ; GC causes re-entry to #'oops due to the finalizer
; -> ERROR, caught, WARNING signalled"
(unless object
(error "Cannot finalize NIL."))
(defun bytes-consed-between-gcs ()
#!+sb-doc
- "Return the amount of memory that will be allocated before the next garbage
- collection is initiated. This can be set with SETF."
+ "The amount of memory that will be allocated before the next garbage
+collection is initiated. This can be set with SETF."
(sb!alien:extern-alien "bytes_consed_between_gcs"
(sb!alien:unsigned 32)))
(or #!+sb-thread *stop-for-gc-pending*
*gc-pending*))
(sb!unix::receive-pending-interrupt)))
+
+;;;; GENCGC specifics
+;;;;
+;;;; For documentation convenience, these have stubs on non-GENCGC platforms
+;;;; as well.
+#!+gencgc
+(deftype generation-index ()
+ '(integer 0 #.sb!vm:+pseudo-static-generation+))
+
+;;; FIXME: GENERATION (and PAGE, as seen in room.lisp) should probably be
+;;; defined in Lisp, and written to header files by genesis, instead of this
+;;; OAOOMiness -- this duplicates the struct definition in gencgc.c.
+#!+gencgc
+(define-alien-type generation
+ (struct generation
+ (alloc-start-page page-index-t)
+ (alloc-unboxed-start-page page-index-t)
+ (alloc-large-start-page page-index-t)
+ (alloc-large-unboxed-start-page page-index-t)
+ (bytes-allocated unsigned-long)
+ (gc-trigger unsigned-long)
+ (bytes-consed-between-gcs unsigned-long)
+ (number-of-gcs int)
+ (number-of-gcs-before-promotion int)
+ (cum-sum-bytes-allocated unsigned-long)
+ (minimum-age-before-gc double)))
+
+#!+gencgc
+(define-alien-variable generations
+ (array generation #.(1+ sb!vm:+pseudo-static-generation+)))
+
+(macrolet ((def (slot doc &optional setfp)
+ (declare (ignorable doc))
+ `(progn
+ (defun ,(symbolicate "GENERATION-" slot) (generation)
+ #!+sb-doc
+ ,doc
+ (declare (generation-index generation))
+ #!-gencgc
+ (declare (ignore generation))
+ #!-gencgc
+ (error "~S is a GENCGC only function and unavailable in this build"
+ ',name)
+ #!+gencgc
+ (slot (deref generations generation) ',slot))
+ ,@(when setfp
+ `((defun (setf ,(symbolicate "GENERATION-" slot)) (value generation)
+ (declare (generation-index generation))
+ #!-gencgc
+ (declare (ignore value generation))
+ #!-gencgc
+ (error "(SETF ~S) is a GENCGC only function and unavailable in this build"
+ ',name)
+ #!+gencgc
+ (setf (slot (deref generations generation) ',slot) value)))))))
+ (def bytes-consed-between-gcs
+ "Number of bytes that can be allocated to GENERATION before that
+generation is considered for garbage collection. This value is meaningless for
+generation 0 (the nursery): see BYTES-CONSED-BETWEEN-GCS instead. Default is
+20Mb. Can be assigned to using SETF. Available on GENCGC platforms only.
+
+Experimental: interface subject to change."
+ t)
+ (def minimum-age-before-gc
+ "Minimum average age of objects allocated to GENERATION before that
+generation is may be garbage collected. Default is 0.75. See also
+GENERATION-AVERAGE-AGE. Can be assigned to using SETF. Available on GENCGC
+platforms only.
+
+Experimental: interface subject to change."
+ t)
+ (def number-of-gcs-before-promotion
+ "Number of times garbage collection is done on GENERATION before
+automatic promotion to the next generation is triggered. Can be assigned to
+using SETF. Available on GENCGC platforms only.
+
+Experimental: interface subject to change."
+ t)
+ (def bytes-allocated
+ "Number of bytes allocated to GENERATION currently. Available on GENCGC
+platforms only.
+
+Experimental: interface subject to change.")
+ (def number-of-gcs
+ "Number of times garbage collection has been done on GENERATION without
+promotion. Available on GENCGC platforms only.
+
+Experimental: interface subject to change."))
+ (defun generation-average-age (generation)
+ "Average age of memory allocated to GENERATION: average number of times
+objects allocated to the generation have seen younger objects promoted to it.
+Available on GENCGC platforms only.
+
+Experimental: interface subject to change."
+ (declare (generation-index generation))
+ #!-gencgc (declare (ignore generation))
+ #!-gencgc
+ (error "~S is a GENCGC only function and unavailable in this build."
+ 'generation-average-age)
+ #!+gencgc
+ (alien-funcall (extern-alien "generation_average_age"
+ (function double generation-index-t))
+ generation))
(defvar *gc-run-time* 0
#!+sb-doc
- "the total CPU time spent doing garbage collection (as reported by
- GET-INTERNAL-RUN-TIME)")
+ "Total CPU time spent doing garbage collection (as reported by
+GET-INTERNAL-RUN-TIME.) Initialized to zero on startup. It is safe to bind
+this to zero in order to measure GC time inside a certain section of code, but
+doing so may interfere with results reported by eg. TIME.")
(declaim (type index *gc-run-time*))
(defun print-time (&key real-time-ms user-run-time-us system-run-time-us
(add (if (eq name '<) '> '<) var2 (lvar-type arg1) nil))))
(t
(let ((ptype (gethash name *backend-predicate-types*)))
- (when ptype
- (add 'typep (ok-lvar-lambda-var (first args) constraints)
- ptype nil))))))))))
+ (if ptype
+ (add 'typep (ok-lvar-lambda-var (first args) constraints)
+ ptype nil)
+ (with-open-file (f "/tmp/unknown.txt"
+ :if-exists :append
+ :if-does-not-exist :create
+ :direction :output)
+ (let ((*package* (find-package :keyword)))
+ (format f "~S~%" name))))))))))))
(values consequent-constraints alternative-constraints))))
;;;; Applying constraints
(maybe-record-with-translated-name '("-SIZE") 6)
(maybe-record-with-translated-name '("-START" "-END" "-PAGE-BYTES") 7 :large t)
(maybe-record-with-translated-name '("-CORE-ENTRY-TYPE-CODE") 8)
- (maybe-record-with-translated-name '("-CORE-SPACE-ID") 9))))))
+ (maybe-record-with-translated-name '("-CORE-SPACE-ID") 9)
+ (maybe-record-with-translated-name '("-GENERATION+") 10))))))
;; KLUDGE: these constants are sort of important, but there's no
;; pleasing way to inform the code above about them. So we fake
;; it for now. nikodemus on #lisp (2004-08-09) suggested simply
;;; of symbols with thread local bindings.
(def!constant tls-size 4096)
+#!+gencgc
+(progn
+ (def!constant +highest-normal-generation+ 5)
+ (def!constant +pseudo-static-generation+ 6))
+
(defenum ()
trace-table-normal
trace-table-call-site
* scratch space by the collector, and should never get collected.
*/
enum {
- HIGHEST_NORMAL_GENERATION = 5,
- PSEUDO_STATIC_GENERATION,
- SCRATCH_GENERATION,
+ SCRATCH_GENERATION = PSEUDO_STATIC_GENERATION+1,
NUM_GENERATIONS
};
return (pointer_sized_uint_t)x - (pointer_sized_uint_t)y;
}
-/* a structure to hold the state of a generation */
+/* a structure to hold the state of a generation
+ *
+ * CAUTION: If you modify this, make sure to touch up the alien
+ * definition in src/code/gc.lisp accordingly. ...or better yes,
+ * deal with the FIXME there...
+ */
struct generation {
/* the first page that gc_alloc() checks on its next call */
/* the number of GCs since the last raise */
int num_gc;
- /* the average age after which a GC will raise objects to the
+ /* the number of GCs to run on the generations before raising objects to the
* next generation */
- int trigger_age;
+ int number_of_gcs_before_promotion;
/* the cumulative sum of the bytes allocated to this generation. It is
* cleared after a GC on this generations, and update before new
/* a minimum average memory age before a GC will occur helps
* prevent a GC when a large number of new live objects have been
* added, in which case a GC could be a waste of time */
- double min_av_mem_age;
+ double minimum_age_before_gc;
/* A linked list of lutex structures in this generation, used for
* implementing lutex finalization. */
}
/* Return the average age of the memory in a generation. */
-static double
-gen_av_mem_age(generation_index_t gen)
+extern double
+generation_average_age(generation_index_t gen)
{
if (generations[gen].bytes_allocated == 0)
return 0.0;
generations[i].gc_trigger,
count_write_protect_generation_pages(i),
generations[i].num_gc,
- gen_av_mem_age(i));
+ generation_average_age(i));
}
fprintf(stderr," Total bytes allocated = %lu\n", bytes_allocated);
fprintf(stderr," Dynamic-space-size bytes = %u\n", dynamic_space_size);
} else {
raise =
(gen < last_gen)
- || (generations[gen].num_gc >= generations[gen].trigger_age);
+ || (generations[gen].num_gc >= generations[gen].number_of_gcs_before_promotion);
}
if (gencgc_verbose > 1) {
&& raise
&& (generations[gen].bytes_allocated
> generations[gen].gc_trigger)
- && (gen_av_mem_age(gen)
- > generations[gen].min_av_mem_age))));
+ && (generation_average_age(gen)
+ > generations[gen].minimum_age_before_gc))));
/* Now if gen-1 was raised all generations before gen are empty.
* If it wasn't raised then all generations before gen-1 are empty.
generations[i].cum_sum_bytes_allocated = 0;
/* the tune-able parameters */
generations[i].bytes_consed_between_gc = 2000000;
- generations[i].trigger_age = 1;
- generations[i].min_av_mem_age = 0.75;
+ generations[i].number_of_gcs_before_promotion = 1;
+ generations[i].minimum_age_before_gc = 0.75;
generations[i].lutexes = NULL;
}
#endif
#include "wrap.h"
+#include "gc.h"
#define DEFTYPE(lispname,cname) { cname foo; \
printf("(define-alien-type " lispname " (%s %d))\n", (((foo=-1)<0) ? "sb!alien:signed" : "unsigned"), (8 * (sizeof foo))); }
defconstant("fpe-fltsub", -1);
#endif
#endif // !WIN32
+ printf("\n");
#ifdef LISP_FEATURE_BSD
printf(";;; sysctl(3) names\n");
- printf("(in-package \"SB!IMPL\")\n\n");
+ printf("(in-package \"SB!IMPL\")\n");
defconstant("ctl-kern", CTL_KERN);
defconstant("ctl-hw", CTL_HW);
defconstant("ctl-maxname", CTL_MAXNAME);
defconstant("hw-pagesize", HW_PAGESIZE);
printf("\n");
#endif
+
+#ifdef LISP_FEATURE_GENCGC
+ printf(";;; GENCGC related\n");
+ printf("(in-package \"SB!KERNEL\")\n");
+ DEFTYPE("page-index-t", page_index_t);
+ DEFTYPE("generation-index-t", generation_index_t);
+ printf("\n");
+#endif
+
return 0;
}
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.32.32"
+"1.0.32.33"