bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#45224: 28.0.50; eww and GIFS (cpu usage shoots through the roof)


From: Stefan Kangas
Subject: bug#45224: 28.0.50; eww and GIFS (cpu usage shoots through the roof)
Date: Sat, 30 Oct 2021 18:54:56 -0700
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux)

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Madhavan Krishnan <krishnanmadhavan000@gmail.com> writes:
>
>> Thank you for investigating this issue, I am not entirely sure of what
>> the next step would be. Is there a sample code that I can refer to for
>> the ImageMagic version you are referring to? (to get some idea about how
>> it can be patched)
>
> imagemagick_get_animation_cache and friends in src/image.c.

I've been looking into this a bit, and here are my preliminary
conclusions.  I hope it is clear, and appreciate any feedback!

The first part of the problem is making sure that we can cache animated
images, which currently never happens.  Once that is in place, the
second part is to cache all animated images up-front.  I only discuss
the first part below.

Besides the special cache for ImageMagick we also have tho one used for
*all* images.  So my thinking is: why not use the "real" cache also for
animated images?  Why implement a specialized cache just for that?

I believe it is possible.[1]  And actually, the first question is: why
aren't they already cached?  The reason is this: in search_image_cache
(image.c:1599), we use sxhash and Fequal to compare the Lisp image
descriptor (or "image specification" or "spec" as its called in image.c)
to the one we have in cache.  But in an animated gif the image spec is
changed in image.el:

    (image :type gif
           :file "/some/file.gif"
           :scale 1
           :max-width 1248
           :max-height 1321
           :format nil
           :transform-smoothing t
           :animate-buffer "file.gif"
           :animate-tardiness 0.9810895737588246
           :animate-multi-frame-data (62 . 0.04)
           :index 61)

The value of :animate-tardiness is updated in image.el on every
iteration.  When image.el updates :animate-tardiness, it will never be
equal to something in the cache and we always get a cache miss!

I have attached a patch that will demonstrate how we get back caching by
simply disabling the updating of the image spec in image.el.  This is
completely the wrong thing to do, but demonstrates what is going on.
With that patch, caching will be enabled, and you can see it the second
time you try to run an animated gif.  (Use RET to start the animation.)

The correct fix here is to somehow *only* compare the relevant
attributes above, and ignore or leave out e.g. :animate-tardiness.

I have experimented with different approaches.  My first idea was to
create a new comparison function "image_cache_equal" that basically
only compares the attributes we are interested.  But then the problem
was that we use the "sxhash" function to find which hash bucket to
find the list in, so that didn't help much.  We would also need to
replace the sxhash with something else.  Perhaps sxhash_equal?  Hmm.

So I thought of two other ways to go about this:

A) We create a new stripped down Lisp plist containing only the
   attributes we are interested in and use that to compare against the
   cache.  We obviously need to make sure the cache also contains only
   stripped down list.  This means we can keep using Fequal and sxhash,
   but we also need to create a new list for *every cache lookup*!

B) We parse the relevant parts of the image spec into a C struct and
   then use that struct for comparisons.  It turns out we already have
   most of the code in place to do this, see parse_image_spec
   (image.c:898), so most of it should be some restructuring, and then
   writing up a comparison function.  With that in place, we would just
   need to .

Option A) seems ugly to me: why would we be consing up Lisp lists on
such a low level, which also makes me worry about creating a lot of
unnecessary garbage.  So I prefer Option B).  The struct also seems
more clean to me.  Perhaps there are some performance implications I'm
not thinking of?  Or perhaps there is some even better way to do the
cache check than a new struct, such as using the "image struct"
directly?

A third alternative is to somehow change image.el to put this
information outside the image specifier, but that leaves unfixed a
rather subtle issue with caching.  That issue may or may not bite
someone later.

Comments about all this is very welcome!  I'm basically at the point
where any approach I choose means investing a bunch of work, and it
would be useful with some feedback before I rush ahead and attempt any
of them.  Perhaps someone here has an idea or hunch about which
approach might prove more fruitful.

Footnotes:
[1] There is a comment in the ImageMagick cache saying: "We have to
     maintain a cache separate from the image cache, because the images
     may be scaled before display."  However, this was written before we
     had native image scaling, and actually it seems to me either
     incorrect, based on the above, or correct but only applicable to
     ImageMagick, or, perhaps more likely, I am missing something
     important.

Attachment: 0001-gif-load-debug.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]