GNU bug report logs -
#7089
23.2; slow ansi-color-apply
Previous Next
Reported by: Leo <sdl.web <at> gmail.com>
Date: Thu, 23 Sep 2010 09:14:02 UTC
Severity: normal
Found in version 23.2
Done: Leo <sdl.web <at> gmail.com>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 7089 in the body.
You can then email your comments to 7089 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org
:
bug#7089
; Package
emacs
.
(Thu, 23 Sep 2010 09:14:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Leo <sdl.web <at> gmail.com>
:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org
.
(Thu, 23 Sep 2010 09:14:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
I have found ansi-color-apply very expensive and slow.
To test this, do the following
(remove-hook 'eshell-output-filter-functions 'eshell-handle-ansi-color)
(add-hook 'eshell-preoutput-filter-functions 'ansi-color-apply)
and do something in eshell that can output a large coloured text such
as:
cd /usr/include; ack time
where ack is a single file perl script from http://betterthangrep.com/.
The CPU usage should shoot up to very high.
The following version (after brief testing) seems to be noticeably
faster.
(defun ansi-color-apply* (string)
"A more efficient implementation of `ansi-color-apply' (which see)."
(let ((face (car ansi-color-context))
start end fragment escape-sequence)
;; If context was saved and is a string, prepend it.
(if (cadr ansi-color-context)
(setq string (concat (cadr ansi-color-context) string)
ansi-color-context nil))
(with-temp-buffer
(insert string)
(setq start (point-min-marker))
(goto-char start)
(while (re-search-forward ansi-color-drop-regexp nil t)
(replace-match ""))
(goto-char start)
;; Find the next escape sequence.
(while (re-search-forward ansi-color-regexp nil t)
(setq end (match-beginning 0))
(when face
(put-text-property start end 'ansi-color t)
(put-text-property start end 'face face))
(setq start (copy-marker (match-end 0)))
(setq escape-sequence (match-string 1))
(replace-match "")
(setq face (ansi-color-apply-sequence escape-sequence face)))
;; search for the possible start of a new escape sequence
(if (re-search-forward "\033" nil t)
(setq end (match-beginning 0)
fragment (buffer-substring end (point-max)))
(setq end (point-max)))
;; if the rest of the string should have a face, put it there
(when face
(put-text-property start end 'ansi-color t)
(put-text-property start end 'face face))
;; save context
(if (or face fragment)
(setq ansi-color-context (list face fragment))
(setq ansi-color-context nil))
(buffer-string))))
Leo
Information forwarded
to
owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org
:
bug#7089
; Package
emacs
.
(Thu, 23 Sep 2010 10:52:01 GMT)
Full text and
rfc822 format available.
Message #8 received at submit <at> debbugs.gnu.org (full text, mbox):
The following version fixed some glitches in setting ansi-color-context.
Also I have received an email from Alex that welcomes the improvement.
Let me know if I should send a patch in.
(defun ansi-color-apply* (string)
"A more efficient implementation of `ansi-color-apply' (which see)."
(let ((face (car ansi-color-context))
start end fragment escape-sequence)
;; If context was saved and is a string, prepend it.
(if (cadr ansi-color-context)
(setq string (concat (cadr ansi-color-context) string)
ansi-color-context nil))
(prog1
(with-temp-buffer
(insert string)
(setq start (point-min-marker))
(goto-char start)
(while (re-search-forward ansi-color-drop-regexp nil t)
(replace-match ""))
(goto-char start)
;; Find the next escape sequence.
(while (re-search-forward ansi-color-regexp nil t)
(setq end (match-beginning 0))
(when face
(put-text-property start end 'ansi-color t)
(put-text-property start end 'face face))
(setq start (copy-marker (match-end 0)))
(setq escape-sequence (match-string 1))
(replace-match "")
(setq face (ansi-color-apply-sequence escape-sequence face)))
;; search for the possible start of a new escape sequence
(if (re-search-forward "\033" nil t)
(setq fragment
(delete-and-extract-region (match-beginning 0)
(point-max))))
;; if the rest of the string should have a face, put it there
(when face
(put-text-property start (point-max) 'ansi-color t)
(put-text-property start (point-max) 'face face))
;; return the string
(buffer-string))
;; save context; NB: ansi-color-context is buffer-local so set it after
;; return to the original buffer
(if (or face fragment)
(setq ansi-color-context (list face fragment))
(setq ansi-color-context nil)))))
Leo
Information forwarded
to
owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org
:
bug#7089
; Package
emacs
.
(Thu, 28 Oct 2010 02:35:01 GMT)
Full text and
rfc822 format available.
Message #11 received at 7089 <at> debbugs.gnu.org (full text, mbox):
> The following version fixed some glitches in setting ansi-color-context.
> Also I have received an email from Alex that welcomes the improvement.
> Let me know if I should send a patch in.
Yes, a patch would be nice. Also a ChangeLog explaining the change
(which should hopefully explain why the new code is faster) would
be welcome.
Stefan
Information forwarded
to
owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org
:
bug#7089
; Package
emacs
.
(Thu, 28 Oct 2010 04:00:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 7089 <at> debbugs.gnu.org (full text, mbox):
On 2010-10-28 10:38 +0800, Stefan Monnier wrote:
>> The following version fixed some glitches in setting ansi-color-context.
>> Also I have received an email from Alex that welcomes the improvement.
>> Let me know if I should send a patch in.
>
> Yes, a patch would be nice. Also a ChangeLog explaining the change
> (which should hopefully explain why the new code is faster) would
> be welcome.
>
>
> Stefan
Attached to the end of this message. I basically rewrite
ansi-color-apply using re-search-forward (as in
ansi-color-apply-on-region) which seems to be an order more efficient
than string-match.
I have been using the new version in eshell and it is almost as
efficient as ansi-color-apply-on-region. It is very painful to use the
original ansi-color-apply.
Do you know for sure string-match is slower (more CPU intensive) than
re-search-forward?
Thanks.
Leo
--------------------------------
From 724a620dd2d5301c32ecf4fbe6ce539db0c9bc8d Mon Sep 17 00:00:00 2001
Date: Thu, 28 Oct 2010 11:48:13 +0800
Subject: [PATCH] Rewrite ansi-color-apply using re-search-forward
to improve efficiency. `string-match' uses a lot of CPU.
---
lisp/ChangeLog | 5 ++++
lisp/ansi-color.el | 66 ++++++++++++++++++++++++++-------------------------
2 files changed, 39 insertions(+), 32 deletions(-)
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 146c6c9..7088f28 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,8 @@
+2010-10-28 Leo <sdl.web <at> gmail.com>
+
+ * ansi-color.el (ansi-color-apply): Rewrite using
+ re-search-forward for speed.
+
2010-10-03 Chong Yidong <cyd <at> stupidchicken.com>
* minibuffer.el (completion--some, completion--do-completion)
diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el
index 00162c9..6ef55e1 100644
--- a/lisp/ansi-color.el
+++ b/lisp/ansi-color.el
@@ -314,43 +314,45 @@ This function can be added to `comint-preoutput-filter-functions'.
You cannot insert the strings returned into buffers using font-lock.
See `ansi-color-unfontify-region' for a way around this."
(let ((face (car ansi-color-context))
- (start 0) end escape-sequence result
- colorized-substring)
+ start end fragment escape-sequence)
;; If context was saved and is a string, prepend it.
(if (cadr ansi-color-context)
(setq string (concat (cadr ansi-color-context) string)
ansi-color-context nil))
- ;; Find the next escape sequence.
- (while (setq end (string-match ansi-color-regexp string start))
- (setq escape-sequence (match-string 1 string))
- ;; Colorize the old block from start to end using old face.
- (when face
- (put-text-property start end 'ansi-color t string)
- (put-text-property start end 'face face string))
- (setq colorized-substring (substring string start end)
- start (match-end 0))
- ;; Eliminate unrecognized ANSI sequences.
- (while (string-match ansi-color-drop-regexp colorized-substring)
- (setq colorized-substring
- (replace-match "" nil nil colorized-substring)))
- (push colorized-substring result)
- ;; Create new face, by applying escape sequence parameters.
- (setq face (ansi-color-apply-sequence escape-sequence face)))
- ;; if the rest of the string should have a face, put it there
- (when face
- (put-text-property start (length string) 'ansi-color t string)
- (put-text-property start (length string) 'face face string))
- ;; save context, add the remainder of the string to the result
- (let (fragment)
- (if (string-match "\033" string start)
- (let ((pos (match-beginning 0)))
- (setq fragment (substring string pos))
- (push (substring string start pos) result))
- (push (substring string start) result))
+ (prog1
+ (with-temp-buffer
+ (insert string)
+ (setq start (point-min-marker))
+ (goto-char start)
+ (while (re-search-forward ansi-color-drop-regexp nil t)
+ (replace-match ""))
+ (goto-char start)
+ ;; Find the next escape sequence.
+ (while (re-search-forward ansi-color-regexp nil t)
+ (setq end (match-beginning 0))
+ (when face
+ (put-text-property start end 'ansi-color t)
+ (put-text-property start end 'face face))
+ (setq start (copy-marker (match-end 0)))
+ (setq escape-sequence (match-string 1))
+ (replace-match "")
+ (setq face (ansi-color-apply-sequence escape-sequence face)))
+ ;; Search for the possible start of a new escape sequence
+ (if (re-search-forward "\033" nil t)
+ (setq fragment
+ (delete-and-extract-region (match-beginning 0)
+ (point-max))))
+ ;; If the rest of the string should have a face, put it there
+ (when face
+ (put-text-property start (point-max) 'ansi-color t)
+ (put-text-property start (point-max) 'face face))
+ ;; Return the string
+ (buffer-string))
+ ;; Save context; NB: ansi-color-context is buffer-local so set it after
+ ;; exit the temp buffer.
(if (or face fragment)
- (setq ansi-color-context (list face fragment))
- (setq ansi-color-context nil)))
- (apply 'concat (nreverse result))))
+ (setq ansi-color-context (list face fragment))
+ (setq ansi-color-context nil)))))
;; Working with regions
--
1.7.3
Information forwarded
to
owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org
:
bug#7089
; Package
emacs
.
(Sun, 31 Oct 2010 19:07:01 GMT)
Full text and
rfc822 format available.
Message #17 received at 7089 <at> debbugs.gnu.org (full text, mbox):
>>> The following version fixed some glitches in setting ansi-color-context.
>>> Also I have received an email from Alex that welcomes the improvement.
>>> Let me know if I should send a patch in.
>> Yes, a patch would be nice. Also a ChangeLog explaining the change
>> (which should hopefully explain why the new code is faster) would
>> be welcome.
> Attached to the end of this message. I basically rewrite
> ansi-color-apply using re-search-forward (as in
> ansi-color-apply-on-region) which seems to be an order more efficient
> than string-match.
> I have been using the new version in eshell and it is almost as
> efficient as ansi-color-apply-on-region. It is very painful to use the
> original ansi-color-apply.
Any reason why your new code does something similar to
ansi-color-apply-on-region rather than calling
ansi-color-apply-on-region?
> Do you know for sure string-match is slower (more CPU intensive) than
> re-search-forward?
They should be largely equivalent. The difference between the two codes
might be due to replace-match and substring. I.e. the original
ansi-color-apply should be at least as efficient as your code (if not
more) in the case where there are no SGR escape sequences.
Stefan
Information forwarded
to
owner <at> debbugs.gnu.org, bug-gnu-emacs <at> gnu.org
:
bug#7089
; Package
emacs
.
(Mon, 01 Nov 2010 16:19:02 GMT)
Full text and
rfc822 format available.
Message #20 received at 7089 <at> debbugs.gnu.org (full text, mbox):
On 2010-11-01 03:10 +0800, Stefan Monnier wrote:
>>>> The following version fixed some glitches in setting ansi-color-context.
>>>> Also I have received an email from Alex that welcomes the improvement.
>>>> Let me know if I should send a patch in.
>>> Yes, a patch would be nice. Also a ChangeLog explaining the change
>>> (which should hopefully explain why the new code is faster) would
>>> be welcome.
>
>> Attached to the end of this message. I basically rewrite
>> ansi-color-apply using re-search-forward (as in
>> ansi-color-apply-on-region) which seems to be an order more efficient
>> than string-match.
>
>> I have been using the new version in eshell and it is almost as
>> efficient as ansi-color-apply-on-region. It is very painful to use the
>> original ansi-color-apply.
>
> Any reason why your new code does something similar to
> ansi-color-apply-on-region rather than calling
> ansi-color-apply-on-region?
`ansi-color-apply-on-region' uses overlays while `ansi-color-apply' uses
text properties.
>> Do you know for sure string-match is slower (more CPU intensive) than
>> re-search-forward?
>
> They should be largely equivalent. The difference between the two
> codes might be due to replace-match and substring. I.e. the original
> ansi-color-apply should be at least as efficient as your code (if not
> more) in the case where there are no SGR escape sequences.
>
>
> Stefan
Thanks for that info.
Leo
Reply sent
to
Leo <sdl.web <at> gmail.com>
:
You have taken responsibility.
(Thu, 25 Nov 2010 14:26:02 GMT)
Full text and
rfc822 format available.
Notification sent
to
Leo <sdl.web <at> gmail.com>
:
bug acknowledged by developer.
(Thu, 25 Nov 2010 14:26:03 GMT)
Full text and
rfc822 format available.
Message #25 received at 7089-done <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
On 2010-10-31 19:10 +0000, Stefan Monnier wrote:
>> Do you know for sure string-match is slower (more CPU intensive) than
>> re-search-forward?
>
> They should be largely equivalent. The difference between the two codes
> might be due to replace-match and substring. I.e. the original
> ansi-color-apply should be at least as efficient as your code (if not
> more) in the case where there are no SGR escape sequences.
>
>
> Stefan
I was setting out to profile the two versions of the function and
unfortunately I was not able to see the CPU shootup mentioned in the
first message. My result shows my version of ansi-color-apply is almost
twice as slow as the original one. (The code and data used for profiling
are attached.)
So please ignore this bug report.
Leo
[ansi-color-test.el (application/emacs-lisp, attachment)]
[ansi-test.txt (text/plain, attachment)]
Message #26 received at 7089-done <at> debbugs.gnu.org (full text, mbox):
>>> Do you know for sure string-match is slower (more CPU intensive) than
>>> re-search-forward?
>> They should be largely equivalent. The difference between the two codes
>> might be due to replace-match and substring. I.e. the original
>> ansi-color-apply should be at least as efficient as your code (if not
>> more) in the case where there are no SGR escape sequences.
> I was setting out to profile the two versions of the function and
> unfortunately I was not able to see the CPU shootup mentioned in the
> first message. My result shows my version of ansi-color-apply is almost
> twice as slow as the original one. (The code and data used for profiling
> are attached.)
OK, thanks. As mentioned, it might depend on the density of SGR escape
sequences (and on the size of the text chunks processed, which can
depend on the machine load).
Stefan
Message #27 received at 7089-done <at> debbugs.gnu.org (full text, mbox):
On 2010-11-25 16:31 +0000, Stefan Monnier wrote:
>> I was setting out to profile the two versions of the function and
>> unfortunately I was not able to see the CPU shootup mentioned in the
>> first message. My result shows my version of ansi-color-apply is almost
>> twice as slow as the original one. (The code and data used for profiling
>> are attached.)
>
> OK, thanks. As mentioned, it might depend on the density of SGR escape
> sequences (and on the size of the text chunks processed, which can
> depend on the machine load).
For the record, there's a bug in my version due to the use of
copy-marker, which will create many markers in the temp buffer. Should
use set-marker instead. But even after fixing this, mine is still
slower. So the conclusion holds.
While doing this I have found a bug in the original ansi-color-apply.
I'll put it in a separate report.
Leo
bug archived.
Request was from
Debbugs Internal Request <help-debbugs <at> gnu.org>
to
internal_control <at> debbugs.gnu.org
.
(Sat, 25 Dec 2010 12:24:04 GMT)
Full text and
rfc822 format available.
This bug report was last modified 14 years and 258 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.