Subject: bug#51692: 29.0.50; High CPU in c++ mode. Type finder?

From: David Koppelman <[email-masked]>
Date: Thu, 11 Nov 2021 14:13:48 -0600

I applied the patch and it fixes the problem! I applied the patch to the
checkout on which I reported the problem (I didn't try to update). Also,
I tested both on the reduced testcase and the original file, on both
there was no suspiciously high CPU usage.

Thank you!

Alan Mackenzie <[email-masked]> writes:

> Hello, David, Zhiwei, Yuri, and Lars.
>
> On Mon, Nov 08, 2021 at 13:00:06 -0600, David Koppelman wrote:
>
>> Load the attached file into a buffer:
>
>> ./src/emacs --no-init d.cc
>
>> Emacs will use 100% CPU on a core while the buffer is visible. CPU usage
>> goes to normal when switching to another buffer. The attached file is a
>> reduced version of a much larger file. (The larger file experiences the
>> high CPU usage only while a certain portion of the code is visible.)
>
> Yes, there is a bug here.  CC Mode is expected to use a high amount of
> CPU time (but not 100%) for a few seconds after starting C (etc.) Mode,
> or for a few minutes after starting Emacs when there's a desktop with a
> lot of CC Mode files in it.
>
> However, with C++ files (and likely Java files, too), a problem with
> templates caused this 100% usage.
>
> I'm hoping the following patch will fix it.  Could you (plural) please
> apply this patch to the Emacs master branch, byte compile the two
> amended files, then load the fixed CC Mode into your Emacs.  Then please
> try it out with your real files.  (If anybody wants any help with the
> patching or byte compiling, feel free to send me personal email.)
>
> Then please report back to the bug list confirming that the bug is
> fixed, or telling me what's still not right.
>
> Thank you!
>
>
>
> diff -r 05fd00cb5937 cc-engine.el
> --- a/cc-engine.el	Sat Oct 30 15:57:26 2021 +0000
> +++ b/cc-engine.el	Thu Nov 11 18:47:47 2021 +0000
> @@ -6838,6 +6838,13 @@
>  (defvar c-found-types nil)
>  (make-variable-buffer-local 'c-found-types)
>  
> +;; Dynamically bound variable that instructs `c-forward-type' to
> +;; record the ranges of types that only are found.  Behaves otherwise
> +;; like `c-record-type-identifiers'.  Also when this variable is non-nil,
> +;; `c-fontify-new-found-type' doesn't get called (yet) for the purported
> +;; type.
> +(defvar c-record-found-types nil)
> +
>  (defsubst c-clear-found-types ()
>    ;; Clears `c-found-types'.
>    (setq c-found-types
> @@ -6851,7 +6858,10 @@
>    (let ((type (c-syntactic-content from to c-recognize-<>-arglists)))
>      (unless (gethash type c-found-types)
>        (puthash type t c-found-types)
> -      (when (and (eq (string-match c-symbol-key type) 0)
> +      (when (and (not c-record-found-types) ; Only call `c-fontify-new-fount-type'
> +					; when we haven't "bound" c-found-types
> +					; to itself in c-forward-<>-arglist.
> +		 (eq (string-match c-symbol-key type) 0)
>  		 (eq (match-end 0) (length type)))
>  	(c-fontify-new-found-type type)))))
>  
> @@ -8248,11 +8258,6 @@
>  	   (setq c-record-ref-identifiers
>  		 (cons range c-record-ref-identifiers))))))
>  
> -;; Dynamically bound variable that instructs `c-forward-type' to
> -;; record the ranges of types that only are found.  Behaves otherwise
> -;; like `c-record-type-identifiers'.
> -(defvar c-record-found-types nil)
> -
>  (defmacro c-forward-keyword-prefixed-id (type)
>    ;; Used internally in `c-forward-keyword-clause' to move forward
>    ;; over a type (if TYPE is 'type) or a name (otherwise) which
> @@ -8480,6 +8485,11 @@
>  		(c-forward-<>-arglist-recur all-types)))
>  	(progn
>  	  (when (consp c-record-found-types)
> +	    (let ((cur c-record-found-types))
> +	      (while (consp (car-safe cur))
> +		(c-fontify-new-found-type
> +		 (buffer-substring-no-properties (caar cur) (cdar cur)))
> +		(setq cur (cdr cur))))
>  	    (setq c-record-type-identifiers
>  		  ;; `nconc' doesn't mind that the tail of
>  		  ;; `c-record-found-types' is t.
> @@ -9203,6 +9213,12 @@
>  
>  		(when (and (eq res t)
>  			   (consp c-record-found-types))
> +		  ;; Cause the confirmed types to get fontified.
> +		  (let ((cur c-record-found-types))
> +		    (while (consp (car-safe cur))
> +		      (c-fontify-new-found-type
> +		       (buffer-substring-no-properties (caar cur) (cdar cur)))
> +		      (setq cur (cdr cur))))
>  		  ;; Merge in the ranges of any types found by the second
>  		  ;; `c-forward-type'.
>  		  (setq c-record-type-identifiers
> diff -r 05fd00cb5937 cc-fonts.el
> --- a/cc-fonts.el	Sat Oct 30 15:57:26 2021 +0000
> +++ b/cc-fonts.el	Thu Nov 11 18:47:47 2021 +0000
> @@ -105,6 +105,7 @@
>  (cc-bytecomp-defun c-font-lock-objc-method)
>  (cc-bytecomp-defun c-font-lock-invalid-string)
>  (cc-bytecomp-defun c-before-context-fl-expand-region)
> +(cc-bytecomp-defun c-font-lock-fontify-region)
>  
>  
>  ;; Note that font-lock in XEmacs doesn't expand face names as
> @@ -2431,6 +2432,7 @@
>  (defun c-force-redisplay (start end)
>    ;; Force redisplay immediately.  This assumes `font-lock-support-mode' is
>    ;; 'jit-lock-mode.  Set the variable `c-re-redisplay-timer' to nil.
> +  (save-excursion (c-font-lock-fontify-region start end))
>    (jit-lock-force-redisplay (copy-marker start) (copy-marker end))
>    (setq c-re-redisplay-timer nil))
>  
> @@ -2458,7 +2460,6 @@
>  	    (dolist (win-boundary window-boundaries)
>  	      (when (and (< (match-beginning 0) (cdr win-boundary))
>  			 (> (match-end 0) (car win-boundary))
> -			 (c-get-char-property (match-beginning 0) 'fontified)
>  			 (not c-re-redisplay-timer))
>  		(setq c-re-redisplay-timer
>  		      (run-with-timer 0 nil #'c-force-redisplay