changeset 108741:9480d787845f

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.
author Chong Yidong <cyd@stupidchicken.com>
date Fri, 21 May 2010 13:29:27 -0400
parents e6ab17110c0d
children 36dd9f97c404
files src/ChangeLog src/image.c src/xdisp.c
diffstat 3 files changed, 78 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Fri May 21 09:31:45 2010 -0700
+++ b/src/ChangeLog	Fri May 21 13:29:27 2010 -0400
@@ -1,3 +1,12 @@
+2010-05-21  Chong Yidong  <cyd@stupidchicken.com>
+
+	* 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  <rgm@gnu.org>
 
 	* Makefile.in (${ns_appdir}, ${ns_appbindir}Emacs, ns-app):
--- a/src/image.c	Fri May 21 09:31:45 2010 -0700
+++ b/src/image.c	Fri May 21 13:29:27 2010 -0400
@@ -1582,29 +1582,56 @@
 {
   struct image_cache *c = FRAME_IMAGE_CACHE (f);
 
-  if (c && (!NILP (filter) || INTEGERP (Vimage_cache_eviction_delay)))
-    {
-      EMACS_TIME t;
-      unsigned long old;
-      int i, nfreed;
-
-      EMACS_GET_TIME (t);
-      old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
+  if (c)
+    {
+      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 @@
   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
--- a/src/xdisp.c	Fri May 21 09:31:45 2010 -0700
+++ b/src/xdisp.c	Fri May 21 13:29:27 2010 -0400
@@ -12499,22 +12499,25 @@
   if (windows_or_buffers_changed && !pause)
     goto retry;
 
-  /* Clear the face cache eventually.  */
-  if (consider_all_windows_p)
-    {
-      if (clear_face_cache_count > CLEAR_FACE_CACHE_COUNT)
-	{
-	  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;
-	}
+  /* 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)
+    {
+      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 */
-    }
 
  end_of_redisplay:
   unbind_to (count, Qnil);