unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Tooltips GC overhead
@ 2015-07-28 12:45 martin rudalics
  2015-07-28 13:53 ` Eli Zaretskii
  2015-07-28 23:51 ` Stefan Monnier
  0 siblings, 2 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-28 12:45 UTC (permalink / raw)
  To: emacs-devel

Showing a tooltip here incurs one or two garbage collection cycles.
This is just as much as an entire `scroll-down' in a C mode buffer.

Experienced on Gtk+ and Windows builds.  Does anyone have an idea what's
causing that?

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-28 12:45 Tooltips GC overhead martin rudalics
@ 2015-07-28 13:53 ` Eli Zaretskii
  2015-07-28 15:09   ` martin rudalics
  2015-07-28 23:51 ` Stefan Monnier
  1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-07-28 13:53 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

> Date: Tue, 28 Jul 2015 14:45:31 +0200
> From: martin rudalics <rudalics@gmx.at>
> 
> Showing a tooltip here incurs one or two garbage collection cycles.

I need to show a tooltip 3 times before GC kicks in.

> Does anyone have an idea what's causing that?

Looking at the value returned by garbage-collect might give some
ideas.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-28 13:53 ` Eli Zaretskii
@ 2015-07-28 15:09   ` martin rudalics
  0 siblings, 0 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-28 15:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

 >> Showing a tooltip here incurs one or two garbage collection cycles.
 >
 > I need to show a tooltip 3 times before GC kicks in.

That's what I get with emacs -Q and no files visited.  With more buffers
and files visited things get worse soon.

 > Looking at the value returned by garbage-collect might give some
 > ideas.

I tried that before and it's hardly instructive.  Less characters and
considerably less intervals consed than on the average.  As expected, I
think.

Thanks for trying, martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-28 12:45 Tooltips GC overhead martin rudalics
  2015-07-28 13:53 ` Eli Zaretskii
@ 2015-07-28 23:51 ` Stefan Monnier
  2015-07-29  7:18   ` martin rudalics
  1 sibling, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-07-28 23:51 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

> Showing a tooltip here incurs one or two garbage collection cycles.
> This is just as much as an entire `scroll-down' in a C mode buffer.
> Experienced on Gtk+ and Windows builds.  Does anyone have an idea what's
> causing that?

You could try M-x profiler-start RET mem RET, tho IIRC it counts all
allocations rather than only those that affect calling the GC.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-28 23:51 ` Stefan Monnier
@ 2015-07-29  7:18   ` martin rudalics
  2015-07-29 14:29     ` Paul Eggert
  0 siblings, 1 reply; 47+ messages in thread
From: martin rudalics @ 2015-07-29  7:18 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

 > You could try M-x profiler-start RET mem RET, tho IIRC it counts all
 > allocations rather than only those that affect calling the GC.

This gets me something like the tree below.  Can someone help me to
interpret it?  I am completely lost.  For example from

- timer-event-handler                                      56,501,327   4%
  - apply                                                   56,501,327   4%
   - tooltip-timeout                                        56,500,283   4%
    - run-hook-with-args-until-success                      56,500,283   4%
     - tooltip-help-tips                                    56,500,283   4%
      - tooltip-show                                        56,500,283   4%
       - x-show-tip                                         25,190,423   6%
        - face-set-after-frame-default                      24,981,305   5%
         + face-spec-recalc                                 24,955,421   5%
           face-list                                            19,836   0%
        + frame-set-background-mode                              1,044   0%
          run-at-time                                              996   0%
          frame-windows-min-size                                   996   0%
   + mouse-autoselect-window-select                              1,044   0%
+ command-execute                                           3,441,959   5%
+ redisplay_internal (C function)                             439,724   0%
   mode-line-modified-help-echo                                  8,188   0%
+ tooltip-show-help                                             6,264   0%
   mouse-fixup-help-message                                        512   0%
   ...                                                               0   0%

I deduce that `tooltip-show' is responsible for allocating 56,500,283
bytes (4% of what?).  Apparently, from this amount `x-show-tip' spends
25,190,423 bytes (6% of what?).  Who's responsible for the remaining 30
or so million bytes?  If the percentages are for the total number of
bytes allocated, why do 56 millions contribute 4% and three millions (as
for `command-execute') 5%?

Expanding the tree further gets me

- timer-event-handler                                      56,501,327   4%
  - apply                                                   56,501,327   4%
   - tooltip-timeout                                        56,500,283   4%
    - run-hook-with-args-until-success                      56,500,283   4%
     - tooltip-help-tips                                    56,500,283   4%
      - tooltip-show                                        56,500,283   4%
       - x-show-tip                                         25,190,423   6%
        - face-set-after-frame-default                      24,981,305   5%
         - face-spec-recalc                                 24,955,421   5%
          + face-spec-set-2                                 12,677,521   3%
          - make-face-x-resource-internal                    8,684,863  -3%
           - set-face-attributes-from-resources              8,684,863  -3%
            + set-face-attribute-from-resource               1,401,887   2%
          + face-spec-reset-face                             3,494,237   5%
          + face-spec-choose                                    16,324   0%
           face-list                                            19,836   0%
        + frame-set-background-mode                              1,044   0%
          run-at-time                                              996   0%
          frame-windows-min-size                                   996   0%
   + mouse-autoselect-window-select                              1,044   0%
+ command-execute                                           3,441,959   5%
+ redisplay_internal (C function)                             439,724   0%
   mode-line-modified-help-echo                                  8,188   0%
+ tooltip-show-help                                             6,264   0%
   mouse-fixup-help-message                                        512   0%
   ...                                                               0   0%

Again between `set-face-attributes-from-resources' with its 8,684,863
(why -3%?)  and `set-face-attribute-from-resource' with its 1,401,887 I
have a gap of 7 million bytes.  What am I missing?  Is the tree printing
routine deficient?

Thanks, martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29  7:18   ` martin rudalics
@ 2015-07-29 14:29     ` Paul Eggert
  2015-07-29 15:40       ` martin rudalics
  0 siblings, 1 reply; 47+ messages in thread
From: Paul Eggert @ 2015-07-29 14:29 UTC (permalink / raw)
  To: martin rudalics, Stefan Monnier; +Cc: emacs-devel

martin rudalics wrote:
> Is the tree printing routine deficient?

Yes.  Please try 'configure --with-wide-int'.  We really should make that the 
default.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 14:29     ` Paul Eggert
@ 2015-07-29 15:40       ` martin rudalics
  2015-07-29 16:33         ` Eli Zaretskii
  2015-07-29 16:45         ` Paul Eggert
  0 siblings, 2 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-29 15:40 UTC (permalink / raw)
  To: Paul Eggert, Stefan Monnier; +Cc: emacs-devel

 >> Is the tree printing routine deficient?
 >
 > Yes.  Please try 'configure --with-wide-int'.  We really should make that the default.

Does that mean I have to recompile all elisp files?  Because just doing
that (on Windows 32) followed by `make' makes the number appear more or
less the same and the percentages mostly negative.  For example, I now
get

     - tooltip-show                                        37,978,113  -9%
       - x-show-tip                                         17,048,133  -8%

The numbers on my Debian 64 Gtk build are roughly the same (although the
percentages show up correctly there).  So if you are only concerned
about the percentages, then this could be a problem of my Windows builds
(or the gcc I use there).

Anyway.  If you do `profiler-start', move the mouse over your mode line
for a few seconds so that tooltips show up a couple of times and then do
`profiler-report' and look at the results: Can you tell me from your
report where `tooltip-show' allocates more than half of the bytes it
allocates if _not_ in `x-show-tip'?

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 15:40       ` martin rudalics
@ 2015-07-29 16:33         ` Eli Zaretskii
  2015-07-29 18:05           ` martin rudalics
  2015-07-29 16:45         ` Paul Eggert
  1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-07-29 16:33 UTC (permalink / raw)
  To: martin rudalics; +Cc: eggert, monnier, emacs-devel

> Date: Wed, 29 Jul 2015 17:40:25 +0200
> From: martin rudalics <rudalics@gmx.at>
> Cc: emacs-devel <emacs-devel@gnu.org>
> 
>  >> Is the tree printing routine deficient?
>  >
>  > Yes.  Please try 'configure --with-wide-int'.  We really should make that the default.
> 
> Does that mean I have to recompile all elisp files?

No, of course not.  Otherwise, how would an Emacs tarball made on a
64-bit platform work out of the box on a 32-bit platform?

> Because just doing
> that (on Windows 32) followed by `make' makes the number appear more or
> less the same and the percentages mostly negative.  For example, I now
> get
> 
>      - tooltip-show                                        37,978,113  -9%
>        - x-show-tip                                         17,048,133  -8%

I think this is what Paul alluded to.

> The numbers on my Debian 64 Gtk build are roughly the same (although the
> percentages show up correctly there).

The --with-wide-int option is a no-op in 64-bit builds, AFAIK.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 15:40       ` martin rudalics
  2015-07-29 16:33         ` Eli Zaretskii
@ 2015-07-29 16:45         ` Paul Eggert
  2015-07-29 18:05           ` martin rudalics
  1 sibling, 1 reply; 47+ messages in thread
From: Paul Eggert @ 2015-07-29 16:45 UTC (permalink / raw)
  To: martin rudalics, Stefan Monnier; +Cc: emacs-devel

martin rudalics wrote:
> Does that mean I have to recompile all elisp files?

No, just the .o files, src/temacs, src/bootstrap-emacs, and src/emacs.

> Anyway.  If you do `profiler-start', move the mouse over your mode line
> for a few seconds so that tooltips show up a couple of times and then do
> `profiler-report' and look at the results: Can you tell me from your
> report where `tooltip-show' allocates more than half of the bytes it
> allocates if _not_ in `x-show-tip'?

I presume those bytes are allocated directly by tooltip-show.  By "directly" I 
mean via a function written in C, e.g., "cons".



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 16:33         ` Eli Zaretskii
@ 2015-07-29 18:05           ` martin rudalics
  2015-07-29 21:15             ` Paul Eggert
  0 siblings, 1 reply; 47+ messages in thread
From: martin rudalics @ 2015-07-29 18:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eggert, monnier, emacs-devel

 >> Does that mean I have to recompile all elisp files?
 >
 > No, of course not.  Otherwise, how would an Emacs tarball made on a
 > 64-bit platform work out of the box on a 32-bit platform?

OK.  I wouldn't have had the time anyway ;-)

 >> Because just doing
 >> that (on Windows 32) followed by `make' makes the number appear more or
 >> less the same and the percentages mostly negative.  For example, I now
 >> get
 >>
 >>       - tooltip-show                                        37,978,113  -9%
 >>         - x-show-tip                                         17,048,133  -8%
 >
 > I think this is what Paul alluded to.

But this was --with-wide-int.

 >> The numbers on my Debian 64 Gtk build are roughly the same (although the
 >> percentages show up correctly there).
 >
 > The --with-wide-int option is a no-op in 64-bit builds, AFAIK.

I didn't configure --with-wide-int on that build.

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 16:45         ` Paul Eggert
@ 2015-07-29 18:05           ` martin rudalics
  2015-07-29 21:17             ` Paul Eggert
  0 siblings, 1 reply; 47+ messages in thread
From: martin rudalics @ 2015-07-29 18:05 UTC (permalink / raw)
  To: Paul Eggert, Stefan Monnier; +Cc: emacs-devel

 >> Does that mean I have to recompile all elisp files?
 >
 > No, just the .o files, src/temacs, src/bootstrap-emacs, and src/emacs.

Good.  I did that.

 >> Anyway.  If you do `profiler-start', move the mouse over your mode line
 >> for a few seconds so that tooltips show up a couple of times and then do
 >> `profiler-report' and look at the results: Can you tell me from your
 >> report where `tooltip-show' allocates more than half of the bytes it
 >> allocates if _not_ in `x-show-tip'?
 >
 > I presume those bytes are allocated directly by tooltip-show.  By "directly" I mean via a function written in C, e.g., "cons".

There are one call of `copy-sequence', two calls of `stringp', three of
`setf', one of `propertize' and one of `selected-frame'.  Together these
would allocate some 20 million bytes?

OTOH the `copy-sequence', `face-attribute' and `alist-get' calls get
nowhere listed.

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 18:05           ` martin rudalics
@ 2015-07-29 21:15             ` Paul Eggert
  2015-07-30  6:00               ` martin rudalics
                                 ` (2 more replies)
  0 siblings, 3 replies; 47+ messages in thread
From: Paul Eggert @ 2015-07-29 21:15 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

martin rudalics wrote:

> But this was --with-wide-int.

Weird.  Perhaps my guess about your problem was wrong, though there is clearly a 
bug there in computing percentages, which I'll see if I can fix.

I can't reproduce your problem on Fedora 21, configured with gcc 5.1.0 -m32 and 
--without-imagemagick (ImageMagick breaks the build on my native x86-64 platform 
due to library incompatibilities) and running emacs -Q.  When I tried 
profiler-start with mem, then letting tooltips show over the modeline, then 
running profiler-report, I got the following, which seems benign.

