changeset 5170:5ddbab03b0e6

various fixes to memory-usage stats -------------------- ChangeLog entries follow: -------------------- lisp/ChangeLog addition: 2010-03-25 Ben Wing <ben@xemacs.org> * diagnose.el (show-memory-usage): * diagnose.el (show-object-memory-usage-stats): Further changes to correspond with changes in the C code; add an additional column in show-object-memory-usage-stats showing the ancillary Lisp overhead used with each type; shrink columns for windows in show-memory-usage to get it to fit in 79 chars. src/ChangeLog addition: 2010-03-25 Ben Wing <ben@xemacs.org> * alloc.c: * alloc.c (struct): * alloc.c (finish_object_memory_usage_stats): * alloc.c (object_memory_usage_stats): * alloc.c (Fobject_memory_usage): * alloc.c (lisp_object_memory_usage_full): * alloc.c (compute_memusage_stats_length): * lrecord.h: * lrecord.h (struct lrecord_implementation): Add fields to the `lrecord_implementation' structure to list an offset into the array of extra statistics in a `struct generic_usage_stats' and a length, listing the first slice of ancillary Lisp-object memory. Compute automatically in compute_memusage_stats_length(). Use to add an entry `FOO-lisp-ancillary-storage' for object type FOO. Don't crash when an int or char is given to object-memory-usage, signal an error instead. Add functions lisp_object_memory_usage_full() and lisp_object_memory_usage() to compute the total memory usage of an object (sum of object, non-Lisp attached, and Lisp ancillary memory). * array.c: * array.c (gap_array_memory_usage): * array.h: Add function to return memory usage of a gap array. * buffer.c (struct buffer_stats): * buffer.c (compute_buffer_usage): * buffer.c (vars_of_buffer): * extents.c (compute_buffer_extent_usage): * marker.c: * marker.c (compute_buffer_marker_usage): * extents.h: * lisp.h: Remove `struct usage_stats' arg from compute_buffer_marker_usage() and compute_buffer_extent_usage() -- these are ancillary Lisp objects and don't get accumulated into `struct usage_stats'; change the value of `memusage_stats_list' so that `markers' and `extents' memory is in Lisp-ancillary, where it belongs. In compute_buffer_marker_usage(), use lisp_object_memory_usage() rather than lisp_object_storage_size(). * casetab.c: * casetab.c (case_table_memory_usage): * casetab.c (vars_of_casetab): * emacs.c (main_1): Add memory usage stats for case tables. * lisp.h: Add comment explaining the `struct generic_usage_stats' more, as well as the new fields in lrecord_implementation. * console-impl.h: * console-impl.h (struct console_methods): * scrollbar-gtk.c: * scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage): * scrollbar-msw.c: * scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage): * scrollbar-x.c: * scrollbar-x.c (x_compute_scrollbar_instance_usage): * scrollbar.c: * scrollbar.c (struct scrollbar_instance_stats): * scrollbar.c (compute_all_scrollbar_instance_usage): * scrollbar.c (scrollbar_instance_memory_usage): * scrollbar.c (scrollbar_objects_create): * scrollbar.c (vars_of_scrollbar): * scrollbar.h: * symsinit.h: * window.c: * window.c (find_window_mirror_maybe): * window.c (struct window_mirror_stats): * window.c (compute_window_mirror_usage): * window.c (window_mirror_memory_usage): * window.c (compute_window_usage): * window.c (window_objects_create): * window.c (syms_of_window): * window.c (vars_of_window): Redo memory-usage associated with windows, window mirrors, and scrollbar instances. Should fix crash in find_window_mirror, among other things. Properly assign memo ry to object memory, non-Lisp extra memory, and Lisp ancillary memory. For example, redisplay structures are non-Lisp memory hanging off a window mirror, not a window; make it an ancillary Lisp-object field. Window mirrors and scrollbar instances have their own statistics, among other things.
author Ben Wing <ben@xemacs.org>
date Thu, 25 Mar 2010 06:07:25 -0500
parents 6c6d78781d59
children 8cd17b2131a1
files lisp/ChangeLog lisp/diagnose.el src/ChangeLog src/alloc.c src/array.c src/array.h src/buffer.c src/casetab.c src/console-impl.h src/emacs.c src/extents.c src/extents.h src/lisp.h src/lrecord.h src/marker.c src/scrollbar-gtk.c src/scrollbar-msw.c src/scrollbar-x.c src/scrollbar.c src/scrollbar.h src/symsinit.h src/window.c
diffstat 22 files changed, 649 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Wed Mar 24 01:22:51 2010 -0500
+++ b/lisp/ChangeLog	Thu Mar 25 06:07:25 2010 -0500
@@ -1,3 +1,12 @@
+2010-03-25  Ben Wing  <ben@xemacs.org>
+
+	* diagnose.el (show-memory-usage):
+	* diagnose.el (show-object-memory-usage-stats):
+	Further changes to correspond with changes in the C code;
+	add an additional column in show-object-memory-usage-stats showing
+	the ancillary Lisp overhead used with each type; shrink columns for
+	windows in show-memory-usage to get it to fit in 79 chars.
+
 2010-03-20  Ben Wing  <ben@xemacs.org>
 
 	* diagnose.el (show-memory-usage):
--- a/lisp/diagnose.el	Wed Mar 24 01:22:51 2010 -0500
+++ b/lisp/diagnose.el	Thu Mar 25 06:07:25 2010 -0500
@@ -35,11 +35,12 @@
   "Show statistics about memory usage of various sorts in XEmacs."
   (interactive)
   (garbage-collect)
-  (flet ((show-foo-stats (objtypename cleanfun objlist)
+  (flet ((show-foo-stats (objtypename statname-plist cleanfun objlist
+			  &optional objnamelen)
 	   (let* ((hash (make-hash-table))
 		  (first t)
-		  types fmt
-		  (objnamelen 25)
+		  types origtypes fmt
+		  (objnamelen (or objnamelen 25))
 		  (linelen objnamelen)
 		  (totaltotal 0))
 	     (loop for obj in objlist do
@@ -54,19 +55,22 @@
 		 ;; the  memory grouped by type
 		 (while (and stats (pop stats)))
 
-		 (loop for (type . num) in stats while type do
+		 (loop for (type . num) in (remq t stats) while type do
+		   (if first (push type origtypes))
+		   (setq type (getf statname-plist type type))
 		   (puthash type (+ num (or (gethash type hash) 0)) hash)
 		   (incf total num)
 		   (if first (push type types)))
 		 (incf totaltotal total)
 		 (when first
 		   (setq types (nreverse types))
+		   (setq origtypes (nreverse origtypes))
 		   (setq fmt (concat
 			      (format "%%-%ds" objnamelen)
 			      (mapconcat
 			       #'(lambda (type)
 				   (let ((fieldlen
-					  (max 8 (+ 2 (length
+					  (max 7 (+ 2 (length
 						       (symbol-name type))))))
 				     (incf linelen fieldlen)
 				     (format "%%%ds" fieldlen)))
@@ -83,7 +87,7 @@
 							     (1- objnamelen)))
 				 (nconc (mapcar #'(lambda (type)
 						    (cdr (assq type stats)))
-						types)
+						origtypes)
 					(list total)))))
 		 (setq first nil)))
 	     (princ "\n")
@@ -103,7 +107,7 @@
 	  (when-fboundp 'charset-list
 	    (setq begin (point))
 	    (incf grandtotal
-		  (show-foo-stats 'charset 'charset-name
+		  (show-foo-stats 'charset nil 'charset-name
 				  (mapcar 'get-charset (charset-list))))
 	    (when-fboundp 'sort-numeric-fields
 	      (sort-numeric-fields -1
@@ -117,7 +121,7 @@
 	    (princ "\n"))
 	  (setq begin (point))
 	  (incf grandtotal
-		(show-foo-stats 'buffer 'buffer-name (buffer-list)))
+		(show-foo-stats 'buffer nil 'buffer-name (buffer-list)))
 	  (when-fboundp 'sort-numeric-fields
 	    (sort-numeric-fields -1
 				 (save-excursion
@@ -130,11 +134,19 @@
 	  (princ "\n")
 	  (setq begin (point))
 	  (incf grandtotal
-		(show-foo-stats 'window #'(lambda (x)
-					    (buffer-name (window-buffer x)))
+		(show-foo-stats 'window
+				'(line-start-cache line-st.
+				  face-cache face
+				  glyph-cache glyph
+				  redisplay-structs redisplay
+				  scrollbar-instances scrollbar
+				  window-mirror mirror)
+				#'(lambda (x)
+				    (buffer-name (window-buffer x)))
 				(mapcan #'(lambda (fr)
 					    (window-list fr t))
-					(frame-list))))
+					(frame-list))
+				16))
           (when-fboundp #'sort-numeric-fields
             (sort-numeric-fields -1
                                  (save-excursion
@@ -152,9 +164,14 @@
 	    (princ (make-string 40 ?-))
 	    (princ "\n")
 	    (map-plist #'(lambda (stat num)
-			   (when (string-match 
-				  "\\(.*\\)-storage$"
-				  (symbol-name stat))
+			   (when (and
+				  (not
+				   (string-match 
+				    "\\(.*\\)-ancillary-storage$"
+				    (symbol-name stat)))
+				  (string-match 
+				   "\\(.*\\)-storage$"
+				   (symbol-name stat)))
 			     (incf total num)
 			     (princ (format fmt
 					    (match-string 1 (symbol-name stat))
@@ -184,12 +201,14 @@
   (garbage-collect)
   (let ((buffer "*object memory usage statistics*")
 	(plist (object-memory-usage-stats))
-	(fmt "%-30s%10s%10s%10s%18s\n")
+	(fmt "%-28s%10s%10s%10s%10s%10s\n")
 	(grandtotal 0)
 	begin)
   (flet ((show-stats (match-string)
-	(princ (format fmt "object" "count" "storage" "overhead"
-		       "non-Lisp storage"))
+	(princ (format "%28s%10s%40s\n" "" ""
+		       "--------------storage---------------"))
+	(princ (format fmt "object" "count" "object" "overhead"
+		       "non-Lisp" "ancillary"))
 	(princ (make-string 78 ?-))
 	(princ "\n")
 	(let ((total-use 0)
@@ -202,9 +221,13 @@
 	       (let ((symmatch
 		      (and (string-match match-string (symbol-name stat))
 			   (match-string 1 (symbol-name stat)))))
-		 (when (and symmatch (or (< (length symmatch) 9)
-					 (not (equal (substring symmatch -9)
-						     "-non-lisp"))))
+		 (when (and symmatch
+			    (or (< (length symmatch) 9)
+				(not (equal (substring symmatch -9)
+					    "-non-lisp")))
+			    (or (< (length symmatch) 15)
+				(not (equal (substring symmatch -15)
+					    "-lisp-ancillary"))))
 		   (let* ((storage-use num)
 			  (storage-use-overhead
 			   (or (plist-get 
@@ -227,6 +250,12 @@
 				(intern (concat symmatch
 						"-non-lisp-storage")))
 			       0))
+			  (lisp-ancillary-storage
+			   (or (plist-get
+				plist
+				(intern (concat symmatch
+						"-lisp-ancillary-storage")))
+			       0))
 			  (storage-count 
 			   (or (loop for str in '("s-used" "es-used" "-used")
 				 for val = (plist-get
@@ -251,19 +280,20 @@
 					 (or storage-count "unknown")
 					 storage-use
 					 storage-use-overhead
-					 non-lisp-storage)))))))
+					 non-lisp-storage
+					 lisp-ancillary-storage)))))))
 	   plist)
 	  (princ "\n")
 	  (princ (format fmt "total" 
 			 total-count total-use total-use-overhead
-			 total-non-lisp-use))
+			 total-non-lisp-use ""))
 	  (incf grandtotal total-use-with-overhead)
 	  (incf grandtotal total-non-lisp-use)
           (when-fboundp #'sort-numeric-fields
-            (sort-numeric-fields -3
+            (sort-numeric-fields -4
                                  (save-excursion
                                    (goto-char begin)
-                                   (forward-line 3)
+                                   (forward-line 4)
                                    (point))
                                  (save-excursion
                                    (forward-line -2)
--- a/src/ChangeLog	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/ChangeLog	Thu Mar 25 06:07:25 2010 -0500
@@ -1,3 +1,95 @@
+2010-03-25  Ben Wing  <ben@xemacs.org>
+
+	* alloc.c:
+	* alloc.c (struct):
+	* alloc.c (finish_object_memory_usage_stats):
+	* alloc.c (object_memory_usage_stats):
+	* alloc.c (Fobject_memory_usage):
+	* alloc.c (lisp_object_memory_usage_full):
+	* alloc.c (compute_memusage_stats_length):
+	* lrecord.h:
+	* lrecord.h (struct lrecord_implementation):
+	Add fields to the `lrecord_implementation' structure to list an
+	offset into the array of extra statistics in a
+	`struct generic_usage_stats' and a length, listing the first slice
+	of ancillary Lisp-object memory.  Compute automatically in
+	compute_memusage_stats_length().  Use to add an entry
+	`FOO-lisp-ancillary-storage' for object type FOO.
+
+	Don't crash when an int or char is given to object-memory-usage,
+	signal an error instead.
+
+	Add functions lisp_object_memory_usage_full() and
+	lisp_object_memory_usage() to compute the total memory usage of an
+	object (sum of object, non-Lisp attached, and Lisp ancillary
+	memory).
+	
+	* array.c:
+	* array.c (gap_array_memory_usage):
+	* array.h:
+	Add function to return memory usage of a gap array.
+	
+	* buffer.c (struct buffer_stats):
+	* buffer.c (compute_buffer_usage):
+	* buffer.c (vars_of_buffer):
+	* extents.c (compute_buffer_extent_usage):
+	* marker.c:
+	* marker.c (compute_buffer_marker_usage):
+	* extents.h:
+	* lisp.h:
+	Remove `struct usage_stats' arg from compute_buffer_marker_usage()
+	and compute_buffer_extent_usage() -- these are ancillary Lisp
+	objects and don't get accumulated into `struct usage_stats';
+	change the value of `memusage_stats_list' so that `markers' and
+	`extents' memory is in Lisp-ancillary, where it belongs.
+
+	In compute_buffer_marker_usage(), use lisp_object_memory_usage()
+	rather than lisp_object_storage_size().
+	
+	* casetab.c:
+	* casetab.c (case_table_memory_usage):
+	* casetab.c (vars_of_casetab):
+	* emacs.c (main_1):
+	Add memory usage stats for case tables.
+	
+	* lisp.h:
+	Add comment explaining the `struct generic_usage_stats' more,
+	as well as the new fields in lrecord_implementation.
+
+	* console-impl.h:
+	* console-impl.h (struct console_methods):
+	* scrollbar-gtk.c:
+	* scrollbar-gtk.c (gtk_compute_scrollbar_instance_usage):
+	* scrollbar-msw.c:
+	* scrollbar-msw.c (mswindows_compute_scrollbar_instance_usage):
+	* scrollbar-x.c:
+	* scrollbar-x.c (x_compute_scrollbar_instance_usage):
+	* scrollbar.c:
+	* scrollbar.c (struct scrollbar_instance_stats):
+	* scrollbar.c (compute_all_scrollbar_instance_usage):
+	* scrollbar.c (scrollbar_instance_memory_usage):
+	* scrollbar.c (scrollbar_objects_create):
+	* scrollbar.c (vars_of_scrollbar):
+	* scrollbar.h:
+	* symsinit.h:
+	* window.c:
+	* window.c (find_window_mirror_maybe):
+	* window.c (struct window_mirror_stats):
+	* window.c (compute_window_mirror_usage):
+	* window.c (window_mirror_memory_usage):
+	* window.c (compute_window_usage):
+	* window.c (window_objects_create):
+	* window.c (syms_of_window):
+	* window.c (vars_of_window):
+	Redo memory-usage associated with windows, window mirrors, and
+	scrollbar instances.  Should fix crash in find_window_mirror,
+	among other things.  Properly assign memo ry to object memory,
+	non-Lisp extra memory, and Lisp ancillary memory.  For example,
+	redisplay structures are non-Lisp memory hanging off a window
+	mirror, not a window; make it an ancillary Lisp-object field.
+	Window mirrors and scrollbar instances have their own statistics,
+	among other things.
+	 
 2010-03-24  Ben Wing  <ben@xemacs.org>
 
 	* array.h:
