all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Aleksey Cherepanov <aleksey.4erepanov@gmail.com>
To: Agustin Martin <agustin.martin@hispalinux.es>
Cc: 16800@debbugs.gnu.org
Subject: bug#16800: 24.3; flyspell works slow on very short words at the end of big file
Date: Mon, 24 Feb 2014 20:03:17 +0400	[thread overview]
Message-ID: <20140224160317.GA2475@openwall.com> (raw)
In-Reply-To: <20140223230251.GA30257@openwall.com>

[-- Attachment #1: Type: text/plain, Size: 3297 bytes --]

I played with different (maybe wrong) implementations of
flyspell-word-search-backward and measured time against t.txt
(produced by the one-liner). All implementations are attached.

perl -e 'print(((join " ", ("met and") x 10) . "\n") x 30000)' > t.txt

my-test-agustin                            - Implementation from Agustin Martin with regexp-quote
my-test-concat-up                          - and concat moved upper
my-test-concat-up-goto                     - and goto-char moved into setq
my-test-concat-up-goto-notcap              - and ?: added to the first group
my-test-concat-up-goto-notcap-bob          - and \b replaced by \`
my-test-concat-up-goto-notcap-bob-bobp     - and goto-char replaced with conditional forward-char (on bobp)
my-test-concat-up-goto-notcap-nobob-bobp   - and the first group is removed, this case is handled separately,
my-test-concat-up-goto-notcap-nobob-nobobp - and bobp check is replaced by progn due to separate handling
my-test-goto-notcap-nobob-nobobp           - and concat moved down (back),
my-test-concat-up-goto-notcap-nobob-bobp-fixed - fixed for correct handling of beginning of buffer.

# |String| Time           |Result| Function name
1  nd  (0 0 192227 640000)  nil   my-test-agustin
2  nd  (0 0 192569 63000)   nil   my-test-concat-up
3  nd  (0 0 193895 468000)  nil   my-test-concat-up-goto
4  nd  (0 0 194372 743000)  nil   my-test-concat-up-goto-notcap
5  nd  (0 0 151535 868000)  nil   my-test-concat-up-goto-notcap-bob
6  nd  (0 0 131831 49000)   nil   my-test-concat-up-goto-notcap-bob-bobp
7  nd  (0 0 92012 191000)   nil   my-test-concat-up-goto-notcap-nobob-bobp
8  nd  (0 0 93928 281000)   nil   my-test-concat-up-goto-notcap-nobob-nobobp
9  nd  (0 0 93796 52000)    nil   my-test-goto-notcap-nobob-nobobp
10 nd  (0 0 94061 645000)   nil   my-test-concat-up-goto-notcap-nobob-bobp-fixed

It is from Messages of (my-try "nd") in t.txt.

The last 4 functions are quite close and often mixes differently due
to fluctuations. Really they could not be measured against this file
because re-search-forward always should return nil, I think.

Functions 7, 8, 9 are not correct: they find a word if we search a
word at the beginning of buffer staying at the middle of it. Function
10 has logic to handle this case.

Other corner cases should be thought and tried too. The times could be
different for other files and other words.

On Mon, Feb 24, 2014 at 03:02:51AM +0400, Aleksey Cherepanov wrote:
> I've performed some tests against my .org file (not in emacs -Q):

> On Sun, Feb 23, 2014 at 11:56:59PM +0400, Aleksey Cherepanov wrote:
> > Maybe it would be faster to not capture word but capture one char or
> > void but I doubt the difference would be noticable.
> 
> 307899: (0 3 174172 939000) :: \(?:[^[:alpha:]]\|\`\)\([[:alpha:]]+\)
> 307899: (0 3 250515 907000) :: \([^[:alpha:]]\|\`\)\(?:[[:alpha:]]+\)
> 307899: (0 3 218270 136000) :: \([^[:alpha:]]\|\`\)[[:alpha:]]+
> Unexpectedly capturing of word works a bit faster. Maybe it is not a
> word but the second group and it would work differently for search
> forward. Or alpha+ instead of fixed word caused it. Anyway the
> difference is very small.

We could avoid capturing at all. And it works faster as shown by 4
last functions.

Thanks!

-- 
Regards,
Aleksey Cherepanov

[-- Attachment #2: t.el --]
[-- Type: text/plain, Size: 11242 bytes --]


;; Implementation from Agustin Martin with additional regexp-quote
(defun my-test-agustin (word bound &optional ignore-case)
  (save-excursion
    (let ((r '())
	  (inhibit-point-motion-hooks t)
          (flyspell-not-casechars (flyspell-get-not-casechars))
	  p)
      (while
          (and (not r)
               (setq p
                     (re-search-backward
                      (concat
                       "\\(" flyspell-not-casechars "\\|\\b\\)"
                       "\\(" (regexp-quote word) "\\)"
                       flyspell-not-casechars
                       )
                      bound t)))
        (goto-char (match-beginning 2))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      r)))

(defun my-test-concat-up (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     "\\(" flyspell-not-casechars "\\|\\b\\)"
                     "\\(" (regexp-quote word) "\\)"
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (re-search-backward word-re bound t)))
        (goto-char (match-beginning 2))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      r)))

(defun my-test-concat-up-goto (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     "\\(" flyspell-not-casechars "\\|\\b\\)"
                     "\\(" (regexp-quote word) "\\)"
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (goto-char (match-beginning 2)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      r)))

(defun my-test-concat-up-goto-notcap (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     "\\(?:" flyspell-not-casechars "\\|\\b\\)"
                     "\\(" (regexp-quote word) "\\)"
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (goto-char (match-beginning 2)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      r)))

(defun my-test-concat-up-goto-notcap-bob (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     "\\(?:" flyspell-not-casechars "\\|\\`\\)"
                     "\\(" (regexp-quote word) "\\)"
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (goto-char (match-beginning 2)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      r)))