- command-execute                                             985,993  99%
  - call-interactively                                         985,993  99%
   - funcall-interactively                                     984,565  99%
    - execute-extended-command                                 984,565  99%
     - command-execute                                         949,171  96%
      - call-interactively                                     949,171  96%
       - funcall-interactively                                 949,163  96%
        - profiler-report                                      943,516  95%
         - profiler-report-memory                              943,516  95%
            profiler-memory-profile                            943,516  95%
        - profiler-start                                         5,647   0%
           message                                               1,535   0%
     - sit-for                                                   5,662   0%
      - redisplay                                                2,532   0%
       - redisplay_internal (C function)                         1,874   0%
        - tool-bar-make-keymap                                   1,350   0%
         - tool-bar-make-keymap-1                                1,350   0%
          - mapcar                                               1,350   0%
           - #<compiled 0x22d16eb>                               1,350   0%
            - eval                                               1,350   0%
             - find-image                                        1,350   0%
                image-search-load-path                           1,350   0%
          kill-this-buffer-enabled-p                               524   0%
      - read-event                                                 534   0%
         mouse-fixup-help-message                                  534   0%
   - byte-code                                                   1,428   0%
    - read-extended-command                                      1,428   0%
     - completing-read                                           1,428   0%
      - completing-read-default                                  1,428   0%
       - read-from-minibuffer                                      786   0%
        - command-execute                                          128   0%
           call-interactively                                      128   0%
- timer-event-handler                                           1,252   0%
  - apply                                                        1,252   0%
   - tooltip-timeout                                             1,252   0%
    - run-hook-with-args-until-success                           1,252   0%
     - tooltip-help-tips                                         1,252   0%
        tooltip-show                                             1,252   0%
   ...                                                               0   0%




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 18:05           ` martin rudalics
@ 2015-07-29 21:17             ` Paul Eggert
  2015-07-30  6:00               ` martin rudalics
  0 siblings, 1 reply; 47+ messages in thread
From: Paul Eggert @ 2015-07-29 21:17 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

martin rudalics wrote:
> There are one call of `copy-sequence', two calls of `stringp', three of
> `setf', one of `propertize' and one of `selected-frame'.  Together these
> would allocate some 20 million bytes?

That's what it's saying, yes.

> OTOH the `copy-sequence', `face-attribute' and `alist-get' calls get
> nowhere listed.

copy-sequence and propertize are in C.  Either can easily allocate millions of 
bytes.

Perhaps face-attribute doesn't allocate storage; that would explain its not 
being listed.

alist-get is in a call to the setf macro and you may need to investigate what 
setf is really doing.  One way to look into that is to disassemble the byte code 
(type "M-x disassemble RET tooltip-show RET") and see what it does.




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 21:15             ` Paul Eggert
@ 2015-07-30  6:00               ` martin rudalics
  2015-07-30  7:08               ` martin rudalics
  2015-08-01 10:49               ` martin rudalics
  2 siblings, 0 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-30  6:00 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

 > I can't reproduce your problem on Fedora 21, configured with gcc 5.1.0
 > -m32 and --without-imagemagick (ImageMagick breaks the build on my
 > native x86-64 platform due to library incompatibilities) and running
 > emacs -Q.  When I tried profiler-start with mem, then letting tooltips
 > show over the modeline, then running profiler-report, I got the
 > following, which seems benign.

What can one conclude from this:

 >             profiler-memory-profile                            943,516  95%

That Emacs spent 95% of its allocations in `profiler-memory-profile'?
So all overhead went to the profiler itself?  This output makes even
less sense than mine :-(

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 21:17             ` Paul Eggert
@ 2015-07-30  6:00               ` martin rudalics
  0 siblings, 0 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-30  6:00 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

 >> There are one call of `copy-sequence', two calls of `stringp', three of
 >> `setf', one of `propertize' and one of `selected-frame'.  Together these
 >> would allocate some 20 million bytes?
 >
 > That's what it's saying, yes.
 >
 >> OTOH the `copy-sequence', `face-attribute' and `alist-get' calls get
 >> nowhere listed.
 >
 > copy-sequence and propertize are in C.  Either can easily allocate millions of bytes.

Just that `copy-sequence' makes a copy of a three elements alist.  And
`propertize' usually propertizes a text of a at most hundred characters
here.  If that function were that expensive, Emcas would be stuck most
of the time.

 > Perhaps face-attribute doesn't allocate storage; that would explain its not being listed.

This would make things even more mysterious.

 > alist-get is in a call to the setf macro and you may need to
 > investigate what setf is really doing.  One way to look into that is
 > to disassemble the byte code (type "M-x disassemble RET tooltip-show
 > RET") and see what it does.

I suppose running `tooltip-show' interpreted might be the easier way.

In any case, neither the profiler nor tooltips appear usable in their
current implementation.

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 21:15             ` Paul Eggert
  2015-07-30  6:00               ` martin rudalics
@ 2015-07-30  7:08               ` martin rudalics
  2015-07-30  7:19                 ` Paul Eggert
  2015-08-01 10:49               ` martin rudalics
  2 siblings, 1 reply; 47+ messages in thread
From: martin rudalics @ 2015-07-30  7:08 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

 > I can't reproduce your problem on Fedora 21, configured with gcc 5.1.0
 > -m32 and --without-imagemagick (ImageMagick breaks the build on my
 > native x86-64 platform due to library incompatibilities) and running
 > emacs -Q.  When I tried profiler-start with mem, then letting tooltips
 > show over the modeline, then running profiler-report, I got the
 > following, which seems benign.
 >
 > - command-execute                                             985,993  99%
 >   - call-interactively                                         985,993  99%
 >    - funcall-interactively                                     984,565  99%
 >     - execute-extended-command                                 984,565  99%
 >      - command-execute                                         949,171  96%
 >       - call-interactively                                     949,171  96%
 >        - funcall-interactively                                 949,163  96%
 >         - profiler-report                                      943,516  95%
 >          - profiler-report-memory                              943,516  95%
 >             profiler-memory-profile                            943,516  95%
 >         - profiler-start                                         5,647   0%
 >            message                                               1,535   0%

I was able to reproduce something comparable here on Windows (in a
--with-wide-int build):

- command-execute                                           1,572,084  96%
  - call-interactively                                       1,572,084  96%
   - funcall-interactively                                   1,529,090  94%
    - execute-extended-command                               1,246,749  76%
     - command-execute                                       1,071,389  66%
      - call-interactively                                   1,071,389  66%
       - funcall-interactively                               1,071,381  66%
        - profiler-report                                    1,071,381  66%
         - profiler-report-memory                            1,071,381  66%
          - profiler-memory-profile                            936,852  57%
             profiler-make-profile                               1,560   0%
          + profiler-report-profile-other-window               134,529   8%
     + execute-extended-command--shorter                       117,026   7%
     + sit-for                                                  40,850   2%
      delete-other-windows                                     274,505  16%
    + next-line                                                  7,836   0%
   + byte-code                                                  42,994   2%
+ redisplay_internal (C function)                              41,588   2%
+ timer-event-handler                                           5,220   0%
+ tooltip-show-help                                             2,088   0%
   mouse-fixup-help-message                                      1,499   0%
   ...                                                               0   0%

I suppose you didn't wait until the tooltips really showed up.  When I
do wait I get something like:

- timer-event-handler                                      15,930,094  28%
  - apply                                                   15,925,918  28%
   - tooltip-timeout                                        15,924,874  28%
    - run-hook-with-args-until-success                      15,924,874  28%
     - tooltip-help-tips                                    15,924,874  28%
      - tooltip-show                                        15,924,874  28%
       - x-show-tip                                            675,546   3%
        - face-set-after-frame-default                         637,389   3%
         - face-spec-recalc                                    629,704   3%
          + face-spec-reset-face                               605,688   3%
          + face-spec-set-2                                     11,040   0%
          + face-spec-choose                                     7,756   0%
           face-list                                             4,176   0%
     jit-lock-context-fontify                                    1,044   0%
  + timer-inc-time                                               3,132   0%
+ command-execute                                           1,396,925   7%
+ redisplay_internal (C function)                             660,432   3%
+ tooltip-show-help                                             5,220   0%
+ frame-windows-min-size                                        1,044   0%
+ eldoc-schedule-timer                                          1,044   0%
   ...                                                               0   0%

and after another attempt:

+ timer-event-handler                                      16,921,522 -22%
+ command-execute                                           1,934,186   9%
+ redisplay_internal (C function)                           1,081,661   5%
+ #<compiled 0x5afd1f>                                        189,536   0%
+ mouse-fixup-help-message                                     12,528   0%
+ clear-transient-map                                           6,820   0%
+ tooltip-show-help                                             5,220   0%
+ clear-transient-map                                           4,492   0%
   gui-set-selection                                             1,044   0%
+ eldoc-schedule-timer                                          1,044   0%
   ...                                                               0   0%

So the percentages apparently get wrong over time, maybe due to some
overflow.  But I'm quite sure that the backtrace unifying algorithm
(`profiler-calltree-build-unified') is inherently broken.  I'm not sure
though whether there's any chance to fix that in the first place.

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30  7:08               ` martin rudalics
@ 2015-07-30  7:19                 ` Paul Eggert
  2015-07-30  9:05                   ` martin rudalics
  0 siblings, 1 reply; 47+ messages in thread
From: Paul Eggert @ 2015-07-30  7:19 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

martin rudalics wrote:
>
> I suppose you didn't wait until the tooltips really showed up.

No, I waited.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30  7:19                 ` Paul Eggert
@ 2015-07-30  9:05                   ` martin rudalics
  2015-07-30 16:36                     ` Eli Zaretskii
  2016-03-06  9:21                     ` martin rudalics
  0 siblings, 2 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-30  9:05 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

 >> I suppose you didn't wait until the tooltips really showed up.
 >
 > No, I waited.

This is hopeless.  Evaluating

(let ((c cons-cells-consed)
       (v vector-cells-consed))
   (tooltip-show "foobar")
   (message "cons: %s vector: %s"
	   (- cons-cells-consed c)
	   (- vector-cells-consed v)))

gives here "cons: 58696 vector: 9443".  Evaluating

(let ((c cons-cells-consed)
       (v vector-cells-consed))
   (x-show-tip "foobar")
   (message "cons: %s vector: %s"
	   (- cons-cells-consed c)
	   (- vector-cells-consed v)))

gets me "cons: 58649 vector: 9443", so the remainder of `tooltip-show'
is responsible for just 47 additional conses.  We can ignore that.

I suppose most of the overhead goes to x_create_tip_frame - a normal
`make-frame' here gets me "cons: 37464 vector: 33018".  Calculating the
tooltip position doesn't seem to add much overhead.  So the only way to
fix this is to hide tooltip frames instead of deleting and re-creating
them.  If this can be done properly.

And - ceterum censeo - the profiler should be fixed.  In its current
form it's more confusing than enlightening.

martin




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30  9:05                   ` martin rudalics
@ 2015-07-30 16:36                     ` Eli Zaretskii
  2015-07-30 19:53                       ` martin rudalics
  2016-03-06  9:21                     ` martin rudalics
  1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-07-30 16:36 UTC (permalink / raw)
  To: martin rudalics; +Cc: eggert, emacs-devel

> Date: Thu, 30 Jul 2015 11:05:47 +0200
> From: martin rudalics <rudalics@gmx.at>
> Cc: emacs-devel@gnu.org
> 
>  >> I suppose you didn't wait until the tooltips really showed up.
>  >
>  > No, I waited.
> 
> This is hopeless.  Evaluating
> 
> (let ((c cons-cells-consed)
>        (v vector-cells-consed))
>    (tooltip-show "foobar")
>    (message "cons: %s vector: %s"
> 	   (- cons-cells-consed c)
> 	   (- vector-cells-consed v)))
> 
> gives here "cons: 58696 vector: 9443".  Evaluating
> 
> (let ((c cons-cells-consed)
>        (v vector-cells-consed))
>    (x-show-tip "foobar")
>    (message "cons: %s vector: %s"
> 	   (- cons-cells-consed c)
> 	   (- vector-cells-consed v)))
> 
> gets me "cons: 58649 vector: 9443", so the remainder of `tooltip-show'
> is responsible for just 47 additional conses.  We can ignore that.
> 
> I suppose most of the overhead goes to x_create_tip_frame - a normal
> `make-frame' here gets me "cons: 37464 vector: 33018".  Calculating the
> tooltip position doesn't seem to add much overhead.  So the only way to
> fix this is to hide tooltip frames instead of deleting and re-creating
> them.  If this can be done properly.

According to my testing, over 80% of consing happens inside
face-spec-recalc which is called by face-set-after-frame-default on
all the known faces.

I guess your numbers above are from a non-Q session with a lot of
additional faces, because in "emacs -Q" I get "only" about 15000
conses from a single tool-tip.

So maybe one other idea is to skip faces that are obviously unused in
tip frames.

Or maybe we should just make gc-cons-threshold higher ;-)

This is not new, btw: Emacs 24.1 exhibits approximately the same
numbers, Emacs 23 conses only two thirds of that, and Emacs 22.3 one
third.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30 16:36                     ` Eli Zaretskii
@ 2015-07-30 19:53                       ` martin rudalics
  2015-07-30 23:09                         ` Stefan Monnier
  2015-07-31  6:47                         ` Eli Zaretskii
  0 siblings, 2 replies; 47+ messages in thread
From: martin rudalics @ 2015-07-30 19:53 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eggert, emacs-devel

 > According to my testing, over 80% of consing happens inside
 > face-spec-recalc which is called by face-set-after-frame-default on
 > all the known faces.

What's so special about `face-spec-recalc'?

 > I guess your numbers above are from a non-Q session with a lot of
 > additional faces, because in "emacs -Q" I get "only" about 15000
 > conses from a single tool-tip.

Correct.  emacs -Q gets me 9324 conses and 3546 vectors.

 > So maybe one other idea is to skip faces that are obviously unused in
 > tip frames.

Hmmm...  Maybe I should reduce the number of my faces.  They seem to
cause a combinatory explosion.

 > Or maybe we should just make gc-cons-threshold higher ;-)