@@ -6,7 +98,7 @@
 	* dumper.c (pdump_store_new_pointer_offsets):
 	* dumper.c (pdump_reloc_one_mc):
 	* elhash.c:
-	* gc.c (lispdesc_one_description_line_size):
+	* gc.c  (lispdesc_one_description_line_size):
 	* gc.c (kkcc_marking):
 	* lrecord.h:
 	* lrecord.h (IF_NEW_GC):
--- a/src/alloc.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/alloc.c	Thu Mar 25 06:07:25 2010 -0500
@@ -177,6 +177,7 @@
   Bytecount bytes_on_free_list_overhead;
 #ifdef MEMORY_USAGE_STATS
   Bytecount nonlisp_bytes_in_use;
+  Bytecount lisp_ancillary_bytes_in_use;
   struct generic_usage_stats stats;
 #endif
 } lrecord_stats [countof (lrecord_implementations_table)];
@@ -3888,6 +3889,14 @@
 	    lrecord_stats[i].nonlisp_bytes_in_use +=
 	      lrecord_stats[i].stats.othervals[j];
 	}
+      if (imp && imp->num_extra_lisp_ancillary_memusage_stats)
+	{
+	  int j;
+	  for (j = 0; j < imp->num_extra_lisp_ancillary_memusage_stats; j++)
+	    lrecord_stats[i].lisp_ancillary_bytes_in_use +=
+	      lrecord_stats[i].stats.othervals
+	      [j + imp->offset_lisp_ancillary_memusage_stats];
+	}
     }
 #endif /* defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) */
 }
