emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
To: Suvayu Ali <fatkasuvayu+linux@gmail.com>
Cc: Emacs Org mode <emacs-orgmode@gnu.org>
Subject: Re: Possible cache problems
Date: Tue, 02 Jun 2015 22:26:54 +0200	[thread overview]
Message-ID: <87d21dsvox.fsf@nicolasgoaziou.fr> (raw)
In-Reply-To: <20150602170921.GF2027@chitra.no-ip.org> (Suvayu Ali's message of "Tue, 2 Jun 2015 19:09:21 +0200")

Hello,

Suvayu Ali <fatkasuvayu+linux@gmail.com> writes:

> I have been noticing a strange heisenbug.  From time to time, Org starts
> eating CPU for certain specific tasks: org-end-of-line, fill-paragraph,
> folding or unfolding trees, or adding/changing properties with
> org-set-property.  However these happen only after I have been using Org
> for a while.

This is typical for cache breakage.

> I think I also see similar CPU eating symptoms when I have buffers
> editing version controlled files.  I have auto-revert-mode enabled for
> files under version control, I think that is related.  I'm not entirely
> sure though, I don't know how to narrow it down either.
>
> I say it is cache related since all this magically goes away, once I go
> to the top of my current tree, and call org-element-cache-reset.
> However, once the symptoms start showing, it happens more frequently
> despite my cache resets.

Usually, a cache breakage is a specific action applied to some specific
document structure that induces an incorrect computation of the parts of
the cache to clear and to update.

If you encountered the problem, it means the problematic document
structure is already in the current buffer. So, the chances are high
that you will repeat the problematic editing action on it again, even
after resetting the cache. IOW, all the ingredients are there for the
problem to repeat again and again.

Finding the problematic action is not easy. I wrote a basic minor mode
(element-debug-mode) for that: after each change to the buffer, it
checks if the cache and pending updates match the parse tree. It sends
a message anytime they differ, which happens as soon as a problematic
action was triggered.

Obviously, it is unusable if the buffer is not small. You may want to
try it on small parts of your document, repeating your usual editing
actions.

--8<---------------cut here---------------start------------->8---
(defun element-check-cache (&rest ignore)
  (when (org-element--cache-active-p)
    (save-match-data
      (let ((cache (copy-tree org-element--cache t))
            (requests (copy-tree org-element--cache-sync-requests t))
            (buffer-contents (org-with-wide-buffer (buffer-string)))
            (translations (make-hash-table :test #'eq))
            (structures (make-hash-table :test #'eq))
            (keys (make-hash-table :test #'eq)))
        ;; Fix parents.
        (loop for key in (avl-tree-flatten org-element--cache)
              for value in (avl-tree-flatten cache)
              do (let ((struct (and (memq (org-element-type key)
                                          '(plain-list item))
                                    (gethash (org-element-property :structure key)
                                             structures 'missing))))
                   (progn
                     (puthash key value translations)
                     (let ((k (gethash key org-element--cache-sync-keys)))
                       (when k (puthash value k keys)))
                     (puthash
                      key
                      (org-element-put-property
                       value :parent
                       (gethash (org-element-property :parent key)
                                translations))
                      translations)
                     (when (eq struct 'missing)
                       (setq struct
                             (puthash (org-element-property :structure key)
                                      (org-element-property :structure value)
                                      structures)))
                     (when struct
                       (puthash
                        key
                        (org-element-put-property value :structure struct)
                        translations)))))
        ;; Fix requests.
        (loop for original in org-element--cache-sync-requests
              for copy in requests
              do (progn (aset copy 4 (gethash (aref original 4) translations))
                        (aset copy 5 (gethash (aref original 5) translations))))
        (with-temp-buffer
          (let ((org-element-use-cache nil)) (insert buffer-contents))
          (let ((org-inhibit-startup t)) (org-mode))
          (setq org-element--cache cache
                org-element--cache-sync-requests requests
                org-element--cache-sync-keys keys)
          (org-element--cache-sync (current-buffer) (point-max))
          (let ((seen '()))
            (avl-tree-mapc
             (lambda (element)
               (let ((beg (org-element-property :begin element))
                     (type (org-element-type element)))
                 (let ((real (let (org-element-use-cache)
                               (goto-char
                                (if (memq type '(item table-row)) (1+ beg)
                                  beg))
                               (org-element-at-point))))
                   (cond
                    ((member real seen)
                     (message
                      "======\nWARNING. Two entries for the same element\n\n %s"
                      element))
                    ((not (equal real element))
                     (message
                      "======\nWARNING. Corrupted element (%s) at %d\n\nReal: %s\n\nCached: %s\nLast request: %s"
                      (org-element-type element) beg real element (car requests)))
                    (t (push real seen))))))
             org-element--cache)))))))

(define-minor-mode element-debug-mode
  "Minor mode to debug Org Element cache."
  nil " OrgCacheD" nil
  (if ngz-debug-mode
      (progn (setq org-element-cache-sync-idle-time 3600)
             (add-hook 'after-change-functions 'element-check-cache t t))
    (setq org-element-cache-sync-idle-time 0.6)
    (remove-hook 'after-change-functions 'element-check-cache t)))
--8<---------------cut here---------------end--------------->8---


Regards,

-- 
Nicolas Goaziou

  reply	other threads:[~2015-06-02 20:25 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-02 17:09 Possible cache problems Suvayu Ali
2015-06-02 20:26 ` Nicolas Goaziou [this message]
2015-06-02 21:21   ` Suvayu Ali
2015-06-02 21:27     ` Nicolas Goaziou
2015-06-02 21:35       ` Suvayu Ali
2015-06-06 19:38       ` Suvayu Ali
2015-06-06 23:29         ` Nicolas Goaziou
2015-06-07  3:39           ` Suvayu Ali
2015-06-10  8:40           ` Suvayu Ali
2015-06-10 21:41             ` Rasmus
2015-06-11  7:00             ` Nicolas Goaziou
2015-06-11 15:06               ` Suvayu Ali
2015-06-14 12:58             ` Nicolas Goaziou
2015-06-15  1:21               ` Suvayu Ali

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87d21dsvox.fsf@nicolasgoaziou.fr \
    --to=mail@nicolasgoaziou.fr \
    --cc=emacs-orgmode@gnu.org \
    --cc=fatkasuvayu+linux@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).