I have a problem with overlays or visibility specification which
occasionally causes an inexplicable 5-10 secs delay here.  Then I
started to display the number of GC cycles in the modeline to find out
whether GC is responsible and accidentally noticed that tooltips cause
more GCs than anything else.  Funnily there's never a disruptive effect
due to GC.

 > This is not new, btw: Emacs 24.1 exhibits approximately the same
 > numbers, Emacs 23 conses only two thirds of that, and Emacs 22.3 one
 > third.

So with Emacs 22.3 you had one GC every ninth tooltip?

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30 19:53                       ` martin rudalics
@ 2015-07-30 23:09                         ` Stefan Monnier
  2015-07-30 23:33                           ` Drew Adams
  2015-07-31  6:47                         ` Eli Zaretskii
  1 sibling, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-07-30 23:09 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, eggert, emacs-devel

>> So maybe one other idea is to skip faces that are obviously unused in
>> tip frames.
> Hmmm...  Maybe I should reduce the number of my faces.  They seem to
> cause a combinatory explosion.

I guess we (c|sh)ould optimize frame creation algorithmically
(e.g. making face-spec-recalc lazy so that the faces are "recalc"ulated
only if needed).

I'm a heavy user of frames, and I've never been satisfied by the time
needed to create a new frame, so I'd be happy to see some improvement in
this area.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: Tooltips GC overhead
  2015-07-30 23:09                         ` Stefan Monnier
@ 2015-07-30 23:33                           ` Drew Adams
  2015-07-31  6:48                             ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Drew Adams @ 2015-07-30 23:33 UTC (permalink / raw)
  To: Stefan Monnier, martin rudalics; +Cc: Eli Zaretskii, eggert, emacs-devel

> I'm a heavy user of frames, and I've never been satisfied by the time
> needed to create a new frame, so I'd be happy to see some improvement in
> this area.

I too use frames heavily.  And I remember that frame creation
could be slow on UNIX - back in the Dark Ages, at least.  But
AFAICT it is nearly instantaneous on MS Windows.  Maybe
something can be done at a lower level to speed things up on
other platforms?



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30 19:53                       ` martin rudalics
  2015-07-30 23:09                         ` Stefan Monnier
@ 2015-07-31  6:47                         ` Eli Zaretskii
  1 sibling, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2015-07-31  6:47 UTC (permalink / raw)
  To: martin rudalics; +Cc: eggert, emacs-devel

> Date: Thu, 30 Jul 2015 21:53:47 +0200
> From: martin rudalics <rudalics@gmx.at>
> CC: eggert@cs.ucla.edu, emacs-devel@gnu.org
> 
>  > According to my testing, over 80% of consing happens inside
>  > face-spec-recalc which is called by face-set-after-frame-default on
>  > all the known faces.
> 
> What's so special about `face-spec-recalc'?

It loops over all the faces; for each one of them, it first calls
face-spec-reset-face, which loops over all the face attributes, then
calls face-spec-set-2, which again sets face attributes.  If you look
at face-spec-reset-face, you'll see that it, too, conses quite a lot.

>  > This is not new, btw: Emacs 24.1 exhibits approximately the same
>  > numbers, Emacs 23 conses only two thirds of that, and Emacs 22.3 one
>  > third.
> 
> So with Emacs 22.3 you had one GC every ninth tooltip?

I get more, but not because of faces.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30 23:33                           ` Drew Adams
@ 2015-07-31  6:48                             ` Eli Zaretskii
  0 siblings, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2015-07-31  6:48 UTC (permalink / raw)
  To: Drew Adams; +Cc: rudalics, eggert, monnier, emacs-devel

> Date: Thu, 30 Jul 2015 16:33:33 -0700 (PDT)
> From: Drew Adams <drew.adams@oracle.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, eggert@cs.ucla.edu, emacs-devel@gnu.org
> 
> > I'm a heavy user of frames, and I've never been satisfied by the time
> > needed to create a new frame, so I'd be happy to see some improvement in
> > this area.
> 
> I too use frames heavily.  And I remember that frame creation
> could be slow on UNIX - back in the Dark Ages, at least.  But
> AFAICT it is nearly instantaneous on MS Windows.  Maybe
> something can be done at a lower level to speed things up on
> other platforms?

The code in question runs on all platforms for GUI frames, so it is as
slow on Unix as it is fast on Windows.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-29 21:15             ` Paul Eggert
  2015-07-30  6:00               ` martin rudalics
  2015-07-30  7:08               ` martin rudalics
@ 2015-08-01 10:49               ` martin rudalics
  2015-08-03 10:34                 ` Stefan Monnier
  2 siblings, 1 reply; 47+ messages in thread
From: martin rudalics @ 2015-08-01 10:49 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

 > Weird.  Perhaps my guess about your problem was wrong, though there is
 > clearly a bug there in computing percentages, which I'll see if I can
 > fix.

Whatever you've done: With latest trunk/master all percentages come up
correctly.  So many thanks for your efforts.

The following excerpt from `profiler-report' still exhibits the other
problem:

- timer-event-handler                                      21,655,992  90%
  - apply                                                   21,655,992  90%
   - tooltip-timeout                                        21,655,992  90%
    - run-hook-with-args-until-success                      21,655,992  90%
     - tooltip-help-tips                                    21,655,992  90%
      - tooltip-show                                        21,655,992  90%
       - x-show-tip                                          1,119,104   4%
        - face-set-after-frame-default                       1,119,104   4%
         - face-spec-recalc                                  1,102,240   4%
          + face-spec-reset-face                             1,045,708   4%
          + face-spec-set-2                                     21,924   0%
          + face-spec-choose                                    15,816   0%
           face-list                                             5,220   0%
+ command-execute                                           1,399,342   5%
+ redisplay_internal (C function)                             870,687   3%
+ tooltip-show-help                                             8,352   0%
   ...                                                               0   0%

The absolute value for `x-show-tip' is surely wrong.  `x-show-tip'
is responsible for 90% (or maybe 89%) of the allocations.

Thanks again, martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-01 10:49               ` martin rudalics
@ 2015-08-03 10:34                 ` Stefan Monnier
  2015-08-03 14:56                   ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-08-03 10:34 UTC (permalink / raw)
  To: martin rudalics; +Cc: Paul Eggert, emacs-devel

> The absolute value for `x-show-tip' is surely wrong.  `x-show-tip'
> is responsible for 90% (or maybe 89%) of the allocations.

A potential source of such errors is that we count the moment when
"malloc" is called, and this can be misleading: you could do a thousand
"cons" calls in x-show-tip, all satisfied from the list of free
cons-cells, and then a single "cons" call elsewhere which finds the free
list to be empty and hence does a "malloc" which will re-fill the free
list with another thousand cons cells.

Often/usually, this should be "random" and hence irrelevant
statistically (as long as we have enough samples), but there might well
be cases where the allocation patterns end up always shifting the
blame elsewhere.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-03 10:34                 ` Stefan Monnier
@ 2015-08-03 14:56                   ` Eli Zaretskii
  2015-08-03 21:13                     ` Stefan Monnier
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-03 14:56 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, eggert, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Mon, 03 Aug 2015 06:34:52 -0400
> Cc: Paul Eggert <eggert@cs.ucla.edu>, emacs-devel@gnu.org
> 
> > The absolute value for `x-show-tip' is surely wrong.  `x-show-tip'
> > is responsible for 90% (or maybe 89%) of the allocations.
> 
> A potential source of such errors is that we count the moment when
> "malloc" is called, and this can be misleading: you could do a thousand
> "cons" calls in x-show-tip, all satisfied from the list of free
> cons-cells, and then a single "cons" call elsewhere which finds the free
> list to be empty and hence does a "malloc" which will re-fill the free
> list with another thousand cons cells.

Indeed, when I looked into this issue, I tracked increments to
consing_since_gc.  Perhaps we should change the "memory" profiler to
do the same.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-03 14:56                   ` Eli Zaretskii
@ 2015-08-03 21:13                     ` Stefan Monnier
  2015-08-04  2:38                       ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-08-03 21:13 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, eggert, emacs-devel

> Indeed, when I looked into this issue, I tracked increments to
> consing_since_gc.  Perhaps we should change the "memory" profiler to
> do the same.

The problem is that it would slow down functions like `cons'.  And given
that the "memory profiler" is very rarely useful, I'm not really willing
to pay that slowdown.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-03 21:13                     ` Stefan Monnier
@ 2015-08-04  2:38                       ` Eli Zaretskii
  2015-08-04  7:31                         ` Stefan Monnier
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-04  2:38 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, eggert, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: rudalics@gmx.at,  eggert@cs.ucla.edu,  emacs-devel@gnu.org
> Date: Mon, 03 Aug 2015 17:13:03 -0400
> 
> > Indeed, when I looked into this issue, I tracked increments to
> > consing_since_gc.  Perhaps we should change the "memory" profiler to
> > do the same.
> 
> The problem is that it would slow down functions like `cons'.

I don't see why it has to.

And we could do that only when the memory profiler is invoked.

In any case, it's much better than the current useless profile.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-04  2:38                       ` Eli Zaretskii
@ 2015-08-04  7:31                         ` Stefan Monnier
  2015-08-04 13:28                           ` Eli Zaretskii
  2015-08-08 13:41                           ` Nix
  0 siblings, 2 replies; 47+ messages in thread
From: Stefan Monnier @ 2015-08-04  7:31 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, eggert, emacs-devel

>> The problem is that it would slow down functions like `cons'.
> I don't see why it has to.

I don't see how it wouldn't have to ;-)

> And we could do that only when the memory profiler is invoked.

AFAICT it would require an extra test somewhere in Fcons, and that
test will always have to be performed.

> In any case, it's much better than the current useless profile.

I'm not convinced it'd make it sufficiently better to justify the cost.
I'd be OK with adding this "more precise allocation profiler" as
a compile-time option, so we could at least see if the improved
precision does make it more useful.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-04  7:31                         ` Stefan Monnier
@ 2015-08-04 13:28                           ` Eli Zaretskii
  2015-08-07 14:52                             ` Stefan Monnier
  2015-08-08 13:41                           ` Nix
  1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-04 13:28 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, eggert, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: rudalics@gmx.at,  eggert@cs.ucla.edu,  emacs-devel@gnu.org
> Date: Tue, 04 Aug 2015 03:31:52 -0400
> 
> > And we could do that only when the memory profiler is invoked.
> 
> AFAICT it would require an extra test somewhere in Fcons, and that
> test will always have to be performed.

Just looking at the implementation of Fcons, I find it hard to believe
a single comparison can have any significant effect on its efficiency.
So I'm unsure how this could be of any practical concern.

> > In any case, it's much better than the current useless profile.
> 
> I'm not convinced it'd make it sufficiently better

Well, it allowed me in this case to identify the source of the problem
quickly, efficiently, and accurately.

> to justify the cost.

Please show the costs, then, and please do that with some kind of
quantitative analysis, so that we could have some numbers to discuss,
instead of just arguing about personal preferences and opinions.

> I'd be OK with adding this "more precise allocation profiler" as
> a compile-time option, so we could at least see if the improved
> precision does make it more useful.