@@ -4041,6 +4050,14 @@
 				  pl);
 	      tgu_val += lrecord_stats[i].nonlisp_bytes_in_use;
 	    }
+	  if (lrecord_stats[i].lisp_ancillary_bytes_in_use)
+	    {
+	      sprintf (buf, "%s-lisp-ancillary-storage", name);
+	      pl = gc_plist_hack (buf, lrecord_stats[i].
+				  lisp_ancillary_bytes_in_use,
+				  pl);
+	      tgu_val += lrecord_stats[i].lisp_ancillary_bytes_in_use;
+	    }
 #endif /* MEMORY_USAGE_STATS */
 	  pluralize_and_append (buf, name, "-freed");
           if (lrecord_stats[i].instances_freed != 0)
@@ -4175,7 +4192,13 @@
   struct usage_stats object_stats;
   int i;
   Lisp_Object val = Qnil;
-  Lisp_Object stats_list = OBJECT_PROPERTY (object, memusage_stats_list);
+  Lisp_Object stats_list;
+
+  if (INTP (object) || CHARP (object))
+    invalid_argument ("No memory associated with immediate objects (int or char)",
+		      object);
+
+  stats_list = OBJECT_PROPERTY (object, memusage_stats_list);
 
   xzero (object_stats);
   lisp_object_storage_size (object, &object_stats);
@@ -4223,6 +4246,80 @@
   return Fnreverse (val);
 }
 