(defun my-test-concat-up-goto-notcap-bob-bobp (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     "\\(?:" flyspell-not-casechars "\\|\\`\\)"
                     (regexp-quote word)
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (unless (bobp)
                        (forward-char)
                        (point)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      r)))

;; Wrong
(defun my-test-concat-up-goto-notcap-nobob-bobp (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     flyspell-not-casechars
                     (regexp-quote word)
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (unless (bobp)
                        (forward-char)
                        (point)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      (unless r
        (setq p (goto-char (point-min)))
        (let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p))))
      r)))

;; Wrong
(defun my-test-concat-up-goto-notcap-nobob-nobobp (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     flyspell-not-casechars
                     (regexp-quote word)
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (progn
                        (forward-char)
                        (point)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      (unless r
        (setq p (goto-char (point-min)))
        (let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p))))
      r)))

;; Wrong
(defun my-test-goto-notcap-nobob-nobobp (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward (concat
                                           flyspell-not-casechars
                                           (regexp-quote word)
                                           flyspell-not-casechars)
                                          bound
                                          t)
                      (progn
                        (forward-char)
                        (point)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      (unless r
        (setq p (goto-char (point-min)))
        (let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p))))
      r)))

(defun my-test-concat-up-goto-notcap-nobob-bobp-fixed (word bound &optional ignore-case)
  (save-excursion
    (let* ((r '())
           (inhibit-point-motion-hooks t)
           (flyspell-not-casechars (flyspell-get-not-casechars))
           (word-re (concat
                     flyspell-not-casechars
                     (regexp-quote word)
                     flyspell-not-casechars))
           p)
      (while
          (and (not r)
               (setq p
                     (and
                      (re-search-backward word-re bound t)
                      (unless (bobp)
                        (forward-char)
                        (point)))))
	(let ((lw (flyspell-get-word)))
	  (if (and (consp lw)
		   (if ignore-case
		       (string-equal (downcase (car lw)) (downcase word))
		     (string-equal (car lw) word)))
	      (setq r p)
	    (goto-char p))))
      (unless r
        (let ((pos (point)))
          (setq p (goto-char (point-min)))
          (and (search-forward word (length word) t)
               (let ((lw (flyspell-get-word)))
                 (if (and (consp lw)
                          (if ignore-case
                              (string-equal (downcase (car lw)) (downcase word))
                            (string-equal (car lw) word)))
                     (setq r p))))))
      r)))

(defun my-try (word)
  (message "%s"
           (mapconcat (lambda (func)
                        (end-of-buffer)
                        (let* ((time (current-time))
                               (res (apply func '("nd" nil))))
                          (format ":>: %s %S =%S %S"
                                  word
                                  (subtract-time (current-time) time)
                                  res
                                  func)))
                      (let ((lst '(my-test-agustin
                                   my-test-concat-up
                                   my-test-concat-up-goto
                                   my-test-concat-up-goto-notcap
                                   my-test-concat-up-goto-notcap-bob
                                   my-test-concat-up-goto-notcap-bob-bobp
                                   my-test-concat-up-goto-notcap-nobob-bobp
                                   my-test-concat-up-goto-notcap-nobob-nobobp
                                   my-test-goto-notcap-nobob-nobobp
                                   my-test-concat-up-goto-notcap-nobob-bobp-fixed)))
                        (concatenate 'list lst lst))
                      "\n")))

  reply	other threads:[~2014-02-24 16:03 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-02-18 20:56 bug#16800: 24.3; flyspell works slow on very short words at the end of big file Aleksey Cherepanov
2014-02-21 10:15 ` Eli Zaretskii
2014-02-21 14:38   ` Agustin Martin
2014-02-21 15:12     ` Eli Zaretskii
2014-02-21 15:21       ` Eli Zaretskii
2014-02-22 12:44       ` Aleksey Cherepanov
2014-02-22 13:10         ` Eli Zaretskii
2014-02-22 16:02           ` Aleksey Cherepanov
2014-02-22 16:41             ` Eli Zaretskii
2014-02-22 18:55               ` Aleksey Cherepanov
2014-02-22 20:16                 ` Aleksey Cherepanov
2014-02-22 21:03                 ` Eli Zaretskii
2014-02-23  1:26                   ` Agustin Martin
2014-02-23 18:36                     ` Eli Zaretskii
2014-02-23 19:56                     ` Aleksey Cherepanov
2014-02-23 23:02                       ` Aleksey Cherepanov
2014-02-24 16:03                         ` Aleksey Cherepanov [this message]
2014-02-26 20:32                           ` Agustin Martin
2014-02-28 11:45                             ` Agustin Martin
2014-02-28 11:51                               ` Eli Zaretskii
2014-03-01 21:44                                 ` Aleksey Cherepanov
2014-03-02  3:56                                   ` Eli Zaretskii
2014-03-09 17:36                                     ` Agustin Martin
2014-03-09 18:02                                       ` Aleksey Cherepanov
2014-03-09 18:24                                         ` Eli Zaretskii
2014-02-28 23:11                               ` Aleksey Cherepanov
2014-03-01 10:33                                 ` Aleksey Cherepanov
2014-03-01 15:50                                   ` Aleksey Cherepanov
2014-03-01 21:39                                 ` Aleksey Cherepanov
2014-03-09 17:25                                 ` Agustin Martin
2015-03-06 21:46                                   ` Agustin Martin
2015-03-07  8:09                                     ` Eli Zaretskii
2014-02-23 20:39                     ` Aleksey Cherepanov

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

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

  git send-email \
    --in-reply-to=20140224160317.GA2475@openwall.com \
    --to=aleksey.4erepanov@gmail.com \
    --cc=16800@debbugs.gnu.org \
    --cc=agustin.martin@hispalinux.es \
    /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 external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.