From 98fe5161c42a5ec64df3d0418f918a5ab8c909d6 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Fri, 21 May 2010 13:29:27 -0400 Subject: [PATCH] Improve image cache clearing logic (Bug#6230). * xdisp.c (redisplay_internal): Clear caches even if redisplaying just one window. * image.c (Vimage_cache_eviction_delay): Decrease to 300. (clear_image_cache): If the number of cached images is unusually large, decrease the cache eviction delay. --- src/ChangeLog | 9 +++++++ src/image.c | 70 ++++++++++++++++++++++++++++++++++++--------------- src/xdisp.c | 29 +++++++++++---------- 3 files changed, 75 insertions(+), 33 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index d74fb712e6..f0613a5740 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2010-05-21 Chong Yidong + + * xdisp.c (redisplay_internal): Clear caches even if redisplaying + just one window. + + * image.c (Vimage_cache_eviction_delay): Decrease to 300. + (clear_image_cache): If the number of cached images is unusually + large, decrease the cache eviction delay (Bug#6230). + 2010-05-21 Glenn Morris * Makefile.in (${ns_appdir}, ${ns_appbindir}Emacs, ns-app): diff --git a/src/image.c b/src/image.c index 030e06ad77..5d4f50ee85 100644 --- a/src/image.c +++ b/src/image.c @@ -1582,29 +1582,56 @@ clear_image_cache (struct frame *f, Lisp_Object filter) { struct image_cache *c = FRAME_IMAGE_CACHE (f); - if (c && (!NILP (filter) || INTEGERP (Vimage_cache_eviction_delay))) + if (c) { - EMACS_TIME t; - unsigned long old; - int i, nfreed; - - EMACS_GET_TIME (t); - old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); + int i, nfreed = 0; /* Block input so that we won't be interrupted by a SIGIO while being in an inconsistent state. */ BLOCK_INPUT; - for (i = nfreed = 0; i < c->used; ++i) + if (!NILP (filter)) + { + /* Filter image cache. */ + for (i = 0; i < c->used; ++i) + { + struct image *img = c->images[i]; + if (img && (EQ (Qt, filter) + || !NILP (Fmember (filter, img->dependencies)))) + { + free_image (f, img); + ++nfreed; + } + } + } + else if (INTEGERP (Vimage_cache_eviction_delay)) { - struct image *img = c->images[i]; - if (img != NULL - && (NILP (filter) ? img->timestamp < old - : (EQ (Qt, filter) - || !NILP (Fmember (filter, img->dependencies))))) + /* Free cache based on timestamp. */ + EMACS_TIME t; + unsigned long old; + int delay, nimages = 0; + + for (i = 0; i < c->used; ++i) + if (c->images[i]) + nimages++; + + /* If the number of cached images has grown unusually large, + decrease the cache eviction delay (Bug#6230). */ + delay = XFASTINT (Vimage_cache_eviction_delay); + if (nimages > 40) + delay = max (1, 1600 * delay / (nimages*nimages)); + + EMACS_GET_TIME (t); + old = EMACS_SECS (t) - delay; + + for (i = 0; i < c->used; ++i) { - free_image (f, img); - ++nfreed; + struct image *img = c->images[i]; + if (img && img->timestamp < old) + { + free_image (f, img); + ++nfreed; + } } } @@ -8520,11 +8547,14 @@ A cross is always drawn on black & white displays. */); Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS); DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay, - doc: /* Time after which cached images are removed from the cache. -When an image has not been displayed this many seconds, remove it -from the image cache. Value must be an integer or nil with nil -meaning don't clear the cache. */); - Vimage_cache_eviction_delay = make_number (30 * 60); + doc: /* Maximum time after which images are removed from the cache. +When an image has not been displayed this many seconds, Emacs +automatically removes it from the image cache. If the cache contains +a large number of images, the actual eviction time may be shorter. +The value can also be nil, meaning the cache is never cleared. + +The function `clear-image-cache' disregards this variable. */); + Vimage_cache_eviction_delay = make_number (300); } void diff --git a/src/xdisp.c b/src/xdisp.c index 6b3097c9a1..2ff12730b8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12499,22 +12499,25 @@ redisplay_internal (preserve_echo_area) if (windows_or_buffers_changed && !pause) goto retry; - /* Clear the face cache eventually. */ - if (consider_all_windows_p) + /* Clear the face and image caches. + + We used to do this only if consider_all_windows_p. But the cache + needs to be cleared if a timer creates images in the current + buffer (e.g. the test case in Bug#6230). */ + + if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT) { - if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT) - { - clear_face_cache (0); - clear_face_cache_count = 0; - } + clear_face_cache (0); + clear_face_cache_count = 0; + } + #ifdef HAVE_WINDOW_SYSTEM - if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT) - { - clear_image_caches (Qnil); - clear_image_cache_count = 0; - } -#endif /* HAVE_WINDOW_SYSTEM */ + if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT) + { + clear_image_caches (Qnil); + clear_image_cache_count = 0; } +#endif /* HAVE_WINDOW_SYSTEM */ end_of_redisplay: unbind_to (count, Qnil); -- 2.20.1