+/* Compute total memory usage associated with an object, including
+
+   (a) Storage (including overhead) allocated to the object itself
+   (b) Storage (including overhead) for ancillary non-Lisp structures attached
+       to the object
+   (c) Storage (including overhead) for ancillary Lisp objects attached
+       to the object
+
+   Store the three types of memory into the return values provided they
+   aren't NULL, and return a sum of the three values.  Also store the
+   structure of individual statistics into STATS if non-zero.
+
+   Note that the value for type (c) is the sum of all three types of
+   memory associated with the ancillary Lisp objects.
+*/
+
+Bytecount
+lisp_object_memory_usage_full (Lisp_Object object, Bytecount *storage_size,
+			       Bytecount *extra_nonlisp_storage,
+			       Bytecount *extra_lisp_ancillary_storage,
+			       struct generic_usage_stats *stats)
+{
+  Bytecount total;
+  struct lrecord_implementation *imp = XRECORD_LHEADER_IMPLEMENTATION (object);
+
+  total = lisp_object_storage_size (object, NULL);
+  if (storage_size)
+    *storage_size = total;
+
+  if (HAS_OBJECT_METH_P (object, memory_usage))
+    {
+      int i;
+      struct generic_usage_stats gustats;
+      Bytecount sum;
+
+      xzero (gustats);
+      OBJECT_METH (object, memory_usage, (object, &gustats));
+
+      if (stats)
+	*stats = gustats;
+
+      sum = 0;
+      for (i = 0; i < imp->num_extra_nonlisp_memusage_stats; i++)
+	sum += gustats.othervals[i];
+      total += sum;
+      if (extra_nonlisp_storage)
+	*extra_nonlisp_storage = sum;
+
+      sum = 0;
+      for (i = 0; i < imp->num_extra_lisp_ancillary_memusage_stats; i++)
+	sum += gustats.othervals[imp->offset_lisp_ancillary_memusage_stats +
+				 i];
+      total += sum;
+      if (extra_lisp_ancillary_storage)
+	*extra_lisp_ancillary_storage = sum;
+    }
+  else
+    {
+      if (extra_nonlisp_storage)
+	*extra_nonlisp_storage = 0;
+      if (extra_lisp_ancillary_storage)
+	*extra_lisp_ancillary_storage = 0;
+    }
+
+  return total;
+}
+
+
+Bytecount
+lisp_object_memory_usage (Lisp_Object object)
+{
+  return lisp_object_memory_usage_full (object, NULL, NULL, NULL, NULL);
+}
+
 #endif /* MEMORY_USAGE_STATS */
 
 #ifdef ALLOC_TYPE_STATS
@@ -4258,10 +4355,6 @@
 
   for (i = 0; i < countof (lrecord_implementations_table); i++)
     {
-      int len = 0;
-      int nonlisp_len = 0;
-      int seen_break = 0;
-
       struct lrecord_implementation *imp = lrecord_implementations_table[i];
 
       if (!imp)
@@ -4272,21 +4365,44 @@
       if (EQ (imp->memusage_stats_list, Qnull_pointer))
 	imp->memusage_stats_list = Qnil;
       {
+	Elemcount len = 0;
+	Elemcount nonlisp_len = 0;
+	Elemcount lisp_len = 0;
+	Elemcount lisp_offset = 0;
+	int group_num = 0;
+	int slice_num = 0;
+
 	LIST_LOOP_2 (item, imp->memusage_stats_list)
 	  {
-	    if (!NILP (item) && !EQ (item, Qt))
+	    if (EQ (item, Qt))
 	      {
-		len++;
-		if (!seen_break)
-		  nonlisp_len++;
+		group_num++;
+		if (group_num == 1)
+		  lisp_offset = len;
+		slice_num = 0;
+	      }
+	    else if (EQ (item, Qnil))
+	      {
+		slice_num++;
 	      }
 	    else
-	      seen_break++;
+	      {
+		if (slice_num == 0)
+		  {
+		    if (group_num == 0)
+		      nonlisp_len++;
+		    else if (group_num == 1)
+		      lisp_len++;
+		  }
+		len++;
+	      }
 	  }
+
+	imp->num_extra_memusage_stats = len;
+	imp->num_extra_nonlisp_memusage_stats = nonlisp_len;
+	imp->num_extra_lisp_ancillary_memusage_stats = lisp_len;
+	imp->offset_lisp_ancillary_memusage_stats = lisp_offset;
       }
-
-      imp->num_extra_memusage_stats = len;
-      imp->num_extra_nonlisp_memusage_stats = nonlisp_len;
     }
 }
 
--- a/src/array.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/array.c	Thu Mar 25 06:07:25 2010 -0500
@@ -940,6 +940,59 @@
 }
 #endif /* not NEW_GC */
 
+#ifdef MEMORY_USAGE_STATS
+
+/* Return memory usage for gap array GA.  The returned value is the total
+   amount of bytes actually being used for the gap array, including all
+   overhead.  The extra amount of space in the gap array that is used
+   for the gap is counted in GAP_OVERHEAD, not in WAS_REQUESTED.
+   If NEW_GC, space for gap-array markers is returned through MARKER_ANCILLARY;
+   otherwise it's added into the gap array usage. */
+
+Bytecount
+gap_array_memory_usage (Gap_Array *ga, struct usage_stats *stats,
+			Bytecount *marker_ancillary)
+{
+  Bytecount total = 0;
+
+  /* We have to be a bit tricky here because not all of the
+     memory that malloc() will claim as "requested" was actually
+     requested -- some of it makes up the gap. */
+
+  Bytecount size = gap_array_byte_size (ga);
+  Bytecount gap_size = ga->gapsize * ga->elsize;
+  Bytecount malloc_used = malloced_storage_size (ga, size, 0);
+  total += malloc_used;
+  stats->was_requested += size - gap_size;
+  stats->gap_overhead += gap_size;
+  stats->malloc_overhead += malloc_used - size;
+
+#ifdef NEW_GC
+  {
+    Bytecount marker_usage = 0;
+    Gap_Array_Marker *p;
+
+    for (p = ga->markers; p; p = p->next)
+      marker_usage += lisp_object_memory_usage (wrap_gap_array_marker (p));
+    if (marker_ancillary)
+      *marker_ancillary = marker_usage;
+  }
+#else
+  {
+    Gap_Array_Marker *p;
+
+    for (p = ga->markers; p; p = p->next)
+      total += malloced_storage_size (p, sizeof (p), stats);
+    if (marker_ancillary)
+      *marker_ancillary = 0;
+  }
+#endif /* (not) NEW_GC */
+  
+  return total;
+}
+
+#endif /* MEMORY_USAGE_STATS */
+
 
 /*****************************************************************************/
 /*                              Initialization                               */
--- a/src/array.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/array.h	Thu Mar 25 06:07:25 2010 -0500
@@ -763,5 +763,7 @@
 Gap_Array *make_gap_array (Elemcount elsize, int USED_IF_NEW_GC (do_lisp));
 Gap_Array *gap_array_clone (Gap_Array *ga);
 void free_gap_array (Gap_Array *ga);
+Bytecount gap_array_memory_usage (Gap_Array *ga, struct usage_stats *stats,
+				  Bytecount *marker_ancillary);
 
 #endif /* INCLUDED_array_h_ */
--- a/src/buffer.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/buffer.c	Thu Mar 25 06:07:25 2010 -0500
@@ -1754,6 +1754,7 @@
 {
   struct usage_stats u;
   Bytecount text;
+  /* Ancillary Lisp */
   Bytecount markers;
   Bytecount extents;
 };
@@ -1787,8 +1788,8 @@
 		      struct usage_stats *ustats)
 {
   stats->text    += compute_buffer_text_usage   (b, ustats);
-  stats->markers += compute_buffer_marker_usage (b, ustats);
-  stats->extents += compute_buffer_extent_usage (b, ustats);
+  stats->markers += compute_buffer_marker_usage (b);
+  stats->extents += compute_buffer_extent_usage (b);
 }
 
 static void