IME, compile-time options of this kind are rarely useful, because they
are never there when you need them.  Especially if the person who
needs to perform measurements doesn't build their Emacs.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-04 13:28                           ` Eli Zaretskii
@ 2015-08-07 14:52                             ` Stefan Monnier
  2015-08-07 15:23                               ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-08-07 14:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, eggert, emacs-devel

> Just looking at the implementation of Fcons, I find it hard to believe
> a single comparison can have any significant effect on its efficiency.
> So I'm unsure how this could be of any practical concern.

Fcons is a core operation executed fairly frequently, so any slowdown
(no matter how small) needs to be justified by a major advantage.

Making the allocation profiler (which so far has never been useful to
anyone, AFAICT) slightly more precise, is not obviously a "major
advantage".  At the very least, I'd need positive proof that the extra
precision has been useful at least once.

>> > In any case, it's much better than the current useless profile.
>> I'm not convinced it'd make it sufficiently better
> Well, it allowed me in this case to identify the source of the problem
> quickly, efficiently, and accurately.

IIUC, something *else* allowed you to do that.  I don't think anyone
has actually tried to improve the precision of the allocation profiler
and found it to help in this case.
It's quite possible that some other problems might still prevent it from
being useful in this case.

>> I'd be OK with adding this "more precise allocation profiler" as
>> a compile-time option, so we could at least see if the improved
>> precision does make it more useful.
> IME, compile-time options of this kind are rarely useful, because they
> are never there when you need them.  Especially if the person who
> needs to perform measurements doesn't build their Emacs.

Until I have positive proof that the extra precision is useful in some
cases, I'll reject such changes in the default build.  So it's either
"rejected" or "depends on a compile-time option" for now.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 14:52                             ` Stefan Monnier
@ 2015-08-07 15:23                               ` Eli Zaretskii
  2015-08-07 17:26                                 ` Stefan Monnier
  2015-08-07 18:26                                 ` Paul Eggert
  0 siblings, 2 replies; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-07 15:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, eggert, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: rudalics@gmx.at,  eggert@cs.ucla.edu,  emacs-devel@gnu.org
> Date: Fri, 07 Aug 2015 10:52:34 -0400
> 
> > Just looking at the implementation of Fcons, I find it hard to believe
> > a single comparison can have any significant effect on its efficiency.
> > So I'm unsure how this could be of any practical concern.
> 
> Fcons is a core operation executed fairly frequently, so any slowdown
> (no matter how small) needs to be justified by a major advantage.

Without some kind of quantitative criterion, this sounds irrational to
me.  Would a 0.001% slow-down be acceptable?  How about 0.1%?  There
must exist some threshold below which any slow-down can be ignored,
and the question I'm asking is what is that threshold?

> >> > In any case, it's much better than the current useless profile.
> >> I'm not convinced it'd make it sufficiently better
> > Well, it allowed me in this case to identify the source of the problem
> > quickly, efficiently, and accurately.
> 
> IIUC, something *else* allowed you to do that.

That something else was a watchpoint put on the variable, followed by
semi-manual computation of the frequency distribution of functions
that caused the watchpoint to fire.  That's exactly what a profiler
would have done for me, if it were looking at that variable instead of
counting calls to malloc.

> Until I have positive proof that the extra precision is useful in some
> cases, I'll reject such changes in the default build.  So it's either
> "rejected" or "depends on a compile-time option" for now.

Too bad.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 15:23                               ` Eli Zaretskii
@ 2015-08-07 17:26                                 ` Stefan Monnier
  2015-08-07 18:20                                   ` Eli Zaretskii
  2015-08-07 18:26                                 ` Paul Eggert
  1 sibling, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-08-07 17:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, eggert, emacs-devel

> Without some kind of quantitative criterion, this sounds irrational to
> me.  Would a 0.001% slow-down be acceptable?  How about 0.1%?  There
> must exist some threshold below which any slow-down can be ignored,
> and the question I'm asking is what is that threshold?

For a functionality whose usefulness has not been proven, the threshold
is 0%.

> That something else was a watchpoint put on the variable, followed by
> semi-manual computation of the frequency distribution of functions
> that caused the watchpoint to fire.  That's exactly what a profiler
> would have done for me, if it were looking at that variable instead of
> counting calls to malloc.

I'd welcome a patch which uses such a "sampling watchpoint", since it
would even speed up the code by removing the code that counts calls
to malloc.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 17:26                                 ` Stefan Monnier
@ 2015-08-07 18:20                                   ` Eli Zaretskii
  2015-08-07 21:25                                     ` Stefan Monnier
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-07 18:20 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, eggert, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: rudalics@gmx.at,  eggert@cs.ucla.edu,  emacs-devel@gnu.org
> Date: Fri, 07 Aug 2015 13:26:54 -0400
> 
> > Without some kind of quantitative criterion, this sounds irrational to
> > me.  Would a 0.001% slow-down be acceptable?  How about 0.1%?  There
> > must exist some threshold below which any slow-down can be ignored,
> > and the question I'm asking is what is that threshold?
> 
> For a functionality whose usefulness has not been proven, the threshold
> is 0%.

That's irrational.

> > That something else was a watchpoint put on the variable, followed by
> > semi-manual computation of the frequency distribution of functions
> > that caused the watchpoint to fire.  That's exactly what a profiler
> > would have done for me, if it were looking at that variable instead of
> > counting calls to malloc.
> 
> I'd welcome a patch which uses such a "sampling watchpoint", since it
> would even speed up the code by removing the code that counts calls
> to malloc.

Sorry, your jokes are beyond me.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 15:23                               ` Eli Zaretskii
  2015-08-07 17:26                                 ` Stefan Monnier
@ 2015-08-07 18:26                                 ` Paul Eggert
  2015-08-07 18:59                                   ` Eli Zaretskii
  1 sibling, 1 reply; 47+ messages in thread
From: Paul Eggert @ 2015-08-07 18:26 UTC (permalink / raw)
  To: Eli Zaretskii, Stefan Monnier; +Cc: rudalics, emacs-devel

Eli Zaretskii wrote:
> Without some kind of quantitative criterion, this sounds irrational to
> me.

I don't know -- adding gingerbread to Fcons, even if it's a small inefficiency 
now, is likely to lead to greater inefficiencies later as it will place more 
design constraints on future attempts to improve performance.  In the meantime 
surely it's enough to make it a compile-time option.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 18:26                                 ` Paul Eggert
@ 2015-08-07 18:59                                   ` Eli Zaretskii
  0 siblings, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-07 18:59 UTC (permalink / raw)
  To: Paul Eggert; +Cc: rudalics, monnier, emacs-devel

> Date: Fri, 07 Aug 2015 11:26:12 -0700
> From: Paul Eggert <eggert@cs.ucla.edu>
> CC: rudalics@gmx.at, emacs-devel@gnu.org
> 
> Eli Zaretskii wrote:
> > Without some kind of quantitative criterion, this sounds irrational to
> > me.
> 
> I don't know -- adding gingerbread to Fcons, even if it's a small inefficiency 
> now, is likely to lead to greater inefficiencies later as it will place more 
> design constraints on future attempts to improve performance.

Don't be ridiculous; all it takes is a single test followed by a
function call that is only made if the test succeeded (i.e. a profile
is in progress).  We do that all the time, and no one has ever looked
back.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 18:20                                   ` Eli Zaretskii
@ 2015-08-07 21:25                                     ` Stefan Monnier
  2015-08-08  6:46                                       ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-08-07 21:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, eggert, emacs-devel

>> I'd welcome a patch which uses such a "sampling watchpoint", since it
>> would even speed up the code by removing the code that counts calls
>> to malloc.
> Sorry, your jokes are beyond me.

You must have misunderstood, because that was no joke at all.  I really
mean it: I'd be happy to see a patch which uses the same trick used by
GDB to add a "watchpoint".


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-07 21:25                                     ` Stefan Monnier
@ 2015-08-08  6:46                                       ` Eli Zaretskii
  2015-08-08  7:01                                         ` David Kastrup
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2015-08-08  6:46 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, eggert, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: rudalics@gmx.at,  eggert@cs.ucla.edu,  emacs-devel@gnu.org
> Date: Fri, 07 Aug 2015 17:25:37 -0400
> 
> >> I'd welcome a patch which uses such a "sampling watchpoint", since it
> >> would even speed up the code by removing the code that counts calls
> >> to malloc.
> > Sorry, your jokes are beyond me.
> 
> You must have misunderstood, because that was no joke at all.  I really
> mean it: I'd be happy to see a patch which uses the same trick used by
> GDB to add a "watchpoint".

GDB uses debug registers and the debug interface that catches the
resulting signal/exception, something a well-behaving program that is
not a debugger should never do.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-08  6:46                                       ` Eli Zaretskii
@ 2015-08-08  7:01                                         ` David Kastrup
  0 siblings, 0 replies; 47+ messages in thread
From: David Kastrup @ 2015-08-08  7:01 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, eggert, Stefan Monnier, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Stefan Monnier <monnier@iro.umontreal.ca>
>> Cc: rudalics@gmx.at,  eggert@cs.ucla.edu,  emacs-devel@gnu.org
>> Date: Fri, 07 Aug 2015 17:25:37 -0400
>> 
>> >> I'd welcome a patch which uses such a "sampling watchpoint", since it
>> >> would even speed up the code by removing the code that counts calls
>> >> to malloc.
>> > Sorry, your jokes are beyond me.
>> 
>> You must have misunderstood, because that was no joke at all.  I really
>> mean it: I'd be happy to see a patch which uses the same trick used by
>> GDB to add a "watchpoint".
>
> GDB uses debug registers and the debug interface that catches the
> resulting signal/exception, something a well-behaving program that is
> not a debugger should never do.

Well, but in this case we want to debug a problem.  So it might be worth
considering how to make it easy and/or standard to generate/retrieve the
desired information from a debugger.  Interpreted languages like
GUILE/Elisp tend to be a real mess to debug regarding the setting of
break points and trapping on virtual machine registers and so on.  The
question is how one could make it easier to immerse the debugger in the
world view of an interpreted/VM application and use its hardware tools
for debugging problems not cast in terms of actual assembly code on the
executing CPU.

Zero-expense Lisp-level hooks that only become available within a
debugging session (and of course have quite non-zero cost when activated
but zero when not) but do not require recompilation would fall in that
class.

Of course, that would be a nice long-term solution.  But the mere
potential for a long-term solution does not solve short-term problems.
In particular if nobody is working on the long-term solutions.

-- 
David Kastrup



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-04  7:31                         ` Stefan Monnier
  2015-08-04 13:28                           ` Eli Zaretskii
@ 2015-08-08 13:41                           ` Nix
  2015-08-08 16:10                             ` Stefan Monnier
  1 sibling, 1 reply; 47+ messages in thread
From: Nix @ 2015-08-08 13:41 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: rudalics, Eli Zaretskii, eggert, emacs-devel

On 4 Aug 2015, Stefan Monnier told this:

>>> The problem is that it would slow down functions like `cons'.
>> I don't see why it has to.
>
> I don't see how it wouldn't have to ;-)
>
>> And we could do that only when the memory profiler is invoked.
>
> AFAICT it would require an extra test somewhere in Fcons, and that
> test will always have to be performed.

The cost you're trying to defend against here is a mispredicted branch
and corresponding pipeline stall, so if you mark it with
__builtin_expect() (or analogue in other compilers) you can make the
'profiler off' case the predicted branch, and its cost when off should
drop to nearly zero.

(Or so it seems to me.)

-- 
NULL && (void)



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-08 13:41                           ` Nix
@ 2015-08-08 16:10                             ` Stefan Monnier
  2015-08-08 16:13                               ` David Kastrup
  0 siblings, 1 reply; 47+ messages in thread
From: Stefan Monnier @ 2015-08-08 16:10 UTC (permalink / raw)
  To: Nix; +Cc: rudalics, Eli Zaretskii, eggert, emacs-devel

> The cost you're trying to defend against here is a mispredicted branch

No, I assume the branch would be properly predicted since it would
always take the same path.


        Stefan



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-08 16:10                             ` Stefan Monnier
@ 2015-08-08 16:13                               ` David Kastrup
  2015-08-10 17:05                                 ` Nix
  0 siblings, 1 reply; 47+ messages in thread
From: David Kastrup @ 2015-08-08 16:13 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Nix, rudalics, Eli Zaretskii, eggert, emacs-devel

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> The cost you're trying to defend against here is a mispredicted branch
>
> No, I assume the branch would be properly predicted since it would
> always take the same path.

If cons is encountered with high frequency.  But of course, if it is
not, why bother in the first place?

-- 
David Kastrup



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-08 16:13                               ` David Kastrup
@ 2015-08-10 17:05                                 ` Nix
  2015-08-10 17:44                                   ` David Kastrup
  0 siblings, 1 reply; 47+ messages in thread
From: Nix @ 2015-08-10 17:05 UTC (permalink / raw)
  To: David Kastrup
  Cc: rudalics, Eli Zaretskii, eggert, Stefan Monnier, emacs-devel

On 8 Aug 2015, David Kastrup uttered the following:

> Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>
>>> The cost you're trying to defend against here is a mispredicted branch
>>
>> No, I assume the branch would be properly predicted since it would
>> always take the same path.
>
> If cons is encountered with high frequency.  But of course, if it is
> not, why bother in the first place?

In that case I have no idea what you're trying to defend against. The
cost of a single conditional and predicted branch is drowned in the
overhead of the allocation that cons has to do anyway. I'd be astonished
if you could ever see any performance impact whatsoever.

-- 
NULL && (void)



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-08-10 17:05                                 ` Nix
@ 2015-08-10 17:44                                   ` David Kastrup
  0 siblings, 0 replies; 47+ messages in thread
From: David Kastrup @ 2015-08-10 17:44 UTC (permalink / raw)
  To: Nix; +Cc: rudalics, Eli Zaretskii, eggert, Stefan Monnier, emacs-devel

Nix <nix@esperi.org.uk> writes:

> On 8 Aug 2015, David Kastrup uttered the following:
>
>> Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
>>
>>>> The cost you're trying to defend against here is a mispredicted branch
>>>
>>> No, I assume the branch would be properly predicted since it would
>>> always take the same path.
>>
>> If cons is encountered with high frequency.  But of course, if it is
>> not, why bother in the first place?
>
> In that case I have no idea what you're trying to defend against. The
> cost of a single conditional and predicted branch is drowned in the
> overhead of the allocation that cons has to do anyway.

Cons cells are pooled, so in a long session the consolidated cost is
that of getting from the free list (cheap) and sweeping back into it
once a mark phase no longer visits the cell.  Which would be the rule
rather than the exception for high-frequency consing.

> I'd be astonished if you could ever see any performance impact
> whatsoever.

Cons cells for Lisp should end up quite cheaper than arbitrary-size
allocations.

-- 
David Kastrup



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2015-07-30  9:05                   ` martin rudalics
  2015-07-30 16:36                     ` Eli Zaretskii
@ 2016-03-06  9:21                     ` martin rudalics
  2016-03-08  8:02                       ` martin rudalics
  1 sibling, 1 reply; 47+ messages in thread
