emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/org edddc7d 3/3: org-element-cache-map: Reduce memory a


From: ELPA Syncer
Subject: [elpa] externals/org edddc7d 3/3: org-element-cache-map: Reduce memory allocation and time re-search
Date: Fri, 10 Dec 2021 21:57:33 -0500 (EST)

branch: externals/org
commit edddc7d149b8668a830443b12db14075beb28607
Author: Ihor Radchenko <yantar92@gmail.com>
Commit: Ihor Radchenko <yantar92@gmail.com>

    org-element-cache-map: Reduce memory allocation and time re-search
    
    * lisp/org-element.el (org-element-cache-map): Move all possible
    let-bindings outside the loop to avoid remory re-allocation on every
    iteration.  Track statistics for `re-search-forward' calls.
---
 lisp/org-element.el | 165 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 91 insertions(+), 74 deletions(-)

diff --git a/lisp/org-element.el b/lisp/org-element.el
index 5c52318..26e7dec 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -7109,7 +7109,11 @@ the cache."
       (setq to-pos mk)))
   ;; Make sure that garbage collector does not stand on the way to
   ;; maximum performance.
-  (let ((gc-cons-threshold #x40000000))
+  (let ((gc-cons-threshold #x40000000)
+        ;; Bind variables used inside loop to avoid memory
+        ;; re-allocation on every iteration.
+        ;; See https://emacsconf.org/2021/talks/faster/
+        tmpnext-start tmpparent tmpelement)
     (save-excursion
       (save-restriction
         (unless narrow (widen))
@@ -7138,37 +7142,38 @@ the cache."
                        () `(setq continue-flag t
                                  node nil))
                       (element-match-at-point
-                       ;; Returning the first element to match around point.
-                       ;; For example, if point is inside headline and
-                       ;; granularity is restricted to headlines only, skip
-                       ;; over all the child elements inside the headline
-                       ;; and return the first parent headline.
-                       ;; When we are inside a cache gap, calling
-                       ;; `org-element-at-point' also fills the cache gap down 
to
-                       ;; point.
-                       () `(progn
-                             ;; Parsing is one of the performance
-                             ;; bottlenecks.  Make sure to optimise it as
-                             ;; much as possible.
-                             ;;
-                             ;; Avoid extra staff like timer cancels et al
-                             ;; and only call 
`org-element--cache-sync-requests' when
-                             ;; there are pending requests.
-                             (when org-element--cache-sync-requests
-                               (org-element--cache-sync (current-buffer)))
-                             ;; Call `org-element--parse-to' directly avoiding 
any
-                             ;; kind of `org-element-at-point' overheads.
-                             (if restrict-elements
-                                 ;; Search directly instead of calling
-                                 ;; `org-element-lineage' to avoid funcall 
overheads
-                                 ;; and making sure that we do not go all
-                                 ;; the way to `org-data' as 
`org-element-lineage'
-                                 ;; does.
-                                 (let ((el (org-element--parse-to (point))))
-                                   (while (and el (not (memq (org-element-type 
el) restrict-elements)))
-                                     (setq el (org-element-property :parent 
el)))
-                                   el)
-                               (org-element--parse-to (point)))))
+                        ;; Returning the first element to match around point.
+                        ;; For example, if point is inside headline and
+                        ;; granularity is restricted to headlines only, skip
+                        ;; over all the child elements inside the headline
+                        ;; and return the first parent headline.
+                        ;; When we are inside a cache gap, calling
+                        ;; `org-element-at-point' also fills the cache gap 
down to
+                        ;; point.
+                        () `(progn
+                              ;; Parsing is one of the performance
+                              ;; bottlenecks.  Make sure to optimise it as
+                              ;; much as possible.
+                              ;;
+                              ;; Avoid extra staff like timer cancels et al
+                              ;; and only call 
`org-element--cache-sync-requests' when
+                              ;; there are pending requests.
+                              (when org-element--cache-sync-requests
+                                (org-element--cache-sync (current-buffer)))
+                              ;; Call `org-element--parse-to' directly 
avoiding any
+                              ;; kind of `org-element-at-point' overheads.
+                              (if restrict-elements
+                                  ;; Search directly instead of calling
+                                  ;; `org-element-lineage' to avoid funcall 
overheads
+                                  ;; and making sure that we do not go all
+                                  ;; the way to `org-data' as 
`org-element-lineage'
+                                  ;; does.
+                                  (progn
+                                    (setq tmpelement (org-element--parse-to 
(point)))
+                                    (while (and tmpelement (not (memq 
(org-element-type tmpelement) restrict-elements)))
+                                      (setq tmpelement (org-element-property 
:parent tmpelement)))
+                                    tmpelement)
+                                (org-element--parse-to (point)))))
                       ;; Starting from (point), search RE and move START to
                       ;; the next valid element to be matched according to
                       ;; restriction.  Abort cache walk if no next element
