Index: trunk/psLib/src/sys/psMemory.c
===================================================================
--- trunk/psLib/src/sys/psMemory.c	(revision 8232)
+++ trunk/psLib/src/sys/psMemory.c	(revision 8438)
@@ -8,6 +8,6 @@
 *  @author Robert Lupton, Princeton University
 *
-*  @version $Revision: 1.75 $ $Name: not supported by cvs2svn $
-*  @date $Date: 2006-08-08 23:32:23 $
+*  @version $Revision: 1.76 $ $Name: not supported by cvs2svn $
+*  @date $Date: 2006-08-21 21:22:56 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -19,4 +19,6 @@
 #include <stdio.h>
 #include <stdint.h>
+#include <string.h>
+#include <assert.h>
 
 #include "psMemory.h"
@@ -52,12 +54,14 @@
 static bool memory_is_persistent = false;
 
-static psS32 recycleBins = 13;
-static psS32 recycleBinSize[14] = {
-                                      8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, P_PS_LARGE_BLOCK_SIZE
-                                  };
+#define N_RECYCLE_BINS 14  // number of recycle bins
+static const psS32 recycleBins = N_RECYCLE_BINS;
+static const psS32 recycleBinSize[N_RECYCLE_BINS] =
+    {
+        8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, P_PS_LARGE_BLOCK_SIZE
+    };
 
 // N.B. recycleBinSize should be terminated by P_PS_LARGE_BLOCK_SIZE (simplifies search loops)
-static psMemBlock* recycleMemBlockList[13] = {
-            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+static psMemBlock* recycleMemBlockList[N_RECYCLE_BINS] = {
+            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
         };
 
@@ -453,35 +457,17 @@
         }
 
-        if (safeThreads) {
-            pthread_mutex_lock(&memBlockListMutex);
-        }
-
-        isBlockLast = (ptr == lastMemBlockAllocated);
-
-        ptr = (psMemBlock* ) realloc(ptr, sizeof(psMemBlock) + size + sizeof(psPtr ));
-
-        if (ptr == NULL) {
-            ptr = memExhaustedCallback(size);
-            if(ptr == NULL) {
-                psAbort(__func__, "Failed to reallocate %ld bytes at %s:%d", size, file, lineno);
-            }
-        }
-
-        ptr->userMemorySize = size;
-        *(psPtr *)((int8_t *) (ptr + 1) + size) = P_PS_MEMMAGIC;
-
-        if (isBlockLast) {
-            lastMemBlockAllocated = ptr;
-        }
-        // the block location may have changed, so fix the linked list addresses.
-        if (ptr->nextBlock != NULL) {
-            ptr->nextBlock->previousBlock = ptr;
-        }
-        if (ptr->previousBlock != NULL) {
-            ptr->previousBlock->nextBlock = ptr;
-        }
-
-        if (safeThreads) {
-            pthread_mutex_unlock(&memBlockListMutex);
+        if (size < ptr->userMemorySize) {
+            ;    // nothing to do
+        } else {
+            isBlockLast = (ptr == lastMemBlockAllocated);
+
+            psPtr *nvptr = p_psAlloc(size, file, lineno);
+            psMemBlock *nptr = ((psMemBlock *)nvptr) - 1;
+            memcpy(nvptr, vptr, ptr->userMemorySize < size ? ptr->userMemorySize : size);
+            *(psMemId *)&nptr->id = ptr->id;
+            nptr->persistent = ptr->persistent;
+
+            psFree(vptr);
+            ptr = nptr;
         }
 
@@ -1151,2 +1137,93 @@
     ptr->persistent = value;
 }
+
+/************************************************************************************************************/
+/*
+ * Return the total amount of memory owned by psLib; if non-NULL also provide a breakdown
+ * into recyclable, allocated, and allocated-and-persistent
+ *
+ * It would be simple enough to fix this code to return an array of structs to describe
+ * the insides of the allocator rather than the printf used here.
+ */
+size_t psMemStats(const bool print, // print details as they're found?
+                  size_t *allocated, // memory that's currently allocated (but not persistent)
+                  size_t *persistent, // persistent memory that's currently allocated
+                  size_t *freelist) // memory that's waiting to be recycled
+{
+    const size_t overhead = sizeof(psMemBlock) + sizeof(psPtr); // overhead on each allocation
+
+    if (print) {
+        printf("Type       %6s  %10s %8s\n", "size", "nByte", "nBlock");
+    }
+
+    if (safeThreads) {
+        pthread_mutex_lock(&memBlockListMutex);
+    }
+    /*
+     * All memory that's currently allocated, whether persistent or not
+     */
+    size_t allocated_s, persistent_s;
+    if (allocated == NULL) {
+        allocated = &allocated_s;
+    }
+    if (persistent == NULL) {
+        persistent = &persistent_s;
+    }
+
+    size_t alloc = 0, persist = 0;
+    size_t nalloc = 0, npersist = 0;
+    for (psMemBlock* ptr = lastMemBlockAllocated; ptr != NULL; ptr = ptr->nextBlock) {
+        assert (ptr->refCounter > 0);
+
+        if (ptr->persistent) {
+            npersist++;
+            persist += ptr->userMemorySize + overhead;
+        } else {
+            nalloc++;
+            alloc += ptr->userMemorySize + overhead;
+        }
+    }
+    *allocated = alloc;
+    *persistent = persist;
+
+    if (print) {
+        printf("Allocated  %6s  %10d %8d\n", "", alloc, nalloc);
+        printf("Persistent %6s  %10d %8d\n", "", persist, npersist);
+    }
+    /*
+     * Count the memory on the free list
+     */
+    size_t freelist_s;
+    if (freelist == NULL) {
+        freelist = &freelist_s;
+    }
+
+    *freelist = 0;
+    int nblock_tot = 0;
+    for (int i = 0; ; i++) {
+        if (recycleBinSize[i] == P_PS_LARGE_BLOCK_SIZE) {
+            break;
+        }
+        size_t bin_contents = 0;
+        size_t nblock = 0;
+        for (const psMemBlock *ptr = recycleMemBlockList[i]; ptr != NULL; ptr = ptr->nextBlock) {
+            nblock++;
+            bin_contents += ptr->userMemorySize + overhead;
+        }
+        *freelist += bin_contents;
+        nblock_tot += nblock;
+
+        if (print) {
+            printf("Freelist   %6d  %10d %8d\n", recycleBinSize[i], bin_contents, nblock);
+        }
+    }
+    if (print) {
+        printf("Freelist   %6s  %10d %8d\n", "", *freelist, nblock_tot);
+    }
+
+    if (safeThreads) {
+        pthread_mutex_unlock(&memBlockListMutex);
+    }
+
+    return *freelist + *allocated + *persistent;
+}