From: martin rudalics @ 2016-03-06  9:21 UTC (permalink / raw)
  To: Paul Eggert; +Cc: emacs-devel

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

 > I suppose most of the overhead goes to x_create_tip_frame - a normal
 > `make-frame' here gets me "cons: 37464 vector: 33018".  Calculating the
 > tooltip position doesn't seem to add much overhead.  So the only way to
 > fix this is to hide tooltip frames instead of deleting and re-creating
 > them.  If this can be done properly.

I now tweaked the code to do that.  If nobody objects I intend to apply
the attached patch in the next days.


Optionally reuse tooltip frames instead of deleting/recreating them.

* src/frame.c (tooltip_reuse_hidden_frame): New option.
* src/w32fns.c (x_create_tip_frame): Remove argument TEXT.  Fix
handling of dividers.
(x_hide_tip): New function.
(Fx_show_tip): Try to reuse old tooltip frame when
`tooltip-reuse-hidden-frame' is non-nil and frame parameters
have not changed.  Insert STRING here instead of passing it to
x_create_tip_frame.  Compute size of tooltip window with
Fwindow_text_pixel_size.  Obey Vw32_tooltip_extra_pixels when
padding tooltip window.
(Fx_hide_tip): Call x_hide_tip.
(Vw32_tooltip_extra_pixels): New variable.
* src/xdisp.c (Fwindow_text_pixel_size): Don't return negative y
value.  Fix doc-string.
* src/xfns.c (x_create_tip_frame): Remove argument TEXT.  Call
make_frame with mini_p argument false.
(x_hide_tip): New function.
(Fx_show_tip): Try to reuse old tooltip frame when
`tooltip-reuse-hidden-frame' is non-nil and frame parameters
have not changed.  Insert STRING here instead of passing it to
x_create_tip_frame.  Compute size of tooltip window with
Fwindow_text_pixel_size.  Obey Vw32_tooltip_extra_pixels when
padding tooltip window.
(Fx_hide_tip): Call x_hide_tip.
* lisp/cus-start.el (tooltip-reuse-hidden-frame): Add
customization entry.


martin

[-- Attachment #2: lightweight-tooltips.diff --]
[-- Type: text/plain, Size: 48374 bytes --]

diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 5be61ce..1c10bf7 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -311,6 +311,7 @@ minibuffer-prompt-properties--setter
 					    (const :tag "Always" t)
 					    (repeat (symbol :tag "Parameter")))
 					   "25.1")
+	     (tooltip-reuse-hidden-frame tooltip boolean "26.1")
 	     ;; fringe.c
 	     (overflow-newline-into-fringe fringe boolean)
 	     ;; image.c
diff --git a/src/frame.c b/src/frame.c
index fd9f3ce..d536468 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -5262,6 +5262,21 @@ The function `frame--size-history' displays the value of this variable
 in a more readable form.  */);
     frame_size_history = Qnil;

+  DEFVAR_BOOL ("tooltip-reuse-hidden-frame", tooltip_reuse_hidden_frame,
+	       doc: /* Non-nil means reuse hidden tooltip frames.
+When this is nil, delete a tooltip frame when hiding the associated
+tooltip.  When this is non-nil, make the tooltip frame invisible only,
+so it can be reused when the next tooltip is shown.
+
+Setting this to non-nil may drastically reduce the consing overhead
+incurred by creating new tooltip frames.  However, a value of non-nil
+means also that intermittent changes of faces or `default-frame-alist'
+are not applied when showing a tooltip in a reused frame.
+
+This variable is effective only with the X toolkit (and there only when
+Gtk+ tooltips are not used) and on Windows.  */);
+  tooltip_reuse_hidden_frame = false;
+
   staticpro (&Vframe_list);

   defsubr (&Sframep);
diff --git a/src/w32fns.c b/src/w32fns.c
index 10c8af7..2dfbdc3 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -6416,8 +6416,6 @@ no value of TYPE (always string in the MS Windows case).  */)
 				Tool tips
  ***********************************************************************/

-static Lisp_Object x_create_tip_frame (struct w32_display_info *,
-				       Lisp_Object, Lisp_Object);
 static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
 			    Lisp_Object, int, int, int *, int *);

@@ -6452,8 +6450,7 @@ unwind_create_tip_frame (Lisp_Object frame)


 /* Create a frame for a tooltip on the display described by DPYINFO.
-   PARMS is a list of frame parameters.  TEXT is the string to
-   display in the tip frame.  Value is the frame.
+   PARMS is a list of frame parameters.  Value is the frame.

    Note that functions called here, esp. x_default_parameter can
    signal errors, for instance when a specified color name is
@@ -6461,8 +6458,7 @@ unwind_create_tip_frame (Lisp_Object frame)
    when this happens.  */

 static Lisp_Object
-x_create_tip_frame (struct w32_display_info *dpyinfo,
-		    Lisp_Object parms, Lisp_Object text)
+x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
 {
   struct frame *f;
   Lisp_Object frame;
@@ -6471,8 +6467,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   ptrdiff_t count = SPECPDL_INDEX ();
   struct kboard *kb;
   bool face_change_before = face_change;
-  Lisp_Object buffer;
-  struct buffer *old_buffer;
   int x_width = 0, x_height = 0;

   /* Use this general default value to start with until we know if
@@ -6496,23 +6490,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   frame = Qnil;
   /* Make a frame without minibuffer nor mode-line.  */
   f = make_frame (false);
-  f->wants_modeline = 0;
+  f->wants_modeline = false;
   XSETFRAME (frame, f);

-  AUTO_STRING (tip, " *tip*");
-  buffer = Fget_buffer_create (tip);
-  /* Use set_window_buffer instead of Fset_window_buffer (see
-     discussion of bug#11984, bug#12025, bug#12026).  */
-  set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false);
-  old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (buffer));
-  bset_truncate_lines (current_buffer, Qnil);
-  specbind (Qinhibit_read_only, Qt);
-  specbind (Qinhibit_modification_hooks, Qt);
-  Ferase_buffer ();
-  Finsert (1, &text);
-  set_buffer_internal_1 (old_buffer);
-
   record_unwind_protect (unwind_create_tip_frame, frame);

   /* By setting the output method, we're essentially saying that
@@ -6546,7 +6526,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
     {
       fset_name (f, name);
       f->explicit_name = true;
-      /* use the frame's title when getting resources for this frame.  */
+      /* Use the frame's title when getting resources for this frame.  */
       specbind (Qx_resource_name, name);
     }

@@ -6576,14 +6556,10 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
 	parms = Fcons (Fcons (Qinternal_border_width, value),
 		       parms);
     }
+
   x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
 		       "internalBorderWidth", "internalBorderWidth",
 		       RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qright_divider_width, make_number (0),
-		       NULL, NULL, RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qbottom_divider_width, make_number (0),
-		       NULL, NULL, RES_TYPE_NUMBER);
-
   /* Also do the stuff which must be set before the window exists.  */
   x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
 		       "foreground", "Foreground", RES_TYPE_STRING);
@@ -6610,6 +6586,9 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   f->fringe_cols = 0;
   f->left_fringe_width = 0;
   f->right_fringe_width = 0;
+  /* No dividers on tip frame.  */
+  f->right_divider_width = 0;
+  f->bottom_divider_width = 0;

   block_input ();
   my_create_tip_window (f);
@@ -6636,7 +6615,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
   SET_FRAME_LINES (f, 0);
   adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f),
 		     height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame);
-
   /* Add `tooltip' frame parameter's default value. */
   if (NILP (Fframe_parameter (frame, Qtooltip)))
     Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil));
@@ -6654,8 +6632,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo,
     Lisp_Object fg = Fframe_parameter (frame, Qforeground_color);
     Lisp_Object colors = Qnil;

-    /* Set tip_frame here, so that */
-    tip_frame = frame;
     call2 (Qface_set_after_frame_default, frame, Qnil);

     if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
@@ -6787,6 +6763,48 @@ compute_tip_xy (struct frame *f,
     *root_x = min_x;
 }

+/* Hide tooltip.  Delete its frame if DELETE is true.  */
+static Lisp_Object
+x_hide_tip (bool delete)
+{
+  if (!NILP (tip_timer))
+    {
+      call1 (Qcancel_timer, tip_timer);
+      tip_timer = Qnil;
+    }
+
+  if (NILP (tip_frame)
+      || (!delete && FRAMEP (tip_frame)
+	  && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
+    return Qnil;
+  else
+    {
+      ptrdiff_t count;
+      Lisp_Object was_open = Qnil;
+
+      count = SPECPDL_INDEX ();
+      specbind (Qinhibit_redisplay, Qt);
+      specbind (Qinhibit_quit, Qt);
+
+      if (FRAMEP (tip_frame))
+	{
+	  if (delete)
+	    {
+	      delete_frame (tip_frame, Qnil);
+	      tip_frame = Qnil;
+	    }
+	  else
+	    x_make_frame_invisible (XFRAME (tip_frame));
+
+	  was_open = Qt;
+	}
+      else
+	tip_frame = Qnil;
+
+      return unbind_to (count, was_open);
+    }
+}
+

 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
        doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
@@ -6820,15 +6838,16 @@ A tooltip's maximum size is specified by `x-max-tooltip-size'.
 Text larger than the specified size is clipped.  */)
   (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
 {
-  struct frame *f;
+  struct frame *f, *tip_f;
   struct window *w;
   int root_x, root_y;
   struct buffer *old_buffer;
   struct text_pos pos;
   int i, width, height;
-  bool seen_reversed_p;
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   ptrdiff_t count = SPECPDL_INDEX ();
+  ptrdiff_t count_1;
+  Lisp_Object window, size;

   specbind (Qinhibit_redisplay, Qt);

@@ -6852,91 +6871,155 @@ Text larger than the specified size is clipped.  */)
   if (NILP (last_show_tip_args))
     last_show_tip_args = Fmake_vector (make_number (3), Qnil);

-  if (!NILP (tip_frame))
+  if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       Lisp_Object last_string = AREF (last_show_tip_args, 0);
       Lisp_Object last_frame = AREF (last_show_tip_args, 1);
       Lisp_Object last_parms = AREF (last_show_tip_args, 2);

-      if (EQ (frame, last_frame)
-	  && !NILP (Fequal (last_string, string))
+      if (FRAME_VISIBLE_P (XFRAME (tip_frame))
+	  && EQ (frame, last_frame)
+	  && !NILP (Fequal_including_properties (last_string, string))
 	  && !NILP (Fequal (last_parms, parms)))
 	{
-	  struct frame *f = XFRAME (tip_frame);
-
 	  /* Only DX and DY have changed.  */
+	  tip_f = XFRAME (tip_frame);
 	  if (!NILP (tip_timer))
 	    {
 	      Lisp_Object timer = tip_timer;
+
 	      tip_timer = Qnil;
 	      call1 (Qcancel_timer, timer);
 	    }

 	  block_input ();
-	  compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
-			  FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
+	  compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f),
+			  FRAME_PIXEL_HEIGHT (tip_f), &root_x, &root_y);

 	  /* Put tooltip in topmost group and in position.  */
-	  SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
+	  SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST,
 			root_x, root_y, 0, 0,
 			SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);

 	  /* Ensure tooltip is on top of other topmost windows (eg menus).  */
-	  SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
+	  SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP,
 			0, 0, 0, 0,
 			SWP_NOMOVE | SWP_NOSIZE
 			| SWP_NOACTIVATE | SWP_NOOWNERZORDER);

+	  /* Let redisplay know that we have made the frame visible already.  */
+	  SET_FRAME_VISIBLE (tip_f, 1);
+	  ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE);
 	  unblock_input ();
+
 	  goto start_timer;
 	}
-    }
+      else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame))
+	{
+	  bool delete = false;
+	  Lisp_Object tail, elt, parm, last;

-  /* Hide a previous tip, if any.  */
-  Fx_hide_tip ();
+	  /* Check if every parameter in PARMS has the same value in
+	     last_parms.  This may destruct last_parms which, however,
+	     will be recreated below.  */
+	  for (tail = parms; CONSP (tail); tail = XCDR (tail))
+	    {
+	      elt = XCAR (tail);
+	      parm = Fcar (elt);
+	      /* The left, top, right and bottom parameters are handled
+		 by compute_tip_xy so they can be ignored here.  */
+	      if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
+		  && !EQ (parm, Qright) && !EQ (parm, Qbottom))
+		{
+		  last = Fassq (parm, last_parms);
+		  if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
+		    {
+		      /* We lost, delete the old tooltip.  */
+		      delete = true;
+		      break;
+		    }
+		  else
+		    last_parms = call2 (Qassq_delete_all, parm, last_parms);
+		}
+	      else
+		last_parms = call2 (Qassq_delete_all, parm, last_parms);
+	    }
+
+	  /* Now check if there's a parameter left in last_parms with a
+	     non-nil value.  */
+	  for (tail = last_parms; CONSP (tail); tail = XCDR (tail))
+	    {
+	      elt = XCAR (tail);
+	      parm = Fcar (elt);
+	      if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
+		  && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
+		{
+		  /* We lost, delete the old tooltip.  */
+		  delete = true;
+		  break;
+		}
+	    }
+
+	  x_hide_tip (delete);
+	}
+      else
+	x_hide_tip (true);
+    }
+  else
+    x_hide_tip (true);

   ASET (last_show_tip_args, 0, string);
   ASET (last_show_tip_args, 1, frame);
   ASET (last_show_tip_args, 2, parms);