@@ -1976,7 +1977,7 @@
   /* This function can GC */
 #ifdef MEMORY_USAGE_STATS
   OBJECT_HAS_PROPERTY
-    (buffer, memusage_stats_list, list3 (Qtext, Qmarkers, Qextents));
+    (buffer, memusage_stats_list, list4 (Qtext, Qt, Qmarkers, Qextents));
 #endif /* MEMORY_USAGE_STATS */
 
   staticpro (&QSFundamental);
--- a/src/casetab.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/casetab.c	Thu Mar 25 06:07:25 2010 -0500
@@ -508,6 +508,38 @@
 }
 
 
+#ifdef MEMORY_USAGE_STATS
+
+struct case_table_stats
+{
+  struct usage_stats u;
+  /* Ancillary Lisp */
+  Bytecount downcase, upcase, case_canon, case_eqv;
+};
+
+static void
+case_table_memory_usage (Lisp_Object casetab,
+			 struct generic_usage_stats *gustats)
+{
+  struct case_table_stats *stats = (struct case_table_stats *) gustats;
+
+  stats->downcase = lisp_object_memory_usage (XCASE_TABLE_DOWNCASE (casetab));
+  stats->upcase = lisp_object_memory_usage (XCASE_TABLE_UPCASE (casetab));
+  stats->case_canon = lisp_object_memory_usage (XCASE_TABLE_CANON (casetab));
+  stats->case_eqv = lisp_object_memory_usage (XCASE_TABLE_EQV (casetab));
+}
+
+#endif /* MEMORY_USAGE_STATS */
+
+
+void
+casetab_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (case_table, memory_usage);
+#endif
+}
+
 void
 syms_of_casetab (void)
 {
@@ -530,6 +562,19 @@
 }
 
 void
