Subject: Re: bug#20154: 25.0.50; json-encode-string is too slow for large strings

From: Dmitry Gutov <[email-masked]>
Date: Fri, 20 Mar 2015 17:20:25 +0200

On 03/20/2015 05:03 PM, Eli Zaretskii wrote:

> Yes, I could.  What's your point, though?

That if asking the question takes the same time as doing the profiling 
yourself, the latter would be more efficient. I don't really mind, just 
puzzled.

 > json-encode-char and mapconcat take most of the time, so it seems.

So it does. But here's an alternative implementation I tried:

(defun json-encode-big-string (str)
   (with-temp-buffer
     (insert str)
     (goto-char (point-min))
     (while (re-search-forward "[\"\\/\b\f\b\r\t]\\|[^ -~]" nil t)
       (replace-match (json-encode-char (char-after (match-beginning 0)))
                      t t))
     (format "\"%s\"" (buffer-string))))

It takes 0.15s here, which is still too long. Here's its profile.

CPU:

- command-execute                                   1245  95%
  - call-interactively                               1245  95%
   - funcall-interactively                           1184  90%
    - eval-last-sexp                                 1140  87%
     - elisp--eval-last-sexp                         1140  87%
      - eval                                         1140  87%
       - length                                      1140  87%
        - json-encode-big-string                     1140  87%
         - let                                       1140  87%
          - save-current-buffer                      1140  87%
           - unwind-protect                          1136  87%
            - progn                                  1136  87%
             - while                                  980  75%
              - replace-match                         332  25%
               - json-encode-char                     212  16%
                  char-after                            4   0%
               format                                   4   0%
    + execute-extended-command                         37   2%
    + previous-line                                     7   0%
   + byte-code                                         61   4%
+ ...                                                 57   4%

Memory:

- command-execute                             76,018,070 100%
  - call-interactively                         76,018,070 100%
   - funcall-interactively                     76,005,728  99%
    - eval-last-sexp                           69,257,352  91%
     - elisp--eval-last-sexp                   69,257,352  91%
      - eval                                   69,242,772  91%
       - length                                69,242,772  91%
        - json-encode-big-string               69,242,772  91%
         - let                                 69,242,772  91%
          - save-current-buffer                69,234,412  91%
           - unwind-protect                    69,040,810  90%
            - progn                            69,033,546  90%
             - while                           55,201,778  72%
              - replace-match                  17,829,052  23%
                 json-encode-char              10,471,476  13%
               format                           2,640,256   3%
            generate-new-buffer                     8,360   0%
        elisp--eval-last-sexp-print-value          12,532   0%
      + elisp--preceding-sexp                       2,048   0%
    - execute-extended-command                  6,748,360   8%
     - command-execute                          6,685,480   8%
      - call-interactively                      6,685,480   8%
       - funcall-interactively                  6,685,464   8%
        + profiler-report                       6,681,851   8%
        + profiler-start                            3,613   0%
     + sit-for                                      3,320   0%
    + previous-line                                    16   0%
   + byte-code                                     12,342   0%
   ...                                                  0   0%