Index: /trunk/psLib/psLib.kdevses
===================================================================
--- /trunk/psLib/psLib.kdevses	(revision 1239)
+++ /trunk/psLib/psLib.kdevses	(revision 1240)
@@ -2,24 +2,40 @@
 <!DOCTYPE KDevPrjSession>
 <KDevPrjSession>
- <DocsAndViews NumberOfDocuments="3" >
-  <Doc0 NumberOfViews="1" URL="file:/home/desonia/psLib/src/dataManip/tst_psImageManip.c" >
-   <View0 line="13" Type="???" >
-    <AdditionalSettings Top="2" Width="1196" Attach="1" Height="684" Left="2" MinMaxMode="0" />
+ <DocsAndViews NumberOfDocuments="5" >
+  <Doc0 NumberOfViews="1" URL="file:/home/desonia/psLib/src/astronomy/psCCD.h" >
+   <View0 line="37" Type="???" >
+    <AdditionalSettings Top="2" Width="1058" Attach="1" Height="629" Left="2" MinMaxMode="0" />
    </View0>
   </Doc0>
-  <Doc1 NumberOfViews="1" URL="file:/home/desonia/psLib/test/dataManip/Makefile" >
-   <View0 line="0" Type="???" >
-    <AdditionalSettings Top="2" Width="1196" Attach="1" Height="659" Left="2" MinMaxMode="0" />
+  <Doc1 NumberOfViews="1" URL="file:/home/desonia/psLib/src/collections/psImage.h" >
+   <View0 line="61" Type="???" >
+    <AdditionalSettings Top="2" Width="1058" Attach="1" Height="629" Left="2" MinMaxMode="0" />
    </View0>
   </Doc1>
-  <Doc2 NumberOfViews="1" URL="file:/home/desonia/psLib/test/dataManip/tst_psImageManip.c" >
-   <View0 line="15" Type="???" >
-    <AdditionalSettings Top="2" Width="1196" Attach="1" Height="659" Left="2" MinMaxMode="0" />
+  <Doc2 NumberOfViews="1" URL="file:/home/desonia/psLib/src/astronomy/psCCD.c" >
+   <View0 line="43" Type="???" >
+    <AdditionalSettings Top="2" Width="1058" Attach="1" Height="629" Left="2" MinMaxMode="0" />
    </View0>
   </Doc2>
+  <Doc3 NumberOfViews="1" URL="file:/home/desonia/psLib/src/astronomy/Makefile" >
+   <View0 line="15" Type="???" >
+    <AdditionalSettings Top="2" Width="1058" Attach="1" Height="629" Left="2" MinMaxMode="0" />
+   </View0>
+  </Doc3>
+  <Doc4 NumberOfViews="1" URL="file:/home/desonia/psLib/src/collections/Makefile" >
+   <View0 line="0" Type="???" >
+    <AdditionalSettings Top="2" Width="1058" Attach="1" Height="629" Left="2" MinMaxMode="0" />
+   </View0>
+  </Doc4>
  </DocsAndViews>
  <pluginList>
   <kdevbookmarks>
-   <bookmarks/>
+   <bookmarks>
+    <bookmark url="/home/desonia/psLib/test/dataManip/tst_psImageManip.c" >
+     <mark line="578" />
+     <mark line="598" />
+     <mark line="632" />
+    </bookmark>
+   </bookmarks>
   </kdevbookmarks>
   <kdevsubversion>
Index: /trunk/psLib/src/astronomy/psCCD.d
===================================================================
--- /trunk/psLib/src/astronomy/psCCD.d	(revision 1239)
+++ /trunk/psLib/src/astronomy/psCCD.d	(revision 1240)
@@ -1,3 +1,3 @@
 psCCD.o psCCD.d : psCCD.c psCCD.h ../collections/psType.h ../collections/psImage.h \
-  ../collections/psList.h ../collections/psCompare.h \
-  ../collections/psArray.h ../sysUtils/psMemory.h
+  ../collections/psArray.h ../collections/psCompare.h \
+  ../collections/psList.h ../sysUtils/psMemory.h
Index: /trunk/psLib/src/sys/psMemory.c
===================================================================
--- /trunk/psLib/src/sys/psMemory.c	(revision 1239)
+++ /trunk/psLib/src/sys/psMemory.c	(revision 1240)
@@ -8,6 +8,6 @@
  *  @author Robert Lupton, Princeton University
  *
- *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 23:52:34 $
+ *  @version $Revision: 1.29 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-19 20:45:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -28,4 +28,6 @@
 #define P_PS_MEMMAGIC (void *)0xdeadbeef // Magic number in psMemBlock header
 