+vars_of_casetab (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY (case_table, memusage_stats_list,
+		       list5 (Qt,
+			      intern ("downcase"),
+			      intern ("upcase"),
+			      intern ("case-canon"),
+			      intern ("case-eqv")));
+#endif /* MEMORY_USAGE_STATS */
+}
+
+void
 complex_vars_of_casetab (void)
 {
   REGISTER Ichar i;
--- a/src/console-impl.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/console-impl.h	Thu Mar 25 06:07:25 2010 -0500
@@ -1,5 +1,5 @@
 /* Define console object for XEmacs.
-   Copyright (C) 1996, 2002, 2003, 2005 Ben Wing
+   Copyright (C) 1996, 2002, 2003, 2005, 2010 Ben Wing
 
 This file is part of XEmacs.
 
@@ -290,9 +290,10 @@
 						   scrollbar_instance *);
   void (*scrollbar_pointer_changed_in_window_method) (struct window *w);
 #ifdef MEMORY_USAGE_STATS
-  int (*compute_scrollbar_instance_usage_method) (struct device *,
-						  struct scrollbar_instance *,
-						  struct usage_stats *);
+  Bytecount (*compute_scrollbar_instance_usage_method)
+    (struct device *,
+     struct scrollbar_instance *,
+     struct usage_stats *);
 #endif
   /* Paint the window's deadbox, a rectangle between window
      borders and two short edges of both scrollbars. */
--- a/src/emacs.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/emacs.c	Thu Mar 25 06:07:25 2010 -0500
@@ -1763,6 +1763,7 @@
       )
     {
       buffer_objects_create ();
+      casetab_objects_create ();
       extent_objects_create ();
       face_objects_create ();
       frame_objects_create ();
@@ -1772,6 +1773,9 @@
 #ifdef MULE
       mule_charset_objects_create ();
 #endif
+#ifdef HAVE_SCROLLBARS
+      scrollbar_objects_create ();
+#endif
 #ifdef HAVE_GTK
       ui_gtk_objects_create ();
 #endif
@@ -2094,6 +2098,7 @@
       vars_of_buffer ();
       vars_of_bytecode ();
       vars_of_callint ();
+      vars_of_casetab ();
       vars_of_chartab ();
       vars_of_cmdloop ();
       vars_of_cmds ();
--- a/src/extents.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/extents.c	Thu Mar 25 06:07:25 2010 -0500
@@ -7003,9 +7003,8 @@
 
 #ifdef MEMORY_USAGE_STATS
 
-int
-compute_buffer_extent_usage (struct buffer *UNUSED (b),
-			     struct usage_stats *UNUSED (ustats))
+Bytecount
+compute_buffer_extent_usage (struct buffer *UNUSED (b))
 {
   /* #### not yet written */
   return 0;
--- a/src/extents.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/extents.h	Thu Mar 25 06:07:25 2010 -0500
@@ -218,8 +218,7 @@
 #endif
 
 #ifdef MEMORY_USAGE_STATS
-int compute_buffer_extent_usage (struct buffer *b,
-				 struct usage_stats *ustats);
+Bytecount compute_buffer_extent_usage (struct buffer *b);
 #endif
 
 #endif /* INCLUDED_extents_h_ */
--- a/src/lisp.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/lisp.h	Thu Mar 25 06:07:25 2010 -0500
@@ -1619,6 +1619,18 @@
   Bytecount gap_overhead;
 };
 
+/* Generic version of usage stats structure including extra non-Lisp and
+   Lisp storage associated with the object, but not including the memory
+   used to hold the object itself.  Up to 32 statistics are allowed,
+   in addition to the statistics in `U', which store another slice onto the
+   ancillary non-Lisp storage.
+
+   Normally, each object creates its own version of this structure, e.g.
+   `struct window_stats', which parallels the structure in beginning with
+   a `struct usage_stats' and followed by Bytecount fields, so that a
+   pointer to that structure can be cast to a pointer of this structure
+   and sensible results gotten. */
+
 struct generic_usage_stats
 {
   struct usage_stats u;
@@ -5334,7 +5346,7 @@
 Lisp_Object noseeum_copy_marker (Lisp_Object, Lisp_Object);
 Lisp_Object set_marker_restricted (Lisp_Object, Lisp_Object, Lisp_Object);
 #ifdef MEMORY_USAGE_STATS
-Bytecount compute_buffer_marker_usage (struct buffer *, struct usage_stats *);
+Bytecount compute_buffer_marker_usage (struct buffer *b);
 #endif
 void init_buffer_markers (struct buffer *b);
 void uninit_buffer_markers (struct buffer *b);
--- a/src/lrecord.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/lrecord.h	Thu Mar 25 06:07:25 2010 -0500
@@ -514,8 +514,8 @@
 
   /**********************************************************************/
   /* Remaining stuff is not assignable statically using
-     DEFINE_*_LISP_OBJECT, but must be assigned with OBJECT_HAS_METHOD
-     or the like. */
+     DEFINE_*_LISP_OBJECT, but must be assigned with OBJECT_HAS_METHOD,
+     OBJECT_HAS_PROPERTY or the like. */
 
   /* These functions allow any object type to have builtin property
      lists that can be manipulated from the lisp level with
@@ -542,34 +542,73 @@
 
 #ifdef MEMORY_USAGE_STATS
   /* Return memory-usage information about the object in question, stored
-     into STATS. */
-  void (*memory_usage) (Lisp_Object obj, struct generic_usage_stats *stats);
+     into STATS.
 
-  /* Number of additional type-specific statistics related to memory usage.
-     Automatically calculated (see compute_memusage_stats_length()) based
-     on the value placed in `memusage_stats_list'. */
-  Elemcount num_extra_memusage_stats;
+     Two types of information are stored: storage (including overhead) for
+     ancillary non-Lisp structures attached to the object, and storage
+     (including overhead) for ancillary Lisp objects attached to the
+     object.  The third type of memory-usage information (storage for the
+     object itself) is not noted here, because it's computed automatically
+     by the calling function.  Also, the computed storage for ancillary
+     Lisp objects is the sum of all three source of memory associated with
+     the Lisp object: the object itself, ancillary non-Lisp structures and
+     ancillary Lisp objects.  Note also that the `struct usage_stats u' at
+     the beginning of the STATS structure is for ancillary non-Lisp usage
+     *ONLY*; do not store any memory into it related to ancillary Lisp
+     objects.
 
-  /* Number of additional type-specific statistics related to
-     non-Lisp-Object memory usage for this object.  Automatically
-     calculated (see compute_memusage_stats_length()) based on the value
-     placed in `memusage_stats_list'. */
-  Elemcount num_extra_nonlisp_memusage_stats;
+     Note that it may be subjective which Lisp objects are considered
+     "attached" to the object.  Some guidelines:
+
+     -- Lisp objects which are "internal" to the main object and not
+        accessible except through the main object should be included
+     -- Objects linked by a weak reference should *NOT* be included
+  */
+  void (*memory_usage) (Lisp_Object obj, struct generic_usage_stats *stats);
 
   /* List of tags to be given to the extra statistics, one per statistic.
      Qnil or Qt can be present to separate off different slices.  Qnil
-     separates different slices within the same type of statistics.
-     Qt separates slices corresponding to different types of statistics.
+     separates different slices within the same group of statistics.
+     These represent different ways of partitioning the same memory space.
+     Qt separates different groups; these represent different spaces of
+     memory.
+
      If Qt is not present, all slices describe extra non-Lisp-Object memory
-     associated with a Lisp object.  If Qt is present, slices after Qt
-     describe non-Lisp-Object memory and slices before Qt describe
-     Lisp-Object memory logically associated with the object.  For example,
-     if the object is a table, then Lisp-Object memory might be the entries
-     in the table.  This info is only advisory since it will duplicate
-     memory described elsewhere and since it may not be possible to be
-     completely accurate if the same object occurs multiple times in the
-     table. */
+     associated with a Lisp object.  If Qt is present, slices before Qt
+     describe non-Lisp-Object memory, as before, and slices after Qt
+     describe ancillary Lisp-Object memory logically associated with the
+     object.  For example, if the object is a table, then ancillary
+     Lisp-Object memory might be the entries in the table.  This info is
+     only advisory since it will duplicate memory described elsewhere and
+     since it may not be possible to be completely accurate, e.g. it may
+     not be clear what to count in "ancillary objects", and the value may
+     be too high if the same object occurs multiple times in the table. */
   Lisp_Object memusage_stats_list;
+
+  /* --------------------------------------------------------------------- */
+
+  /* The following are automatically computed based on the value in
+     `memusage_stats_list' (see compute_memusage_stats_length()). */
+
+  /* Total number of additional type-specific statistics related to memory
+     usage. */
+  Elemcount num_extra_memusage_stats;
+
+  /* Number of additional type-specific statistics belonging to the first
+     slice of the group describing non-Lisp-Object memory usage for this
+     object.  These stats occur starting at offset 0. */
+  Elemcount num_extra_nonlisp_memusage_stats;
+
+  /* The offset into the extra statistics at which the Lisp-Object
+     memory-usage statistics begin. */
+  Elemcount offset_lisp_ancillary_memusage_stats;
+
+  /* Number of additional type-specific statistics belonging to the first
+     slice of the group describing Lisp-Object memory usage for this
+     object.  These stats occur starting at offset
+     `offset_lisp_ancillary_memusage_stats'. */
+  Elemcount num_extra_lisp_ancillary_memusage_stats;
+
 #endif /* MEMORY_USAGE_STATS */
 };
 
@@ -2040,6 +2079,12 @@
 MODULE_API void zero_nonsized_lisp_object (Lisp_Object obj);
 Bytecount lisp_object_storage_size (Lisp_Object obj,
 				    struct usage_stats *ustats);
+Bytecount lisp_object_memory_usage_full (Lisp_Object object,
+					 Bytecount *storage_size,
+					 Bytecount *extra_nonlisp_storage,
+					 Bytecount *extra_lisp_storage,
+					 struct generic_usage_stats *stats);
+Bytecount lisp_object_memory_usage (Lisp_Object object);
 void free_normal_lisp_object (Lisp_Object obj);
 
 
--- a/src/marker.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/marker.c	Thu Mar 25 06:07:25 2010 -0500
@@ -493,13 +493,13 @@
 #ifdef MEMORY_USAGE_STATS
 
 Bytecount
-compute_buffer_marker_usage (struct buffer *b, struct usage_stats *ustats)
+compute_buffer_marker_usage (struct buffer *b)
 {
   Lisp_Marker *m;
   Bytecount total = 0;
 
   for (m = BUF_MARKERS (b); m; m = m->next)
-    total += lisp_object_storage_size (wrap_marker (m), ustats);
+    total += lisp_object_memory_usage (wrap_marker (m));
   return total;
 }
 
--- a/src/scrollbar-gtk.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/scrollbar-gtk.c	Thu Mar 25 06:07:25 2010 -0500
@@ -476,23 +476,15 @@
 }
 
 #ifdef MEMORY_USAGE_STATS
-static int
+static Bytecount
 gtk_compute_scrollbar_instance_usage (struct device *UNUSED (d),
 				      struct scrollbar_instance *inst,
 				      struct usage_stats *ustats)
 {
-  int total = 0;
+  struct gtk_scrollbar_data *data =
+    (struct gtk_scrollbar_data *) inst->scrollbar_data;
 
-  while (inst)
-    {
-      struct gtk_scrollbar_data *data =
-	(struct gtk_scrollbar_data *) inst->scrollbar_data;
-
-      total += malloced_storage_size (data, sizeof (*data), ustats);
-      inst = inst->next;
-    }
-
-  return total;
+  return malloced_storage_size (data, sizeof (*data), ustats);
 }
 
 #endif /* MEMORY_USAGE_STATS */
