From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Opportunistic garbage collection Date: Wed, 24 Apr 2019 16:54:20 -0400 Message-ID: Mime-Version: 1.0 Content-Type: text/plain Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="12420"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Apr 24 22:55:44 2019 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hJOvg-00037H-Mj for ged-emacs-devel@m.gmane.org; Wed, 24 Apr 2019 22:55:44 +0200 Original-Received: from localhost ([127.0.0.1]:47063 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hJOvf-0000cq-GZ for ged-emacs-devel@m.gmane.org; Wed, 24 Apr 2019 16:55:43 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:43998) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hJOuc-0000cd-2Y for emacs-devel@gnu.org; Wed, 24 Apr 2019 16:54:39 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hJOuN-000751-IN for emacs-devel@gnu.org; Wed, 24 Apr 2019 16:54:24 -0400 Original-Received: from pruche.dit.umontreal.ca ([132.204.246.22]:52351) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hJOuN-0006z3-Dh for emacs-devel@gnu.org; Wed, 24 Apr 2019 16:54:23 -0400 Original-Received: from pastel.home (lechon.iro.umontreal.ca [132.204.27.242]) by pruche.dit.umontreal.ca (8.14.7/8.14.1) with ESMTP id x3OKsKAF017764; Wed, 24 Apr 2019 16:54:21 -0400 Original-Received: by pastel.home (Postfix, from userid 20848) id C7A176AE07; Wed, 24 Apr 2019 16:54:20 -0400 (EDT) X-NAI-Spam-Flag: NO X-NAI-Spam-Threshold: 5 X-NAI-Spam-Score: 0.5 X-NAI-Spam-Rules: 5 Rules triggered WB_LK3_SLK=0.3, GEN_SPAM_FEATRE=0.1, TRK_NCM1=0.1, EDT_SA_DN_PASS=0, RV6532=0 X-NAI-Spam-Version: 2.3.0.9418 : core <6532> : inlines <7059> : streams <1819622> : uri <2836634> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 132.204.246.22 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:235883 Archived-At: I recently bumped into http://akrl.sdf.org/ where they mention a hack of running the GC from an idle timer, and I was wondering why that would be a good idea compared to the opportunistic GC we already do. So I went a look for what we do, and the only thing I found was /* If there is still no input available, ask for GC. */ if (!detect_input_pending_run_timers (0)) maybe_gc (); in src/keyboard.c which doesn't seem to be of any use since this maybe_gc will very rarely fire: the Elisp code we ran just before should have called `maybe_gc` already (probably many times, actually). So unless I missed the other place were we take advantage of idle time to force an "early" GC, I suggest we install a patch like the one below (which does more or less what I thought Emacs had been doing all along). WDYT? Stefan diff --git a/lisp/startup.el b/lisp/startup.el index a9b58c5e01..33fc901411 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -971,6 +971,13 @@ startup--load-user-init-file (when debug-on-error-should-be-set (setq debug-on-error debug-on-error-from-init-file)))) +(defcustom gc-cons-opportunistic-idle-time 5 + "Number of seconds before trying an opportunistic GC. +After this number of seconds of idle time, Emacs tries to collect +garbage more eagerly (i.e. with thresholds halved) in the hope +to avoid running the GC later during non-idle time." + :type 'integer) + (defun command-line () "A subroutine of `normal-top-level'. Amongst another things, it parses the command-line arguments." @@ -1368,6 +1375,16 @@ command-line (eq face-ignored-fonts old-face-ignored-fonts)) (clear-face-cache))) + ;; Start opportunistic GC (after loading the init file, so we obey + ;; its settings). This is desirable for two reason: + ;; - It reduces the number of times we have to GC in the middle of + ;; an operation. + ;; - It means we GC when the C stack is short, reducing the risk of false + ;; positives from the conservative stack scanning. + (when gc-cons-opportunistic-idle-time + (run-with-idle-timer gc-cons-opportunistic-idle-time t + #'garbage-collect-maybe 2)) + (setq after-init-time (current-time)) ;; Display any accumulated warnings after all functions in ;; `after-init-hook' like `desktop-read' have finalized possible diff --git a/src/alloc.c b/src/alloc.c index 402fada1ad..14d387861c 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -6016,6 +6016,28 @@ garbage_collect (void) garbage_collect_1 (&gcst); } +DEFUN ("garbage-collect-maybe", Fgarbage_collect_maybe, Sgarbage_collect_maybe, 1, 1, "", + doc: /* Call `garbage-collect' if enough allocation happened. +FACTOR determined what "enough" means here: +a FACTOR of N means to run the GC if more than 1/Nth of the allocations +needed to triger automatic allocation took place. */) + (Lisp_Object factor) +{ + CHECK_FIXNAT (factor); + EMACS_INT fact = XFIXNAT (factor); + byte_ct new_csgc = consing_since_gc * fact; + if (new_csgc / fact != consing_since_gc) + /* Overflow! */ + garbage_collect (); + else + { + consing_since_gc = new_csgc; + maybe_gc (); + consing_since_gc /= fact; + } + return Qnil; +} + DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "", doc: /* Reclaim storage for Lisp objects no longer needed. Garbage collection happens automatically if you cons more than @@ -7416,6 +7438,7 @@ than 2**N, where N is this variable's value. N should be nonnegative. */); defsubr (&Smake_finalizer); defsubr (&Spurecopy); defsubr (&Sgarbage_collect); + defsubr (&Sgarbage_collect_maybe); defsubr (&Smemory_info); defsubr (&Smemory_use_counts); defsubr (&Ssuspicious_object); diff --git a/src/keyboard.c b/src/keyboard.c index dff8f6b2fc..237ced19ca 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2728,7 +2728,7 @@ read_char (int commandflag, Lisp_Object map, /* If there is still no input available, ask for GC. */ if (!detect_input_pending_run_timers (0)) - maybe_gc (); + maybe_gc (); /* FIXME: Why? */ } /* Notify the caller if an autosave hook, or a timer, sentinel or