@@ -7176,7 +7181,14 @@ the cache."
                       ;; point.
                       (move-start-to-next-match
                         (re) `(save-match-data
-                                (if (or (not ,re) (re-search-forward (or 
(car-safe ,re) ,re) nil 'move))
+                                (if (or (not ,re) (if 
org-element--cache-map-statistics
+                                                    (progn
+                                                      (setq before-time 
(float-time))
+                                                      (re-search-forward (or 
(car-safe ,re) ,re) nil 'move)
+                                                      (cl-incf re-search-time
+                                                               (- (float-time)
+                                                                  
before-time)))
+                                                  (re-search-forward (or 
(car-safe ,re) ,re) nil 'move)))
                                     (unless (or (< (point) (or start -1))
                                                 (and data
                                                      (< (point) 
(org-element-property :begin data))))
@@ -7193,26 +7205,27 @@ the cache."
                       ;; Find expected begin position of an element after
                       ;; DATA.
                       (next-element-start
-                        (data) `(let (next-start)
-                                  (if (memq granularity '(headline 
headline+inlinetask))
-                                      (setq next-start (or (when (memq 
(org-element-type data) '(headline org-data))
-                                                             
(org-element-property :contents-begin data))
-                                                           
(org-element-property :end data)))
-                                   (setq next-start (or (when (memq 
(org-element-type data) org-element-greater-elements)
-                                                           
(org-element-property :contents-begin data))
-                                                         (org-element-property 
:end data))))
-                                  ;; DATA end may be the last element inside
-                                  ;; i.e. source block.  Skip up to the end
-                                  ;; of parent in such case.
-                                  (let ((parent data))
-                                   (catch :exit
-                                      (when (eq next-start 
(org-element-property :contents-end parent))
-                                       (setq next-start (org-element-property 
:end parent)))
-                                     (while (setq parent (org-element-property 
:parent parent))
-                                       (if (eq next-start 
(org-element-property :contents-end parent))
-                                           (setq next-start 
(org-element-property :end parent))
-                                          (throw :exit t)))))
-                                  next-start))
+                        () `(progn
+                              (setq tmpnext-start nil)
+                              (if (memq granularity '(headline 
headline+inlinetask))
+                                  (setq tmpnext-start (or (when (memq 
(org-element-type data) '(headline org-data))
+                                                            
(org-element-property :contents-begin data))
+                                                          
(org-element-property :end data)))
+                               (setq tmpnext-start (or (when (memq 
(org-element-type data) org-element-greater-elements)
+                                                          
(org-element-property :contents-begin data))
+                                                        (org-element-property 
:end data))))
+                              ;; DATA end may be the last element inside
+                              ;; i.e. source block.  Skip up to the end
+                              ;; of parent in such case.
+                              (setq tmpparent data)
+                             (catch :exit
+                                (when (eq tmpnext-start (org-element-property 
:contents-end tmpparent))
+                                 (setq tmpnext-start (org-element-property 
:end tmpparent)))
+                               (while (setq tmpparent (org-element-property 
:parent tmpparent))
+                                 (if (eq tmpnext-start (org-element-property 
:contents-end tmpparent))
+                                     (setq tmpnext-start (org-element-property 
:end tmpparent))
+                                    (throw :exit t))))
+                              tmpnext-start))
                       ;; Check if cache does not have gaps.
                       (cache-gapless-p
                         () `(eq org-element--cache-change-tic
@@ -7327,8 +7340,13 @@ the cache."
                  (time (float-time))
                  (predicate-time 0)
                  (pre-process-time 0)
+                 (re-search-time 0)
                  (count-predicate-calls-match 0)
-                 (count-predicate-calls-fail 0))
+                 (count-predicate-calls-fail 0)
+                 ;; Bind variables used inside loop to avoid memory
+                 ;; re-allocation on every iteration.
+                 ;; See https://emacsconf.org/2021/talks/faster/
+                 cache-size before-time modified-tic)
             ;; Skip to first element within region.
             (goto-char (or start (point-min)))
             (move-start-to-next-match next-element-re)