-  /* Add default values to frame parameters.  */
-  if (NILP (Fassq (Qname, parms)))
-    parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
-  if (NILP (Fassq (Qinternal_border_width, parms)))
-    parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
-  if (NILP (Fassq (Qright_divider_width, parms)))
-    parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms);
-  if (NILP (Fassq (Qbottom_divider_width, parms)))
-    parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms);
-  if (NILP (Fassq (Qborder_width, parms)))
-    parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
-  if (NILP (Fassq (Qborder_color, parms)))
-    parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
-  if (NILP (Fassq (Qbackground_color, parms)))
-    parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
-		   parms);
-
   /* Block input until the tip has been fully drawn, to avoid crashes
      when drawing tips in menus.  */
   block_input ();

-  /* Create a frame for the tooltip, and record it in the global
-     variable tip_frame.  */
-  frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string);
-  f = XFRAME (frame);
+  if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+    {
+      /* Add default values to frame parameters.  */
+      if (NILP (Fassq (Qname, parms)))
+	parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+      if (NILP (Fassq (Qinternal_border_width, parms)))
+	parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
+      if (NILP (Fassq (Qborder_width, parms)))
+	parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
+      if (NILP (Fassq (Qborder_color, parms)))
+	parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
+      if (NILP (Fassq (Qbackground_color, parms)))
+	parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+		       parms);
+
+      /* Create a frame for the tooltip, and record it in the global
+	 variable tip_frame.  */
+      if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
+	{
+	  /* Creating the tip frame failed.  */
+	  unblock_input ();
+	  return unbind_to (count, Qnil);
+	}
+    }
+
+  tip_f = XFRAME (tip_frame);
+  window = FRAME_ROOT_WINDOW (tip_f);
+  AUTO_STRING (tip, " *tip*");
+  set_window_buffer (window, Fget_buffer_create (tip), false, false);
+  w = XWINDOW (window);
+  w->pseudo_window_p = true;

-  /* Set up the frame's root window.  */
-  w = XWINDOW (FRAME_ROOT_WINDOW (f));
+  /* Set up the frame's root window.  Note: The following code does not
+     try to size the window or its frame correctly.  Its only purpose is
+     to make the subsequent text size calculations work.  The right
+     sizes should get installed when the toolkit gets back to us.  */
   w->left_col = 0;
   w->top_line = 0;
   w->pixel_left = 0;
   w->pixel_top = 0;

   if (CONSP (Vx_max_tooltip_size)
-      && INTEGERP (XCAR (Vx_max_tooltip_size))
-      && XINT (XCAR (Vx_max_tooltip_size)) > 0
-      && INTEGERP (XCDR (Vx_max_tooltip_size))
-      && XINT (XCDR (Vx_max_tooltip_size)) > 0)
+      && RANGED_INTEGERP (1, XCAR (Vx_max_tooltip_size), INT_MAX)
+      && RANGED_INTEGERP (1, XCDR (Vx_max_tooltip_size), INT_MAX))
     {
       w->total_cols = XFASTINT (XCAR (Vx_max_tooltip_size));
       w->total_lines = XFASTINT (XCDR (Vx_max_tooltip_size));
@@ -6947,164 +7030,71 @@ Text larger than the specified size is clipped.  */)
       w->total_lines = 40;
     }

-  w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f);
-  w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f);
-
-  FRAME_TOTAL_COLS (f) = WINDOW_TOTAL_COLS (w);
-  adjust_frame_glyphs (f);
-  w->pseudo_window_p = true;
+  w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
+  w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
+  FRAME_TOTAL_COLS (tip_f) = WINDOW_TOTAL_COLS (w);
+  adjust_frame_glyphs (tip_f);

-  /* Display the tooltip text in a temporary buffer.  */
+  /* Insert STRING into the root window's buffer and fit the frame to
+     the buffer.  */
+  count_1 = SPECPDL_INDEX ();
   old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents));
+  set_buffer_internal_1 (XBUFFER (w->contents));
   bset_truncate_lines (current_buffer, Qnil);
+  specbind (Qinhibit_read_only, Qt);
+  specbind (Qinhibit_modification_hooks, Qt);
+  specbind (Qinhibit_point_motion_hooks, Qt);
+  Ferase_buffer ();
+  Finsert (1, &string);
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
-
-  /* Compute width and height of the tooltip.  */
-  width = height = 0;
-  seen_reversed_p = false;
-  for (i = 0; i < w->desired_matrix->nrows; ++i)
-    {
-      struct glyph_row *row = &w->desired_matrix->rows[i];
-      struct glyph *last;
-      int row_width;
-
-      /* Stop at the first empty row at the end.  */
-      if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-	break;
-
-      /* Let the row go over the full width of the frame.  */
-      row->full_width_p = true;
-
-      row_width = row->pixel_width;
-      if (row->used[TEXT_AREA])
-	{
-	  if (!row->reversed_p)
-	    {
-	      /* There's a glyph at the end of rows that is used to
-		 place the cursor there.  Don't include the width of
-		 this glyph.  */
-	      last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
-	      if (NILP (last->object))
-		row_width -= last->pixel_width;
-	    }
-	  else
-	    {
-	      /* There could be a stretch glyph at the beginning of R2L
-		 rows that is produced by extend_face_to_end_of_line.
-		 Don't count that glyph.  */
-	      struct glyph *g = row->glyphs[TEXT_AREA];
-
-	      if (g->type == STRETCH_GLYPH && NILP (g->object))
-		{
-		  row_width -= g->pixel_width;
-		  seen_reversed_p = true;
-		}
-	    }
-	}
-
-      height += row->height;
-      width = max (width, row_width);
-    }
-
-  /* If we've seen partial-length R2L rows, we need to re-adjust the
-     tool-tip frame width and redisplay it again, to avoid over-wide
-     tips due to the stretch glyph that extends R2L lines to full
-     width of the frame.  */
-  if (seen_reversed_p)
-    {
-      /* PXW: Why do we do the pixel-to-cols conversion only if
-	 seen_reversed_p holds?  Don't we have to set other fields of
-	 the window/frame structure?
-
-	 w->total_cols and FRAME_TOTAL_COLS want the width in columns,
-	 not in pixels.  */
-      w->pixel_width = width;
-      width /= WINDOW_FRAME_COLUMN_WIDTH (w);
-      w->total_cols = width;
-      FRAME_TOTAL_COLS (f) = width;
-      SET_FRAME_WIDTH (f, width);
-      adjust_frame_glyphs (f);
-      w->pseudo_window_p = 1;
-      clear_glyph_matrix (w->desired_matrix);
-      clear_glyph_matrix (w->current_matrix);
-      try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
-      width = height = 0;
-      /* Recompute width and height of the tooltip.  */
-      for (i = 0; i < w->desired_matrix->nrows; ++i)
-	{
-	  struct glyph_row *row = &w->desired_matrix->rows[i];
-	  struct glyph *last;
-	  int row_width;
-
-	  if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-	    break;
-	  row->full_width_p = true;
-	  row_width = row->pixel_width;
-	  if (row->used[TEXT_AREA] && !row->reversed_p)
-	    {
-	      last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
-	      if (NILP (last->object))
-		row_width -= last->pixel_width;
-	    }
-
-	  height += row->height;
-	  width = max (width, row_width);
-	}
-    }
-
-  /* Add the frame's internal border to the width and height the w32
-     window should have.  */
-  height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
-  width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
-
-  /* Move the tooltip window where the mouse pointer is.  Resize and
-     show it.
-
-     PXW: This should use the frame's pixel coordinates.  */
-  compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
-
+  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  /* Calculate size of tooltip window.  */
+  size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
+				  make_number (w->pixel_height), Qnil);
+  /* Add the frame's internal border to calculated size.  */
+  width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+  height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+  /* Calculate position of tooltip frame.  */
+  compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
+
+  /* Show tooltip frame.  */
   {
-    /* Adjust Window size to take border into account.  */
     RECT rect;
+    int pad = (NUMBERP (Vw32_tooltip_extra_pixels)
+	       ? max (0, XINT (Vw32_tooltip_extra_pixels))
+	       : FRAME_COLUMN_WIDTH (tip_f));
+
     rect.left = rect.top = 0;
     rect.right = width;
     rect.bottom = height;
-    AdjustWindowRect (&rect, f->output_data.w32->dwStyle, false);
-
-    /* Position and size tooltip, and put it in the topmost group.
-       The add-on of FRAME_COLUMN_WIDTH to the 5th argument is a
-       peculiarity of w32 display: without it, some fonts cause the
-       last character of the tip to be truncated or wrapped around to
-       the next line.  */
-    SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
+    AdjustWindowRect (&rect, tip_f->output_data.w32->dwStyle,
+		      FRAME_EXTERNAL_MENU_BAR (tip_f));
+
+    /* Position and size tooltip and put it in the topmost group.  */
+    SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOPMOST,
 		  root_x, root_y,
-		  rect.right - rect.left + FRAME_COLUMN_WIDTH (f),
+		  rect.right - rect.left + pad,
 		  rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER);

     /* Ensure tooltip is on top of other topmost windows (eg menus).  */
-    SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
+    SetWindowPos (FRAME_W32_WINDOW (tip_f), HWND_TOP,
 		  0, 0, 0, 0,
 		  SWP_NOMOVE | SWP_NOSIZE
 		  | SWP_NOACTIVATE | SWP_NOOWNERZORDER);

     /* Let redisplay know that we have made the frame visible already.  */
-    SET_FRAME_VISIBLE (f, 1);
+    SET_FRAME_VISIBLE (tip_f, 1);

-    ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
+    ShowWindow (FRAME_W32_WINDOW (tip_f), SW_SHOWNOACTIVATE);
   }

-  /* Draw into the window.  */
   w->must_be_updated_p = true;
   update_single_window (w);
-
-  unblock_input ();
-
-  /* Restore original current buffer.  */
   set_buffer_internal_1 (old_buffer);
+  unbind_to (count_1, Qnil);
+  unblock_input ();
   windows_or_buffers_changed = old_windows_or_buffers_changed;

  start_timer:
@@ -7121,31 +7111,7 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
 Value is t if tooltip was open, nil otherwise.  */)
   (void)
 {
-  ptrdiff_t count;
-  Lisp_Object deleted, frame, timer;
-
-  /* Return quickly if nothing to do.  */
-  if (NILP (tip_timer) && NILP (tip_frame))
-    return Qnil;
-
-  frame = tip_frame;
-  timer = tip_timer;
-  tip_frame = tip_timer = deleted = Qnil;
-
-  count = SPECPDL_INDEX ();
-  specbind (Qinhibit_redisplay, Qt);
-  specbind (Qinhibit_quit, Qt);
-
-  if (!NILP (timer))
-    call1 (Qcancel_timer, timer);
-
-  if (FRAMEP (frame))
-    {
-      delete_frame (frame, Qnil);
-      deleted = Qt;
-    }
-
-  return unbind_to (count, deleted);
+  return x_hide_tip (!tooltip_reuse_hidden_frame);
 }
 \f
 /***********************************************************************
@@ -9745,6 +9711,7 @@ syms_of_w32fns (void)
   DEFSYM (Qmm_size, "mm-size");
   DEFSYM (Qframes, "frames");
   DEFSYM (Qtip_frame, "tip-frame");
+  DEFSYM (Qassq_delete_all, "assq-delete-all");
   DEFSYM (Qunicode_sip, "unicode-sip");
 #if defined WINDOWSNT && !defined HAVE_DBUS
   DEFSYM (QCicon, ":icon");
@@ -10057,6 +10024,18 @@ Default is nil.
 This variable has effect only on Windows Vista and later.  */);
   w32_disable_new_uniscribe_apis = 0;

+  DEFVAR_LISP ("w32-tooltip-extra-pixels",
+	       Vw32_tooltip_extra_pixels,
+	       doc: /* Number of pixels added after tooltip text.
+On Windows some fonts may cause the last character of a tooltip be
+truncated or wrapped around to the next line.  Adding some extra space
+at the end of the toooltip works around this problem.
+
+This variable specifies the number of pixels that shall be added.  The
+default value t means to add the width of one canonical character of the
+tip frame.  */);
+  Vw32_tooltip_extra_pixels = Qt;
+
 #if 0 /* TODO: Port to W32 */
   defsubr (&Sx_change_window_property);
   defsubr (&Sx_delete_window_property);
diff --git a/src/xdisp.c b/src/xdisp.c
index b9d496e..5b96144 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -9794,26 +9794,28 @@ the maximum pixel-height of all text lines.

 The optional argument FROM, if non-nil, specifies the first text
 position and defaults to the minimum accessible position of the buffer.
-If FROM is t, use the minimum accessible position that is not a newline
-character.  TO, if non-nil, specifies the last text position and
+If FROM is t, use the minimum accessible position that starts a
+non-empty line.  TO, if non-nil, specifies the last text position and
 defaults to the maximum accessible position of the buffer.  If TO is t,
-use the maximum accessible position that is not a newline character.
+use the maximum accessible position that ends a non-empty line.

 The optional argument X-LIMIT, if non-nil, specifies the maximum text
 width that can be returned.  X-LIMIT nil or omitted, means to use the