+#define P_PS_LARGE_BLOCK_SIZE 65536    // size where under, we try to recycle
+
 static int checkMemBlock(const psMemBlock *m, const char* funcName);
 static psMemBlock *lastMemBlockAllocated = NULL;
@@ -33,4 +35,14 @@
 static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;
 
+static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int recycleBins = 13;
+static int recycleBinSize[14] = {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};
+
+#ifdef PS_MEM_DEBUG
+static psMemBlock* deadBlockList;    // a place to put dead memBlocks in debug mode.
+#endif
 /**
  * Unique ID for allocated blocks
@@ -43,5 +55,20 @@
 static void *memExhaustedCallbackDefault(size_t size)
 {
-    return NULL;
+    void* ptr = NULL;
+
+    pthread_mutex_lock(&recycleMemBlockListMutex);
+    int level=recycleBins-1;
+    while (level >= 0 && ptr == NULL) {
+        while (recycleMemBlockList[level] != NULL && ptr == NULL) {
+            psMemBlock* old = recycleMemBlockList[level];
+            recycleMemBlockList[level] = recycleMemBlockList[level]->nextBlock;
+            free(old);
+            ptr = malloc(size);
+        }
+        level--;
+    }
+    pthread_mutex_unlock(&recycleMemBlockListMutex);
+
+    return ptr;
 }
 
@@ -243,12 +270,49 @@
 void *p_psAlloc(size_t size, const char *file, int lineno)
 {
-    psMemBlock *ptr = malloc(sizeof(psMemBlock) + size + sizeof(void*));
+
+    psMemBlock *ptr = NULL;
+
+    // memory is of the size I want to bother recycling?
+    if (size < P_PS_LARGE_BLOCK_SIZE) {
+        // find the bin we need.
+        int level = 0;
+        while (size > recycleBinSize[level]) {
+            level++;
+        }
+        // Are we in one of the bins
+        if (level<recycleBins) {
+
+            size = recycleBinSize[level];  // round-up size to next sized bin.
+
+            pthread_mutex_lock(&recycleMemBlockListMutex);
+
+            if (recycleMemBlockList[level] != NULL) {
+                ptr = recycleMemBlockList[level];
+                recycleMemBlockList[level] = ptr->nextBlock;
+                if (recycleMemBlockList[level] != NULL) {
+                    recycleMemBlockList[level]->previousBlock = NULL;
+                }
+                size = ptr->userMemorySize;
+            }
+
+            pthread_mutex_unlock(&recycleMemBlockListMutex);
+        }
+    }
 
     if (ptr == NULL) {
-        ptr = memExhaustedCallback(size);
+        ptr = malloc(sizeof(psMemBlock) + size + sizeof(void*));
+
         if (ptr == NULL) {
-            psAbort(__func__, "Failed to allocate %u bytes at %s:%d",
-                    size, file, lineno);
-        }
+            ptr = memExhaustedCallback(size);
+            if (ptr == NULL) {
+                psAbort(__func__, "Failed to allocate %u bytes at %s:%d",
+                        size, file, lineno);
+            }
+        }
+
+        ptr->startblock = P_PS_MEMMAGIC;
+        ptr->endblock = P_PS_MEMMAGIC;
+        ptr->userMemorySize = size;
+        pthread_mutex_init(&ptr->refCounterMutex, NULL);
     }
 
@@ -261,11 +325,7 @@
     ptr->freeFcn = NULL;
     *(unsigned int*)&ptr->lineno = lineno;
-    ptr->startblock = P_PS_MEMMAGIC;
-    ptr->endblock = P_PS_MEMMAGIC;
-    ptr->userMemorySize = size;
     *(void**)((int8_t*)(ptr+1)+size) = P_PS_MEMMAGIC;
     ptr->previousBlock = NULL;
 
-    pthread_mutex_init(&ptr->refCounterMutex, NULL);
     ptr->refCounter = 1;                // one user so far
 
@@ -475,10 +535,4 @@
         }
 
-        #ifdef PS_MEM_DEBUG
-        // for debug mode, we should keep the memBlock around and mark as not referenced.
-        ptr->refCounter = 0;
-        (void)p_psRealloc(vptr,0,file,lineno);
-        #else
-
         pthread_mutex_lock(&memBlockListMutex);
 
@@ -496,8 +550,46 @@
         pthread_mutex_unlock(&memBlockListMutex);
 
+
+        // do we need to recycle?
+        if (ptr->userMemorySize < P_PS_LARGE_BLOCK_SIZE) {
+
+            int level = 1;
+            while (ptr->userMemorySize >= recycleBinSize[level]) {
+                level++;
+            }
+            level--;
+
+            ptr->refCounter = 0;
+            ptr->previousBlock = NULL;
+
+            pthread_mutex_lock(&recycleMemBlockListMutex);
+            ptr->nextBlock = recycleMemBlockList[level];
+            if (recycleMemBlockList[level] != NULL) {
+                recycleMemBlockList[level]->previousBlock = ptr;
+            }
+            recycleMemBlockList[level] = ptr;
+            pthread_mutex_unlock(&recycleMemBlockListMutex);
+
+        } else {
+            // memory is larger than I want to recycle.
+            #ifdef PS_MEM_DEBUG
+            (void)p_psRealloc(vptr,0,file,lineno);
+            ptr->previousBlock = NULL;
+            ptr->nextBlock = deadBlockList;
+            if (deadBlockList != NULL) {
+                deadBlockList->previous = ptr;
+            }
+            deadBlockList = ptr;
+            #else
+
+            pthread_mutex_destroy(&ptr->refCounterMutex);
+            free(ptr);
+            #endif
+
+        }
+
+
         pthread_mutex_destroy(&ptr->refCounterMutex);
 
-        free(ptr);
-        #endif
 
         vptr = NULL;    // since we freed it, make sure we return NULL.
Index: /trunk/psLib/src/sysUtils/psMemory.c
===================================================================
--- /trunk/psLib/src/sysUtils/psMemory.c	(revision 1239)
+++ /trunk/psLib/src/sysUtils/psMemory.c	(revision 1240)
@@ -8,6 +8,6 @@
  *  @author Robert Lupton, Princeton University
  *
- *  @version $Revision: 1.28 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2004-07-15 23:52:34 $
+ *  @version $Revision: 1.29 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2004-07-19 20:45:53 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -28,4 +28,6 @@
 #define P_PS_MEMMAGIC (void *)0xdeadbeef // Magic number in psMemBlock header
 
+#define P_PS_LARGE_BLOCK_SIZE 65536    // size where under, we try to recycle
+
 static int checkMemBlock(const psMemBlock *m, const char* funcName);
 static psMemBlock *lastMemBlockAllocated = NULL;
@@ -33,4 +35,14 @@
 static pthread_mutex_t memIdMutex = PTHREAD_MUTEX_INITIALIZER;
 
+static pthread_mutex_t recycleMemBlockListMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int recycleBins = 13;
+static int recycleBinSize[14] = {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};
+
+#ifdef PS_MEM_DEBUG
+static psMemBlock* deadBlockList;    // a place to put dead memBlocks in debug mode.
+#endif
 /**
  * Unique ID for allocated blocks
@@ -43,5 +55,20 @@
 static void *memExhaustedCallbackDefault(size_t size)
 {
-    return NULL;
+    void* ptr = NULL;
+
+    pthread_mutex_lock(&recycleMemBlockListMutex);
+    int level=recycleBins-1;
+    while (level >= 0 && ptr == NULL) {
+        while (recycleMemBlockList[level] != NULL && ptr == NULL) {
+            psMemBlock* old = recycleMemBlockList[level];
+            recycleMemBlockList[level] = recycleMemBlockList[level]->nextBlock;
+            free(old);
+            ptr = malloc(size);
+        }
+        level--;
+    }
+    pthread_mutex_unlock(&recycleMemBlockListMutex);
+
+    return ptr;
 }
 
@@ -243,12 +270,49 @@
 void *p_psAlloc(size_t size, const char *file, int lineno)
 {
-    psMemBlock *ptr = malloc(sizeof(psMemBlock) + size + sizeof(void*));
+
+    psMemBlock *ptr = NULL;
+
+    // memory is of the size I want to bother recycling?
+    if (size < P_PS_LARGE_BLOCK_SIZE) {
+        // find the bin we need.
+        int level = 0;
+        while (size > recycleBinSize[level]) {
+            level++;
+        }
+        // Are we in one of the bins
+        if (level<recycleBins) {
+
+            size = recycleBinSize[level];  // round-up size to next sized bin.
+
+            pthread_mutex_lock(&recycleMemBlockListMutex);
+
+            if (recycleMemBlockList[level] != NULL) {
+                ptr = recycleMemBlockList[level];
+                recycleMemBlockList[level] = ptr->nextBlock;
+                if (recycleMemBlockList[level] != NULL) {
+                    recycleMemBlockList[level]->previousBlock = NULL;
+                }
+                size = ptr->userMemorySize;
+            }
+
+            pthread_mutex_unlock(&recycleMemBlockListMutex);
+        }
+    }
 
     if (ptr == NULL) {
-        ptr = memExhaustedCallback(size);
+        ptr = malloc(sizeof(psMemBlock) + size + sizeof(void*));
+
         if (ptr == NULL) {
-            psAbort(__func__, "Failed to allocate %u bytes at %s:%d",
-                    size, file, lineno);
-        }
+            ptr = memExhaustedCallback(size);
+            if (ptr == NULL) {
+                psAbort(__func__, "Failed to allocate %u bytes at %s:%d",
+                        size, file, lineno);
+            }
+        }
+
+        ptr->startblock = P_PS_MEMMAGIC;
+        ptr->endblock = P_PS_MEMMAGIC;
+        ptr->userMemorySize = size;
+        pthread_mutex_init(&ptr->refCounterMutex, NULL);
     }
 
@@ -261,11 +325,7 @@
     ptr->freeFcn = NULL;
     *(unsigned int*)&ptr->lineno = lineno;
-    ptr->startblock = P_PS_MEMMAGIC;
-    ptr->endblock = P_PS_MEMMAGIC;
-    ptr->userMemorySize = size;
     *(void**)((int8_t*)(ptr+1)+size) = P_PS_MEMMAGIC;
     ptr->previousBlock = NULL;
 
-    pthread_mutex_init(&ptr->refCounterMutex, NULL);
     ptr->refCounter = 1;                // one user so far
 
@@ -475,10 +535,4 @@
         }
 
-        #ifdef PS_MEM_DEBUG
-        // for debug mode, we should keep the memBlock around and mark as not referenced.
-        ptr->refCounter = 0;
-        (void)p_psRealloc(vptr,0,file,lineno);
-        #else
-
         pthread_mutex_lock(&memBlockListMutex);
 
@@ -496,8 +550,46 @@
         pthread_mutex_unlock(&memBlockListMutex);
 
+
+        // do we need to recycle?
+        if (ptr->userMemorySize < P_PS_LARGE_BLOCK_SIZE) {
+
+            int level = 1;
+            while (ptr->userMemorySize >= recycleBinSize[level]) {
+                level++;
+            }
+            level--;
+
+            ptr->refCounter = 0;
+            ptr->previousBlock = NULL;
+
+            pthread_mutex_lock(&recycleMemBlockListMutex);
+            ptr->nextBlock = recycleMemBlockList[level];
+            if (recycleMemBlockList[level] != NULL) {
+                recycleMemBlockList[level]->previousBlock = ptr;
+            }
+            recycleMemBlockList[level] = ptr;
+            pthread_mutex_unlock(&recycleMemBlockListMutex);
+
+        } else {
+            // memory is larger than I want to recycle.
+            #ifdef PS_MEM_DEBUG
+            (void)p_psRealloc(vptr,0,file,lineno);
+            ptr->previousBlock = NULL;
+            ptr->nextBlock = deadBlockList;
+            if (deadBlockList != NULL) {
+                deadBlockList->previous = ptr;
+            }
+            deadBlockList = ptr;
+            #else
+
+            pthread_mutex_destroy(&ptr->refCounterMutex);
+            free(ptr);
+            #endif
+
+        }
+
+
         pthread_mutex_destroy(&ptr->refCounterMutex);
 
-        free(ptr);
-        #endif
 
         vptr = NULL;    // since we freed it, make sure we return NULL.
Index: /trunk/psLib/test/sysUtils/verified/tst_psMemory.stderr
===================================================================
--- /trunk/psLib/test/sysUtils/verified/tst_psMemory.stderr	(revision 1239)
+++ /trunk/psLib/test/sysUtils/verified/tst_psMemory.stderr	(revision 1240)
@@ -92,5 +92,5 @@
  <DATE> <TIME> |<HOST>|I|TPmemCorruption|psMemCheckCorruption should output an error message and memProblemCallback callback should be called.
  <DATE> <TIME> |<HOST>|E|psMemCheckCorru|Memory Corruption: memory block 1 is corrupted (buffer underflow)
- <DATE> <TIME> |<HOST>|I|memProblemCallb|memory callback called for id 1 (psMemCheckCorruption:227).
+ <DATE> <TIME> |<HOST>|I|memProblemCallb|memory callback called for id 1 (psMemCheckCorruption:254).
 
 ---> TESTPOINT PASSED (psMemory{psMemCorruption} | tst_psMemory.c)