@@ -7343,13 +7361,13 @@ the cache."
                           (and (eq granularity 'element)
                                (or next-re fail-re)))
                 (let ((org-element-cache-map--recurse t))
-                  (let ((before-time (float-time)))
-                    (org-element-cache-map
-                     #'ignore
-                     :granularity granularity)  
-                    (cl-incf pre-process-time
-                             (- (float-time)
-                                before-time)))
+                  (setq before-time (float-time))
+                  (org-element-cache-map
+                   #'ignore
+                   :granularity granularity)  
+                  (cl-incf pre-process-time
+                           (- (float-time)
+                              before-time))
                   ;; Re-assign the cache root after filling the cache
                   ;; gaps.
                   (setq node (cache-root)))
@@ -7390,8 +7408,9 @@ the cache."
                         ;; DATA is at START.  Match it.
                         ;; In the process, we may alter the buffer,
                         ;; so also keep track of the cache state.
-                        (let ((modified-tic org-element--cache-change-tic)
-                              (cache-size (cache-size)))
+                        (progn
+                          (setq modified-tic org-element--cache-change-tic)
+                          (setq cache-size (cache-size))
                           ;; When NEXT-RE/FAIL-RE is provided, skip to
                           ;; next regexp match after :begin of the current
                           ;; element.
@@ -7403,7 +7422,7 @@ the cache."
                                      (< (org-element-property :begin data) 
to-pos)) 
                             ;; Calculate where next possible element
                             ;; starts and update START if needed.
-                           (setq start (next-element-start data))
+                           (setq start (next-element-start))
                             (goto-char start)
                             ;; Move START further if possible.
                             (when (and next-element-re
@@ -7424,7 +7443,8 @@ the cache."
                               ;; 
                               ;; Call FUNC.  FUNC may move point.
                               (if org-element--cache-map-statistics
-                                  (let ((before-time (float-time)))
+                                  (progn
+                                    (setq before-time (float-time))
                                     (push (funcall func data) result)
                                     (cl-incf predicate-time
                                              (- (float-time)
@@ -7448,7 +7468,7 @@ the cache."
                             ;; advance but simply loop to the next cache
                             ;; element.
                             (when (and (cache-gapless-p)
-                                       (eq (next-element-start data)
+                                       (eq (next-element-start)
                                            start))
                               (setq start nil))
                             ;; Check if the buffer has been modified.
@@ -7469,8 +7489,9 @@ the cache."
                               ;; element past already processed
                               ;; place.
                               (when (<= start (org-element-property :begin 
data))
-                                (goto-char start)                              
   
-                                (goto-char (next-element-start 
(element-match-at-point)))
+                                (goto-char start)
+                                (setq data (element-match-at-point))
+                                (goto-char (next-element-start))
                                 (move-start-to-next-match next-element-re))
                               (org-element-at-point to-pos)
                               (cache-walk-restart))
@@ -7513,7 +7534,7 @@ the cache."
             (when (and org-element--cache-map-statistics
                        (or (not org-element--cache-map-statistics-threshold)
                            (> (- (float-time) time) 
org-element--cache-map-statistics-threshold)))
-              (message "Mapped over elements in %S. %d/%d predicate matches. 
Total time: %f sec. Pre-process time: %f sec. Time running predicates: %f sec 
(%f sec avg)
+              (message "Mapped over elements in %S. %d/%d predicate matches. 
Total time: %f sec. Pre-process time: %f sec. Predicate time: %f sec. Re-search 
time: %f sec.
        Calling parameters: :granularity %S :restrict-elements %S :next-re %S 
:fail-re %S :from-pos %S :to-pos %S :limit-count %S :after-element %S"
                        (current-buffer)
                        count-predicate-calls-match
@@ -7522,11 +7543,7 @@ the cache."
                        (- (float-time) time)
                        pre-process-time
                        predicate-time
-                       (if (zerop (+ count-predicate-calls-match
-                                     count-predicate-calls-fail))
-                           0
-                         (/ predicate-time (+ count-predicate-calls-match
-                                              count-predicate-calls-fail)))
+                       re-search-time
                        granularity restrict-elements next-re fail-re from-pos 
to-pos limit-count after-element))
             ;; Return result.
             (nreverse result)))))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]