-pixel-width of WINDOW's body; use this if you do not intend to change
-the width of WINDOW.  Use the maximum width WINDOW may assume if you
-intend to change WINDOW's width.  In any case, text whose x-coordinate
-is beyond X-LIMIT is ignored.  Since calculating the width of long lines
-can take some time, it's always a good idea to make this argument as
-small as possible; in particular, if the buffer contains long lines that
-shall be truncated anyway.
+pixel-width of WINDOW's body; use this if you want to know how high
+WINDOW should be become in order to fit all of its buffer's text with
+the width of WINDOW unaltered.  Use the maximum width WINDOW may assume
+if you intend to change WINDOW's width.  In any case, text whose
+x-coordinate is beyond X-LIMIT is ignored.  Since calculating the width
+of long lines can take some time, it's always a good idea to make this
+argument as small as possible; in particular, if the buffer contains
+long lines that shall be truncated anyway.

 The optional argument Y-LIMIT, if non-nil, specifies the maximum text
-height that can be returned.  Text lines whose y-coordinate is beyond
-Y-LIMIT are ignored.  Since calculating the text height of a large
-buffer can take some time, it makes sense to specify this argument if
-the size of the buffer is unknown.
+height (exluding the height of the mode- or header-line, if any) that
+can be returned.  Text lines whose y-coordinate is beyond Y-LIMIT are
+ignored.  Since calculating the text height of a large buffer can take
+some time, it makes sense to specify this argument if the size of the
+buffer is large or unknown.

 Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
 include the height of the mode- or header-line of WINDOW in the return
@@ -9831,7 +9833,7 @@ include the height of both, if present, in the return value.  */)
   ptrdiff_t start, end, pos;
   struct text_pos startp;
   void *itdata = NULL;
-  int c, max_y = -1, x = 0, y = 0;
+  int c, max_x = 0, max_y = 0, x = 0, y = 0;

   CHECK_BUFFER (buffer);
   b = XBUFFER (buffer);
@@ -9876,11 +9878,13 @@ include the height of both, if present, in the return value.  */)
       end = max (start, min (XINT (to), ZV));
     }

-  if (!NILP (y_limit))
-    {
-      CHECK_NUMBER (y_limit);
-      max_y = min (XINT (y_limit), INT_MAX);
-    }
+  if (!NILP (x_limit) && RANGED_INTEGERP (0, x_limit, INT_MAX))
+    max_x = XINT (x_limit);
+
+  if (NILP (y_limit))
+    max_y = INT_MAX;
+  else if (RANGED_INTEGERP (0, y_limit, INT_MAX))
+    max_y = XINT (y_limit);

   itdata = bidi_shelve_cache ();
   SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
@@ -9890,27 +9894,30 @@ include the height of both, if present, in the return value.  */)
     x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y);
   else
     {
-      CHECK_NUMBER (x_limit);
-      it.last_visible_x = min (XINT (x_limit), INFINITY);
+      it.last_visible_x = max_x;
       /* Actually, we never want move_it_to stop at to_x.  But to make
 	 sure that move_it_in_display_line_to always moves far enough,
-	 we set it to INT_MAX and specify MOVE_TO_X.  */
-      x = move_it_to (&it, end, INT_MAX, max_y, -1,
-		      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+	 we set it to INT_MAX and specify MOVE_TO_X.  Also bound width
+	 value by X-LIMIT.  */
+      x = min (move_it_to (&it, end, INT_MAX, max_y, -1,
+			   MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y),
+	       max_x);
     }

-  y = it.current_y + it.max_ascent + it.max_descent;
+  /* Subtract height of header-line which was counted automatically by
+     start_display.  */
+  y = min (it.current_y + it.max_ascent + it.max_descent
+	   - WINDOW_HEADER_LINE_HEIGHT (w),
+	   max_y);

-  if (!EQ (mode_and_header_line, Qheader_line)
-      && !EQ (mode_and_header_line, Qt))
-    /* Do not count the header-line which was counted automatically by
-       start_display.  */
-    y = y - WINDOW_HEADER_LINE_HEIGHT (w);
+  if (EQ (mode_and_header_line, Qheader_line)
+      || EQ (mode_and_header_line, Qt))
+    /* Re-add height of header-line as requested.  */
+    y = y + WINDOW_HEADER_LINE_HEIGHT (w);

   if (EQ (mode_and_header_line, Qmode_line)
       || EQ (mode_and_header_line, Qt))
-    /* Do count the mode-line which is not included automatically by
-       start_display.  */
+    /* Add height of mode-line as requested.  */
     y = y + WINDOW_MODE_LINE_HEIGHT (w);

   bidi_unshelve_cache (itdata, false);
diff --git a/src/xfns.c b/src/xfns.c
index 2a50a5a..c1ce1b7 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -5303,8 +5303,6 @@ no value of TYPE (always string in the MS Windows case).  */)
 				Tool tips
  ***********************************************************************/

-static Lisp_Object x_create_tip_frame (struct x_display_info *,
-                                       Lisp_Object, Lisp_Object);
 static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
                             Lisp_Object, int, int, int *, int *);

@@ -5348,9 +5346,7 @@ unwind_create_tip_frame (Lisp_Object frame)
    when this happens.  */

 static Lisp_Object
-x_create_tip_frame (struct x_display_info *dpyinfo,
-                    Lisp_Object parms,
-                    Lisp_Object text)
+x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
 {
   struct frame *f;
   Lisp_Object frame;
@@ -5359,7 +5355,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
   ptrdiff_t count = SPECPDL_INDEX ();
   bool face_change_before = face_change;
   Lisp_Object buffer;
-  struct buffer *old_buffer;
   int x_width = 0, x_height = 0;

   if (!dpyinfo->terminal->name)
@@ -5375,23 +5370,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
     error ("Invalid frame name--not a string or nil");

   frame = Qnil;
-  f = make_frame (true);
+  f = make_frame (false);
+  f->wants_modeline = false;
   XSETFRAME (frame, f);
-
-  AUTO_STRING (tip, " *tip*");
-  buffer = Fget_buffer_create (tip);
-  /* Use set_window_buffer instead of Fset_window_buffer (see
-     discussion of bug#11984, bug#12025, bug#12026).  */
-  set_window_buffer (FRAME_ROOT_WINDOW (f), buffer, false, false);
-  old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (buffer));
-  bset_truncate_lines (current_buffer, Qnil);
-  specbind (Qinhibit_read_only, Qt);
-  specbind (Qinhibit_modification_hooks, Qt);
-  Ferase_buffer ();
-  Finsert (1, &text);
-  set_buffer_internal_1 (old_buffer);
-
   record_unwind_protect (unwind_create_tip_frame, frame);

   f->terminal = dpyinfo->terminal;
@@ -5633,8 +5614,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
   {
     Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);

-    /* Set tip_frame here, so that */
-    tip_frame = frame;
     call2 (Qface_set_after_frame_default, frame, Qnil);

     if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
@@ -5773,6 +5752,85 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, Lisp_Object
 }


+/* Hide tooltip.  Delete its frame if DELETE is true.  */
+static Lisp_Object
+x_hide_tip (bool delete)
+{
+  if (!NILP (tip_timer))
+    {
+      call1 (Qcancel_timer, tip_timer);
+      tip_timer = Qnil;
+    }
+
+
+  if (NILP (tip_frame)
+      || (!delete && FRAMEP (tip_frame)
+	  && !FRAME_VISIBLE_P (XFRAME (tip_frame))))
+    return Qnil;
+  else
+    {
+      ptrdiff_t count;
+      Lisp_Object was_open = Qnil;
+
+      count = SPECPDL_INDEX ();
+      specbind (Qinhibit_redisplay, Qt);
+      specbind (Qinhibit_quit, Qt);
+
+#ifdef USE_GTK
+      {
+	/* When using system tooltip, tip_frame is the Emacs frame on
+	   which the tip is shown.  */
+	struct frame *f = XFRAME (tip_frame);
+
+	if (FRAME_LIVE_P (f) && xg_hide_tooltip (f))
+	  {
+	    tip_frame = Qnil;
+	    was_open = Qt;
+	  }
+      }
+#endif
+
+      if (FRAMEP (tip_frame))
+	{
+	  if (delete)
+	    {
+	      delete_frame (tip_frame, Qnil);
+	      tip_frame = Qnil;
+	    }
+	  else
+	    x_make_frame_invisible (XFRAME (tip_frame));
+
+	  was_open = Qt;
+
+#ifdef USE_LUCID
+	  /* Bloodcurdling hack alert: The Lucid menu bar widget's
+	     redisplay procedure is not called when a tip frame over
+	     menu items is unmapped.  Redisplay the menu manually...  */
+	  {
+	    Widget w;
+	    struct frame *f = SELECTED_FRAME ();
+	    if (FRAME_X_P (f) && FRAME_LIVE_P (f))
+	      {
+		w = f->output_data.x->menubar_widget;
+
+		if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen)
+		    && w != NULL)
+		  {
+		    block_input ();
+		    xlwmenu_redisplay (w);
+		    unblock_input ();
+		  }
+	      }
+	  }
+#endif /* USE_LUCID */
+	}
+      else
+	tip_frame = Qnil;
+
+      return unbind_to (count, was_open);
+    }
+}
+
 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
        doc: /* Show STRING in a "tooltip" window on frame FRAME.
 A tooltip window is a small X window displaying a string.
@@ -5805,15 +5863,16 @@ A tooltip's maximum size is specified by `x-max-tooltip-size'.
 Text larger than the specified size is clipped.  */)
   (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
 {
-  struct frame *f;
+  struct frame *f, *tip_f;
   struct window *w;
   int root_x, root_y;
   struct buffer *old_buffer;
   struct text_pos pos;
-  int i, width, height;
-  bool seen_reversed_p;
+  int width, height;
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   ptrdiff_t count = SPECPDL_INDEX ();
+  ptrdiff_t count_1;
+  Lisp_Object window, size;

   specbind (Qinhibit_redisplay, Qt);

@@ -5862,22 +5921,23 @@ Text larger than the specified size is clipped.  */)
   if (NILP (last_show_tip_args))
     last_show_tip_args = Fmake_vector (make_number (3), Qnil);

-  if (!NILP (tip_frame))
+  if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame)))
     {
       Lisp_Object last_string = AREF (last_show_tip_args, 0);
       Lisp_Object last_frame = AREF (last_show_tip_args, 1);
       Lisp_Object last_parms = AREF (last_show_tip_args, 2);

-      if (EQ (frame, last_frame)
-	  && !NILP (Fequal (last_string, string))
+      if (FRAME_VISIBLE_P (XFRAME (tip_frame))
+	  && EQ (frame, last_frame)
+	  && !NILP (Fequal_including_properties (last_string, string))
 	  && !NILP (Fequal (last_parms, parms)))
 	{
-	  struct frame *tip_f = XFRAME (tip_frame);
-
 	  /* Only DX and DY have changed.  */
+	  tip_f = XFRAME (tip_frame);
 	  if (!NILP (tip_timer))
 	    {
 	      Lisp_Object timer = tip_timer;
+
 	      tip_timer = Qnil;
 	      call1 (Qcancel_timer, timer);
 	    }
@@ -5888,41 +5948,103 @@ Text larger than the specified size is clipped.  */)
 	  XMoveWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f),
 		       root_x, root_y);
 	  unblock_input ();
+
 	  goto start_timer;
 	}
-    }
+      else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame))
+	{
+	  bool delete = false;
+	  Lisp_Object tail, elt, parm, last;
+
+	  /* Check if every parameter in PARMS has the same value in
+	     last_parms unless it should be ignored by means of
+	     Vtooltip_reuse_hidden_frame_parameters.  This may destruct
+	     last_parms which, however, will be recreated below.  */
+	  for (tail = parms; CONSP (tail); tail = XCDR (tail))
+	    {
+	      elt = XCAR (tail);
+	      parm = Fcar (elt);
+	      /* The left, top, right and bottom parameters are handled
+		 by compute_tip_xy so they can be ignored here.  */
+	      if (!EQ (parm, Qleft) && !EQ (parm, Qtop)
+		  && !EQ (parm, Qright) && !EQ (parm, Qbottom))
+		{
+		  last = Fassq (parm, last_parms);
+		  if (NILP (Fequal (Fcdr (elt), Fcdr (last))))
+		    {
+		      /* We lost, delete the old tooltip.  */
+		      delete = true;
+		      break;
+		    }
+		  else
+		    last_parms = call2 (Qassq_delete_all, parm, last_parms);
+		}
+	      else
+		last_parms = call2 (Qassq_delete_all, parm, last_parms);
+	    }

-  /* Hide a previous tip, if any.  */
-  Fx_hide_tip ();
+	  /* Now check if every parameter in what is left of last_parms
+	     with a non-nil value has an association in PARMS unless it
+	     should be ignored by means of
+	     Vtooltip_reuse_hidden_frame_parameters.  */
+	  for (tail = last_parms; CONSP (tail); tail = XCDR (tail))
+	    {
+	      elt = XCAR (tail);
+	      parm = Fcar (elt);
+	      if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright)
+		  && !EQ (parm, Qbottom) && !NILP (Fcdr (elt)))
+		{
+		  /* We lost, delete the old tooltip.  */
+		  delete = true;
+		  break;
+		}
+	    }
+
+	  x_hide_tip (delete);
+	}
+      else
+	x_hide_tip (true);
+    }
+  else
+    x_hide_tip (true);

   ASET (last_show_tip_args, 0, string);
   ASET (last_show_tip_args, 1, frame);
   ASET (last_show_tip_args, 2, parms);

