From: Nikodemus Siivola Date: Thu, 19 Nov 2009 16:08:37 +0000 (+0000) Subject: 1.0.32.33: GENCGC tuning parameters X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=4ec0d70e08ea4b512d45ddbd6c82e8f6a91a914f;p=sbcl.git 1.0.32.33: GENCGC tuning parameters * Define +HIGHEST-NORMAL-GENERATION+ and +PSEUDO-STATIC-GENERATION+ in lisp, and let genesis tell C about them. * Make various generations[gen].foo tweakable from lisp, give them nice interface functions and document the same. * Bits of manual prettification in related parts. --- diff --git a/NEWS b/NEWS index c51f304..493e7a0 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,8 @@ changes relative to sbcl-1.0.32: 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 diff --git a/doc/manual/beyond-ansi.texinfo b/doc/manual/beyond-ansi.texinfo index 4a30020..e595663 100644 --- a/doc/manual/beyond-ansi.texinfo +++ b/doc/manual/beyond-ansi.texinfo @@ -22,20 +22,48 @@ it still has quite a few. @xref{Contributed Modules}. @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 @@ -381,6 +409,7 @@ accessor @code{sb-ext:name-conflict-symbols}. @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}. diff --git a/doc/manual/efficiency.texinfo b/doc/manual/efficiency.texinfo index 5c94214..9b7cfd6 100644 --- a/doc/manual/efficiency.texinfo +++ b/doc/manual/efficiency.texinfo @@ -121,7 +121,7 @@ user-defined structures when the structure constructor defined using 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 diff --git a/doc/manual/sbcl.texinfo b/doc/manual/sbcl.texinfo index 02bd67d..fd58d2f 100644 --- a/doc/manual/sbcl.texinfo +++ b/doc/manual/sbcl.texinfo @@ -52,6 +52,9 @@ provided with absolutely no warranty. See the @file{COPYING} and @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 diff --git a/package-data-list.lisp-expr b/package-data-list.lisp-expr index aea5140..2dfb02b 100644 --- a/package-data-list.lisp-expr +++ b/package-data-list.lisp-expr @@ -597,6 +597,14 @@ like *STACK-TOP-HINT* and unsupported stuff like *TRACED-FUN-LIST*." "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*" @@ -2446,10 +2454,12 @@ no guarantees of interface stability." 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" diff --git a/src/code/final.lisp b/src/code/final.lisp index fc807f4..cfa36f1 100644 --- a/src/code/final.lisp +++ b/src/code/final.lisp @@ -41,19 +41,21 @@ signalled in whichever thread the FUNCTION was called in. 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 () @@ -64,7 +66,7 @@ Examples: (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.")) diff --git a/src/code/gc.lisp b/src/code/gc.lisp index 06d38a0..9c98561 100644 --- a/src/code/gc.lisp +++ b/src/code/gc.lisp @@ -304,8 +304,8 @@ run in any thread.") (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))) @@ -321,3 +321,106 @@ run in any thread.") (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)) diff --git a/src/code/time.lisp b/src/code/time.lisp index 6cdb53d..8cf2e00 100644 --- a/src/code/time.lisp +++ b/src/code/time.lisp @@ -257,8 +257,10 @@ format." (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 diff --git a/src/compiler/constraint.lisp b/src/compiler/constraint.lisp index 5a4c627..df2f3b9 100644 --- a/src/compiler/constraint.lisp +++ b/src/compiler/constraint.lisp @@ -508,9 +508,15 @@ (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 diff --git a/src/compiler/generic/genesis.lisp b/src/compiler/generic/genesis.lisp index db3ca48..edd8074 100644 --- a/src/compiler/generic/genesis.lisp +++ b/src/compiler/generic/genesis.lisp @@ -2778,7 +2778,8 @@ core and return a descriptor to it." (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 diff --git a/src/compiler/generic/parms.lisp b/src/compiler/generic/parms.lisp index 6bb0e77..3995376 100644 --- a/src/compiler/generic/parms.lisp +++ b/src/compiler/generic/parms.lisp @@ -81,6 +81,11 @@ ;;; 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 diff --git a/src/runtime/gencgc.c b/src/runtime/gencgc.c index 8937ebe..5bd67c8 100644 --- a/src/runtime/gencgc.c +++ b/src/runtime/gencgc.c @@ -69,9 +69,7 @@ page_index_t gc_find_freeish_pages(long *restart_page_ptr, long nbytes, * 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 }; @@ -257,7 +255,12 @@ size_t void_diff(void *x, void *y) 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 */ @@ -287,9 +290,9 @@ struct generation { /* 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 @@ -301,7 +304,7 @@ struct generation { /* 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. */ @@ -416,8 +419,8 @@ count_generation_bytes_allocated (generation_index_t gen) } /* 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; @@ -500,7 +503,7 @@ print_generation_stats() /* FIXME: should take FILE argument, or construct a str 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); @@ -4357,7 +4360,7 @@ collect_garbage(generation_index_t last_gen) } 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) { @@ -4394,8 +4397,8 @@ collect_garbage(generation_index_t last_gen) && 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. @@ -4599,8 +4602,8 @@ gc_init(void) 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; } diff --git a/tools-for-build/grovel-headers.c b/tools-for-build/grovel-headers.c index 58458b0..b8c34b6 100644 --- a/tools-for-build/grovel-headers.c +++ b/tools-for-build/grovel-headers.c @@ -57,6 +57,7 @@ #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))); } @@ -437,10 +438,11 @@ main(int argc, char *argv[]) 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); @@ -450,5 +452,14 @@ main(int argc, char *argv[]) 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; } diff --git a/version.lisp-expr b/version.lisp-expr index 967a726..fb7f841 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; 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"