--- a/src/scrollbar-msw.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/scrollbar-msw.c	Thu Mar 25 06:07:25 2010 -0500
@@ -424,23 +424,15 @@
 
 #ifdef MEMORY_USAGE_STATS
 
-static int
+static Bytecount
 mswindows_compute_scrollbar_instance_usage (struct device *UNUSED (d),
 					    struct scrollbar_instance *inst,
 					    struct usage_stats *ustats)
 {
-  int total = 0;
+  struct mswindows_scrollbar_data *data =
+    (struct mswindows_scrollbar_data *) inst->scrollbar_data;
 
-  while (inst)
-    {
-      struct mswindows_scrollbar_data *data =
-	(struct mswindows_scrollbar_data *) inst->scrollbar_data;
-
-      total += malloced_storage_size (data, sizeof (*data), ustats);
-      inst = inst->next;
-    }
-
-  return total;
+  return malloced_storage_size (data, sizeof (*data), ustats);
 }
 
 #endif /* MEMORY_USAGE_STATS */
--- a/src/scrollbar-x.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/scrollbar-x.c	Thu Mar 25 06:07:25 2010 -0500
@@ -698,23 +698,18 @@
 
 #ifdef MEMORY_USAGE_STATS
 
-static int
+static Bytecount
 x_compute_scrollbar_instance_usage (struct device *UNUSED (d),
 				    struct scrollbar_instance *inst,
 				    struct usage_stats *ustats)
 {
-  int total = 0;
+  Bytecount total = 0;
+  struct x_scrollbar_data *data =
+    (struct x_scrollbar_data *) inst->scrollbar_data;
 
-  while (inst)
-    {
-      struct x_scrollbar_data *data =
-	(struct x_scrollbar_data *) inst->scrollbar_data;
-
-      total += malloced_storage_size (data, sizeof (*data), ustats);
-      total += malloced_storage_size (data->name, 1 + strlen (data->name),
-				      ustats);
-      inst = inst->next;
-    }
+  total += malloced_storage_size (data, sizeof (*data), ustats);
+  total += malloced_storage_size (data->name, 1 + strlen (data->name),
+				  ustats);
 
   return total;
 }
--- a/src/scrollbar.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/scrollbar.c	Thu Mar 25 06:07:25 2010 -0500
@@ -257,26 +257,43 @@
 
 #ifdef MEMORY_USAGE_STATS
 
-int
-compute_scrollbar_instance_usage (struct device *d,
-				  struct scrollbar_instance *inst,
-				  struct usage_stats *ustats)
+struct scrollbar_instance_stats
 {
-  int total = 0;
+  struct usage_stats u;
+  Bytecount device_data;
+};
 
-  if (HAS_DEVMETH_P(d, compute_scrollbar_instance_usage))
-    total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst, ustats));
+Bytecount
+compute_all_scrollbar_instance_usage (struct scrollbar_instance *inst)
+{
+  Bytecount total = 0;
 
   while (inst)
     {
-      total += lisp_object_storage_size (wrap_scrollbar_instance (inst),
-					 ustats);
+      total += lisp_object_memory_usage (wrap_scrollbar_instance (inst));
       inst = inst->next;
     }
 
   return total;
 }
 
+static void
+scrollbar_instance_memory_usage (Lisp_Object scrollbar_instance,
+				 struct generic_usage_stats *gustats)
+{
+  struct scrollbar_instance_stats *stats =
+    (struct scrollbar_instance_stats *) gustats;
+  struct scrollbar_instance *inst = XSCROLLBAR_INSTANCE (scrollbar_instance);
+  struct device *d = FRAME_XDEVICE (inst->mirror->frame);
+  Bytecount total = 0;
+
+  if (HAS_DEVMETH_P (d, compute_scrollbar_instance_usage))
+    total += DEVMETH (d, compute_scrollbar_instance_usage, (d, inst,
+							    &gustats->u));
+
+  stats->device_data = total;
+}
+
 #endif /* MEMORY_USAGE_STATS */
 
 void
@@ -924,6 +941,13 @@
 /************************************************************************/
 
 void