-  /* Add default values to frame parameters.  */
-  if (NILP (Fassq (Qname, parms)))
-    parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
-  if (NILP (Fassq (Qinternal_border_width, parms)))
-    parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
-  if (NILP (Fassq (Qborder_width, parms)))
-    parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
-  if (NILP (Fassq (Qbottom_divider_width, parms)))
-    parms = Fcons (Fcons (Qbottom_divider_width, make_number (0)), parms);
-  if (NILP (Fassq (Qright_divider_width, parms)))
-    parms = Fcons (Fcons (Qright_divider_width, make_number (0)), parms);
-  if (NILP (Fassq (Qborder_color, parms)))
-    parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
-  if (NILP (Fassq (Qbackground_color, parms)))
-    parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
-		   parms);
-
-  /* Create a frame for the tooltip, and record it in the global
-     variable tip_frame.  */
-  frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms, string);
-  f = XFRAME (frame);
-
-  /* Set up the frame's root window.  */
-  w = XWINDOW (FRAME_ROOT_WINDOW (f));
+  if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame)))
+    {
+      /* Add default values to frame parameters.  */
+      if (NILP (Fassq (Qname, parms)))
+	parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
+      if (NILP (Fassq (Qinternal_border_width, parms)))
+	parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
+      if (NILP (Fassq (Qborder_width, parms)))
+	parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
+      if (NILP (Fassq (Qborder_color, parms)))
+	parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
+      if (NILP (Fassq (Qbackground_color, parms)))
+	parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
+		       parms);
+
+      /* Create a frame for the tooltip, and record it in the global
+	 variable tip_frame.  */
+      if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms)))
+	/* Creating the tip frame failed.  */
+	return unbind_to (count, Qnil);
+    }
+
+  tip_f = XFRAME (tip_frame);
+  window = FRAME_ROOT_WINDOW (tip_f);
+  AUTO_STRING (tip, " *tip*");
+  set_window_buffer (window, Fget_buffer_create (tip), false, false);
+  w = XWINDOW (window);
+  w->pseudo_window_p = true;
+
+  /* Set up the frame's root window.  Note: The following code does not
+     try to size the window or its frame correctly.  Its only purpose is
+     to make the subsequent text size calculations work.  The right
+     sizes should get installed when the toolkit gets back to us.  */
   w->left_col = 0;
   w->top_line = 0;
   w->pixel_left = 0;
@@ -5941,130 +6063,47 @@ Text larger than the specified size is clipped.  */)
       w->total_lines = 40;
     }

-  w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (f);
-  w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (f);
-
-  FRAME_TOTAL_COLS (f) = w->total_cols;
-  adjust_frame_glyphs (f);
-  w->pseudo_window_p = true;
+  w->pixel_width = w->total_cols * FRAME_COLUMN_WIDTH (tip_f);
+  w->pixel_height = w->total_lines * FRAME_LINE_HEIGHT (tip_f);
+  FRAME_TOTAL_COLS (tip_f) = w->total_cols;
+  adjust_frame_glyphs (tip_f);

-  /* Display the tooltip text in a temporary buffer.  */
+  /* Insert STRING into root window's buffer and fit the frame to the
+     buffer.  */
+  count_1 = SPECPDL_INDEX ();
   old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->contents));
+  set_buffer_internal_1 (XBUFFER (w->contents));
   bset_truncate_lines (current_buffer, Qnil);
+  specbind (Qinhibit_read_only, Qt);
+  specbind (Qinhibit_modification_hooks, Qt);
+  specbind (Qinhibit_point_motion_hooks, Qt);
+  Ferase_buffer ();
+  Finsert (1, &string);
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
-  try_window (FRAME_ROOT_WINDOW (f), pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
-
-  /* Compute width and height of the tooltip.  */
-  width = height = 0;
-  seen_reversed_p = false;
-  for (i = 0; i < w->desired_matrix->nrows; ++i)
-    {
-      struct glyph_row *row = &w->desired_matrix->rows[i];
-      struct glyph *last;
-      int row_width;
-
-      /* Stop at the first empty row at the end.  */
-      if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-	break;
-
-      /* Let the row go over the full width of the frame.  */
-      row->full_width_p = true;
-
-      row_width = row->pixel_width;
-      if (row->used[TEXT_AREA])
-	{
-	  /* There's a glyph at the end of rows that is used to place
-	     the cursor there.  Don't include the width of this glyph.  */
-	  if (!row->reversed_p)
-	    {
-	      last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
-	      if (NILP (last->object))
-		row_width -= last->pixel_width;
-	    }
-	  else
-	    {
-	      /* There could be a stretch glyph at the beginning of R2L
-		 rows that is produced by extend_face_to_end_of_line.
-		 Don't count that glyph.  */
-	      struct glyph *g = row->glyphs[TEXT_AREA];
-
-	      if (g->type == STRETCH_GLYPH && NILP (g->object))
-		{
-		  row_width -= g->pixel_width;
-		  seen_reversed_p = true;
-		}
-	    }
-	}
-
-      height += row->height;
-      width = max (width, row_width);
-    }
-
-  /* If we've seen partial-length R2L rows, we need to re-adjust the
-     tool-tip frame width and redisplay it again, to avoid over-wide
-     tips due to the stretch glyph that extends R2L lines to full
-     width of the frame.  */
-  if (seen_reversed_p)
-    {
-      /* w->total_cols and FRAME_TOTAL_COLS want the width in columns,
-	 not in pixels.  */
-      w->pixel_width = width;
-      width /= WINDOW_FRAME_COLUMN_WIDTH (w);
-      w->total_cols = width;
-      FRAME_TOTAL_COLS (f) = width;
-      SET_FRAME_WIDTH (f, width);
-      adjust_frame_glyphs (f);
-      clear_glyph_matrix (w->desired_matrix);
-      clear_glyph_matrix (w->current_matrix);
-      try_window (FRAME_ROOT_WINDOW (f), pos, 0);
-      width = height = 0;
-      /* Recompute width and height of the tooltip.  */
-      for (i = 0; i < w->desired_matrix->nrows; ++i)
-	{
-	  struct glyph_row *row = &w->desired_matrix->rows[i];
-	  struct glyph *last;
-	  int row_width;
-
-	  if (!row->enabled_p || !MATRIX_ROW_DISPLAYS_TEXT_P (row))
-	    break;
-	  row->full_width_p = true;
-	  row_width = row->pixel_width;
-	  if (row->used[TEXT_AREA] && !row->reversed_p)
-	    {
-	      last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
-	      if (NILP (last->object))
-		row_width -= last->pixel_width;
-	    }
-
-	  height += row->height;
-	  width = max (width, row_width);
-	}
-    }
-
-  /* Add the frame's internal border to the width and height the X
-     window should have.  */
-  height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
-  width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
-
-  /* Move the tooltip window where the mouse pointer is.  Resize and
-     show it.  */
-  compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
-
+  try_window (window, pos, TRY_WINDOW_IGNORE_FONTS_CHANGE);
+  /* Calculate size of tooltip window.  */
+  size = Fwindow_text_pixel_size (window, Qnil, Qnil, Qnil,
+				  make_number (w->pixel_height), Qnil);
+  /* Add the frame's internal border to calculated size.  */
+  width = XINT (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+  height = XINT (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f);
+
+  /* Calculate position of tooltip frame.  */
+  compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y);
+
+  /* Show tooltip frame.  */
   block_input ();
-  XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+  XMoveResizeWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f),
 		     root_x, root_y, width, height);
-  XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+  XMapRaised (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f));
   unblock_input ();

-  /* Draw into the window.  */
   w->must_be_updated_p = true;
   update_single_window (w);
-
-  /* Restore original current buffer.  */
   set_buffer_internal_1 (old_buffer);
+  unbind_to (count_1, Qnil);
   windows_or_buffers_changed = old_windows_or_buffers_changed;

  start_timer:
@@ -6081,66 +6120,9 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
 Value is t if tooltip was open, nil otherwise.  */)
   (void)
 {
-  ptrdiff_t count;
-  Lisp_Object deleted, frame, timer;
-
-  /* Return quickly if nothing to do.  */
-  if (NILP (tip_timer) && NILP (tip_frame))
-    return Qnil;
-
-  frame = tip_frame;
-  timer = tip_timer;
-  tip_frame = tip_timer = deleted = Qnil;
-
-  count = SPECPDL_INDEX ();
-  specbind (Qinhibit_redisplay, Qt);
-  specbind (Qinhibit_quit, Qt);
-
-  if (!NILP (timer))
-    call1 (Qcancel_timer, timer);
-
-#ifdef USE_GTK
-  {
-    /* When using system tooltip, tip_frame is the Emacs frame on which
-       the tip is shown.  */
-    struct frame *f = XFRAME (frame);
-    if (FRAME_LIVE_P (f) && xg_hide_tooltip (f))
-      frame = Qnil;
-  }
-#endif
-
-  if (FRAMEP (frame))
-    {
-      delete_frame (frame, Qnil);
-      deleted = Qt;
-
-#ifdef USE_LUCID
-      /* Bloodcurdling hack alert: The Lucid menu bar widget's
-	 redisplay procedure is not called when a tip frame over menu
-	 items is unmapped.  Redisplay the menu manually...  */
-      {
-        Widget w;
-        struct frame *f = SELECTED_FRAME ();
-        if (FRAME_X_P (f) && FRAME_LIVE_P (f))
-          {
-          w = f->output_data.x->menubar_widget;
-
-          if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen)
-              && w != NULL)
-            {
-              block_input ();
-              xlwmenu_redisplay (w);
-              unblock_input ();
-            }
-        }
-      }
-#endif /* USE_LUCID */
-    }
-
-  return unbind_to (count, deleted);
+  return x_hide_tip (!tooltip_reuse_hidden_frame);
 }

-
 \f
 /***********************************************************************
 			File selection dialog
@@ -6802,6 +6784,7 @@ syms_of_xfns (void)
   DEFSYM (Qcancel_timer, "cancel-timer");
   DEFSYM (Qfont_param, "font-parameter");
   DEFSYM (Qmono, "mono");
+  DEFSYM (Qassq_delete_all, "assq-delete-all");

 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Tooltips GC overhead
  2016-03-06  9:21                     ` martin rudalics
@ 2016-03-08  8:02                       ` martin rudalics
  0 siblings, 0 replies; 47+ messages in thread
From: martin rudalics @ 2016-03-08  8:02 UTC (permalink / raw)
  Cc: emacs-devel

 > If nobody objects I intend to apply
 > the attached patch in the next days.

Done as commit 59c7a5d..80864c2  master -> master.

martin



^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2016-03-08  8:02 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-28 12:45 Tooltips GC overhead martin rudalics
2015-07-28 13:53 ` Eli Zaretskii
2015-07-28 15:09   ` martin rudalics
2015-07-28 23:51 ` Stefan Monnier
2015-07-29  7:18   ` martin rudalics
2015-07-29 14:29     ` Paul Eggert
2015-07-29 15:40       ` martin rudalics
2015-07-29 16:33         ` Eli Zaretskii
2015-07-29 18:05           ` martin rudalics
2015-07-29 21:15             ` Paul Eggert
2015-07-30  6:00               ` martin rudalics
2015-07-30  7:08               ` martin rudalics
2015-07-30  7:19                 ` Paul Eggert
2015-07-30  9:05                   ` martin rudalics
2015-07-30 16:36                     ` Eli Zaretskii
2015-07-30 19:53                       ` martin rudalics
2015-07-30 23:09                         ` Stefan Monnier
2015-07-30 23:33                           ` Drew Adams
2015-07-31  6:48                             ` Eli Zaretskii
2015-07-31  6:47                         ` Eli Zaretskii
2016-03-06  9:21                     ` martin rudalics
2016-03-08  8:02                       ` martin rudalics
2015-08-01 10:49               ` martin rudalics
2015-08-03 10:34                 ` Stefan Monnier
2015-08-03 14:56                   ` Eli Zaretskii
2015-08-03 21:13                     ` Stefan Monnier
2015-08-04  2:38                       ` Eli Zaretskii
2015-08-04  7:31                         ` Stefan Monnier
2015-08-04 13:28                           ` Eli Zaretskii
2015-08-07 14:52                             ` Stefan Monnier
2015-08-07 15:23                               ` Eli Zaretskii
2015-08-07 17:26                                 ` Stefan Monnier
2015-08-07 18:20                                   ` Eli Zaretskii
2015-08-07 21:25                                     ` Stefan Monnier
2015-08-08  6:46                                       ` Eli Zaretskii
2015-08-08  7:01                                         ` David Kastrup
2015-08-07 18:26                                 ` Paul Eggert
2015-08-07 18:59                                   ` Eli Zaretskii
2015-08-08 13:41                           ` Nix
2015-08-08 16:10                             ` Stefan Monnier
2015-08-08 16:13                               ` David Kastrup
2015-08-10 17:05                                 ` Nix
2015-08-10 17:44                                   ` David Kastrup
2015-07-29 16:45         ` Paul Eggert
2015-07-29 18:05           ` martin rudalics
2015-07-29 21:17             ` Paul Eggert
2015-07-30  6:00               ` martin rudalics

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.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).