1.0.32.33: GENCGC tuning parameters
authorNikodemus Siivola <nikodemus@random-state.net>
Thu, 19 Nov 2009 16:08:37 +0000 (16:08 +0000)
committerNikodemus Siivola <nikodemus@random-state.net>
Thu, 19 Nov 2009 16:08:37 +0000 (16:08 +0000)
 * 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.

14 files changed:
NEWS
doc/manual/beyond-ansi.texinfo
doc/manual/efficiency.texinfo
doc/manual/sbcl.texinfo
package-data-list.lisp-expr
src/code/final.lisp
src/code/gc.lisp
src/code/time.lisp
src/compiler/constraint.lisp
src/compiler/generic/genesis.lisp
src/compiler/generic/parms.lisp
src/runtime/gencgc.c
tools-for-build/grovel-headers.c
version.lisp-expr

diff --git a/NEWS b/NEWS
index c51f304..493e7a0 100644 (file)
--- 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
index 4a30020..e595663 100644 (file)
@@ -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}.
index 5c94214..9b7cfd6 100644 (file)
@@ -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
index 02bd67d..fd58d2f 100644 (file)
@@ -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
index aea5140..2dfb02b 100644 (file)
@@ -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"
index fc807f4..cfa36f1 100644 (file)
@@ -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."))
index 06d38a0..9c98561 100644 (file)
@@ -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))
index 6cdb53d..8cf2e00 100644 (file)
@@ -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
index 5a4c627..df2f3b9 100644 (file)
                       (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
index db3ca48..edd8074 100644 (file)
@@ -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
index 6bb0e77..3995376 100644 (file)
 ;;; 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
index 8937ebe..5bd67c8 100644 (file)
@@ -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;
     }
 
index 58458b0..b8c34b6 100644 (file)
@@ -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;
 }
index 967a726..fb7f841 100644 (file)
@@ -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"