+scrollbar_objects_create (void)
+{
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_METHOD (scrollbar_instance, memory_usage);
+#endif
+}
+void
 syms_of_scrollbar (void)
 {
   INIT_LISP_OBJECT (scrollbar_instance);
@@ -962,6 +986,12 @@
 void
 vars_of_scrollbar (void)
 {
+#ifdef MEMORY_USAGE_STATS
+  OBJECT_HAS_PROPERTY
+    (scrollbar_instance, memusage_stats_list,
+     list1 (intern ("device-data")));
+#endif /* MEMORY_USAGE_STATS */
+
   DEFVAR_LISP ("scrollbar-pointer-glyph", &Vscrollbar_pointer_glyph /*
 *The shape of the mouse-pointer when over a scrollbar.
 This is a glyph; use `set-glyph-image' to change it.
--- a/src/scrollbar.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/scrollbar.h	Thu Mar 25 06:07:25 2010 -0500
@@ -1,5 +1,6 @@
 /* Define scrollbar instance.
    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
+   Copyright (C) 2010 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -65,9 +66,8 @@
 			       struct window_mirror *mirror,
 			       int active, int horiz_only);
 #ifdef MEMORY_USAGE_STATS
-int compute_scrollbar_instance_usage (struct device *d,
-				      struct scrollbar_instance *inst,
-				      struct usage_stats *ustats);
+Bytecount compute_all_scrollbar_instance_usage (struct scrollbar_instance *
+						inst);
 #endif
 
 extern Lisp_Object Vscrollbar_width, Vscrollbar_height;
--- a/src/symsinit.h	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/symsinit.h	Thu Mar 25 06:07:25 2010 -0500
@@ -209,6 +209,7 @@
    Dump time and post-pdump-load-time. */
 
 void buffer_objects_create (void);
+void casetab_objects_create (void);
 void extent_objects_create (void);
 void face_objects_create (void);
 void frame_objects_create (void);
@@ -216,6 +217,7 @@
 void hash_table_objects_create (void);
 void lstream_objects_create (void);
 void mule_charset_objects_create (void);
+void scrollbar_objects_create (void);
 void ui_gtk_objects_create (void);
 void window_objects_create (void);
 
@@ -354,6 +356,7 @@
 void reinit_vars_of_bytecode (void);
 void vars_of_callint (void);
 EXTERN_C void vars_of_canna_api (void);
+void vars_of_casetab (void);
 void vars_of_chartab (void);
 void vars_of_cmdloop (void);
 void vars_of_cmds (void);
--- a/src/window.c	Wed Mar 24 01:22:51 2010 -0500
+++ b/src/window.c	Thu Mar 25 06:07:25 2010 -0500
@@ -55,7 +55,7 @@
 Lisp_Object Qdisplay_buffer;
 
 #ifdef MEMORY_USAGE_STATS
-Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay;
+Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qredisplay_structs;
 #ifdef HAVE_SCROLLBARS
 Lisp_Object Qscrollbar_instances;
 #endif
@@ -710,6 +710,18 @@
 				      XWINDOW_MIRROR (f->root_mirror), w);
 }
 
+/* Given a real window, return its mirror structure, if it exists.
+   Don't do any updating. */
+static struct window_mirror *
+find_window_mirror_maybe (struct window *w)
+{
+  struct frame *f = XFRAME (w->frame);
+  if (!WINDOW_MIRRORP (f->root_mirror))
+    return 0;
+  return find_window_mirror_internal (f->root_window,
+				      XWINDOW_MIRROR (f->root_mirror), w);
+}
+
 /*****************************************************************************
  find_window_by_pixel_pos
 
@@ -5156,52 +5168,93 @@
 
 #ifdef MEMORY_USAGE_STATS
 
+struct window_mirror_stats
+{
+  struct usage_stats u;
+  /* Ancilliary non-lisp */
+  Bytecount redisplay_structs;
+#ifdef HAVE_SCROLLBARS
+  /* Ancilliary Lisp */
+  Bytecount scrollbar;
+#endif
+};
+
 struct window_stats
 {
   struct usage_stats u;
+  /* Ancillary non-Lisp */
+  Bytecount line_start;
+  /* The next two: ancillary non-Lisp under old-GC, ancillary Lisp under
+     NEW_GC */
   Bytecount face;
   Bytecount glyph;
-  Bytecount line_start;
-  Bytecount other_redisplay;
+  /* The next two are copied out of the window mirror, which is an ancillary
+     Lisp structure; the first is non-Lisp, the second Lisp, but from our
+     perspective, they are both counted as Lisp */
+  Bytecount redisplay_structs;
 #ifdef HAVE_SCROLLBARS
   Bytecount scrollbar;
 #endif
+  /* Remaining memory associated with window mirror (ancillary Lisp) */
+  Bytecount window_mirror;
 };
 
 static void
 compute_window_mirror_usage (struct window_mirror *mir,
-			     struct window_stats *stats,
-			     struct usage_stats *ustats)
-{
-  if (!mir)
-    return;
+			     struct window_mirror_stats *stats)
+{
+  stats->redisplay_structs =
+    compute_display_line_dynarr_usage (mir->current_display_lines, &stats->u)
+    +
+    compute_display_line_dynarr_usage (mir->desired_display_lines, &stats->u);
 #ifdef HAVE_SCROLLBARS
-  {
-    struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
-
-    stats->scrollbar +=
-      compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
-					ustats);
-    stats->scrollbar +=
-      compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
-					ustats);
-  }
+  stats->scrollbar =
+    compute_all_scrollbar_instance_usage (mir->scrollbar_vertical_instance) +
+    compute_all_scrollbar_instance_usage (mir->scrollbar_horizontal_instance);
 #endif /* HAVE_SCROLLBARS */
-  stats->other_redisplay +=
-    compute_display_line_dynarr_usage (mir->current_display_lines, ustats);
-  stats->other_redisplay +=
-    compute_display_line_dynarr_usage (mir->desired_display_lines, ustats);
+}
+
+
+static void
+window_mirror_memory_usage (Lisp_Object window_mirror,
+			    struct generic_usage_stats *gustats)
+{
+  struct window_mirror_stats *stats = (struct window_mirror_stats *) gustats;
+
+  compute_window_mirror_usage (XWINDOW_MIRROR (window_mirror), stats);
 }
 
 static void
 compute_window_usage (struct window *w, struct window_stats *stats,
 		      struct usage_stats *ustats)
 {
-  stats->face += compute_face_cachel_usage (w->face_cachels, ustats);
-  stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ustats);
-  stats->line_start +=
+  stats->line_start =
     compute_line_start_cache_dynarr_usage (w->line_start_cache, ustats);
-  compute_window_mirror_usage (find_window_mirror (w), stats, ustats);
+  stats->face = compute_face_cachel_usage (w->face_cachels,
+					   IF_OLD_GC (ustats));
+  stats->glyph = compute_glyph_cachel_usage (w->glyph_cachels,
+					     IF_OLD_GC (ustats));
+  {
+    struct window_mirror *wm;
+
+    wm = find_window_mirror_maybe (w);
+    if (wm)
+      {
+	struct generic_usage_stats gustats;
+	struct window_mirror_stats *wmstats;
+	Bytecount total;
+	total = lisp_object_memory_usage_full (wrap_window_mirror (wm),
+					       NULL, NULL, NULL, &gustats);
+	wmstats = (struct window_mirror_stats *) &gustats;
+	stats->redisplay_structs = wmstats->redisplay_structs;
+	total -= stats->redisplay_structs;
+#ifdef HAVE_SCROLLBARS
+	stats->scrollbar = wmstats->scrollbar;
+	total -= stats->scrollbar;
+#endif
+	stats->window_mirror = total;
+      }
+  }
 }
 
 static void
@@ -5396,6 +5449,7 @@
 {
 #ifdef MEMORY_USAGE_STATS
   OBJECT_HAS_METHOD (window, memory_usage);
+  OBJECT_HAS_METHOD (window_mirror, memory_usage);
 #endif
 }
 
@@ -5422,7 +5476,7 @@
 #ifdef HAVE_SCROLLBARS
   DEFSYMBOL (Qscrollbar_instances);
 #endif
-  DEFSYMBOL (Qother_redisplay);
+  DEFSYMBOL (Qredisplay_structs);
 #endif
 
   DEFSYMBOL (Qtruncate_partial_width_windows);
@@ -5516,14 +5570,31 @@
 vars_of_window (void)
 {
 #ifdef MEMORY_USAGE_STATS
-  OBJECT_HAS_PROPERTY
-    (window, memusage_stats_list,
-     listu (Qface_cache, Qglyph_cache,
-	    Qline_start_cache, Qother_redisplay,
+  Lisp_Object l;
+
+  l = listu (Qline_start_cache,
+#ifdef NEW_GC
+	     Qt,
+#endif
+	     Qface_cache, Qglyph_cache,
+#ifndef NEW_GC
+	     Qt,
+#endif
+	     Qredisplay_structs,
 #ifdef HAVE_SCROLLBARS
-	    Qscrollbar_instances,
+	     Qscrollbar_instances,
 #endif
-	    Qunbound));
+	     intern ("window-mirror"),
+	     Qunbound);
+
+  OBJECT_HAS_PROPERTY (window, memusage_stats_list, l);
+
+  l = listu (Qredisplay_structs,
+#ifdef HAVE_SCROLLBARS
+	     Qt, Qscrollbar_instances,
+#endif
+	     Qunbound);
+  OBJECT_HAS_PROPERTY (window_mirror, memusage_stats_list, l);
 #endif /* MEMORY_USAGE_STATS */
 
   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*