;;;; files for more information.
(in-package "SB!KERNEL")
-
-(file-comment
- "$Header$")
\f
;;;; DYNAMIC-USAGE and friends
(defun ,lisp-fun ()
(sb!alien:extern-alien ,c-var-name (sb!alien:unsigned 32))))))
-(def-c-var-frob sb!vm:control-stack-start "control_stack")
-#!+x86 (def-c-var-frob control-stack-end "control_stack_end")
-(def-c-var-frob sb!vm:binding-stack-start "binding_stack")
-(def-c-var-frob sb!vm:current-dynamic-space-start "current_dynamic_space")
-
#!-sb-fluid (declaim (inline dynamic-usage))
-#!-(or cgc gencgc)
-(defun dynamic-usage ()
- (the (unsigned-byte 32)
- (- (sb!sys:sap-int (sb!c::dynamic-space-free-pointer))
- (sb!vm:current-dynamic-space-start))))
-#!+(or cgc gencgc)
(def-c-var-frob dynamic-usage "bytes_allocated")
(defun static-space-usage ()
(defun read-only-space-usage ()
(- (* sb!vm::*read-only-space-free-pointer* sb!vm:word-bytes)
- sb!vm:*read-only-space-start*))
+ sb!vm:read-only-space-start))
(defun control-stack-usage ()
#!-x86 (- (sb!sys:sap-int (sb!c::control-stack-pointer-sap))
- (control-stack-start))
- #!+x86 (- (control-stack-end)
+ sb!vm:control-stack-start)
+ #!+x86 (- sb!vm:control-stack-end
(sb!sys:sap-int (sb!c::control-stack-pointer-sap))))
(defun binding-stack-usage ()
(- (sb!sys:sap-int (sb!c::binding-stack-pointer-sap))
- (sb!vm:binding-stack-start)))
+ sb!vm:binding-stack-start))
\f
;;;; ROOM
#!+sb-doc
"The total CPU time spent doing garbage collection (as reported by
GET-INTERNAL-RUN-TIME.)")
-
(declaim (type index *gc-run-time*))
+;;; a limit to help catch programs which allocate too much memory,
+;;; since a hard heap overflow is so hard to recover from.
+(declaim (type (or unsigned-byte null) *soft-heap-limit*))
+(defvar *soft-heap-limit* nil)
+
;;; Internal trigger. When the dynamic usage increases beyond this
;;; amount, the system notes that a garbage collection needs to occur by
;;; setting *NEED-TO-COLLECT-GARBAGE* to T. It starts out as NIL meaning
(sb!alien:def-alien-routine collect-garbage sb!c-call:int
#!+gencgc (last-gen sb!c-call:int))
-#!-ibmrt
(sb!alien:def-alien-routine set-auto-gc-trigger sb!c-call:void
(dynamic-usage sb!c-call:unsigned-long))
-#!+ibmrt
-(defun set-auto-gc-trigger (bytes)
- (let ((words (ash (+ (sb!vm:current-dynamic-space-start) bytes) -2)))
- (unless (and (fixnump words) (plusp words))
- (clear-auto-gc-trigger)
- (warn "attempt to set GC trigger to something bogus: ~S" bytes))
- (setf %rt::*internal-gc-trigger* words)))
-
-#!-ibmrt
(sb!alien:def-alien-routine clear-auto-gc-trigger sb!c-call:void)
-#!+ibmrt
-(defun clear-auto-gc-trigger ()
- (setf %rt::*internal-gc-trigger* -1))
-
;;; This variable contains the function that does the real GC. This is
;;; for low-level GC experimentation. Do not touch it if you do not
;;; know what you are doing.
(/show0 "not *ALREADY-MAYBE-GCING*")
(let* ((*already-maybe-gcing* t)
(start-time (get-internal-run-time))
- (pre-gc-dyn-usage (dynamic-usage)))
+ (pre-gc-dyn-usage (dynamic-usage))
+ ;; Currently we only check *SOFT-HEAP-LIMIT* at GC time,
+ ;; not for every allocation. That makes it cheap to do,
+ ;; even if it is a little ugly.
+ (soft-heap-limit-exceeded? (and *soft-heap-limit*
+ (> pre-gc-dyn-usage
+ *soft-heap-limit*)))
+ (*soft-heap-limit* (if soft-heap-limit-exceeded?
+ (+ pre-gc-dyn-usage
+ *bytes-consed-between-gcs*)
+ *soft-heap-limit*)))
+ (when soft-heap-limit-exceeded?
+ (cerror "Continue with GC."
+ "soft heap limit exceeded (temporary new limit=~D)"
+ *soft-heap-limit*))
(unless (integerp (symbol-value '*bytes-consed-between-gcs*))
;; The noise w/ symbol-value above is to keep the compiler
;; from optimizing the test away because of the type declaim
(/show0 "back from FUNCALL to *INTERNAL-GC*")
(let* ((post-gc-dyn-usage (dynamic-usage))
(bytes-freed (- pre-gc-dyn-usage post-gc-dyn-usage)))
+ (/show0 "got (DYNAMIC-USAGE) and BYTES-FREED")
(when *last-bytes-in-use*
+ (/show0 "doing *LAST-BYTES-IN-USE* thing")
(incf *total-bytes-consed*
(- pre-gc-dyn-usage *last-bytes-in-use*))
+ (/show0 "setting *LAST-BYTES-IN-USE*")
(setq *last-bytes-in-use* post-gc-dyn-usage))
+ (/show0 "clearing *NEED-TO-COLLECT-GARBAGE*")
(setf *need-to-collect-garbage* nil)
+ (/show0 "calculating NEW-GC-TRIGGER")
(let ((new-gc-trigger (+ post-gc-dyn-usage
*bytes-consed-between-gcs*)))
+ (/show0 "setting *GC-TRIGGER*")
(setf *gc-trigger* new-gc-trigger))
+ (/show0 "calling SET-AUTO-GC-TRIGGER")
(set-auto-gc-trigger *gc-trigger*)
(dolist (hook *after-gc-hooks*)
(/show0 "doing a hook from *AFTER-GC--HOOKS*")
- ;; FIXME: This hook should be called with the
- ;; same kind of information as *GC-NOTIFY-AFTER*.
- ;; In particular, it would be nice for the
- ;; hook function to be able to adjust *GC-TRIGGER*
- ;; intelligently to e.g. 108% of total memory usage.
+ ;; FIXME: This hook should be called with the same
+ ;; kind of information as *GC-NOTIFY-AFTER*. In
+ ;; particular, it would be nice for the hook function
+ ;; to be able to adjust *GC-TRIGGER* intelligently to
+ ;; e.g. 108% of total memory usage.
(carefully-funcall hook))
(when *gc-notify-stream*
(/show0 "doing the *GC-NOTIFY-AFTER* thing")
(incf *gc-run-time* (- (get-internal-run-time)
start-time))))
;; FIXME: should probably return (VALUES), here and in RETURN-FROM
- (/show "returning from tail of SUB-GC")
+ (/show0 "returning from tail of SUB-GC")
nil)
;;; This routine is called by the allocation miscops to decide whether