Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorTon Roosendaal <ton@blender.org>2006-02-16 20:51:01 +0300
committerTon Roosendaal <ton@blender.org>2006-02-16 20:51:01 +0300
commitfe036a0538860bf4f0b8e87d70046ff2a75f5f28 (patch)
treec6838cde34a609ea4832b98303c683fe90fd3edd /intern
parent7f4b01ccf076998cac98c52aa6701f35e1c2500f (diff)
Added new malloc type in our MEM module; using the unix feature 'mmap'.
In Orange we've been fighting the past weeks with memory usage a lot... at the moment incredible huge scenes are being rendered, with multiple layers and all compositing, stressing limits of memory a lot. I had hoped that less frequently used blocks would be swapped away nicely, so fragmented memory could survive. Unfortunately (in OSX) the malloc range is limited to 2 GB only (upped half of address space). Other OS's have a limit too, but typically larger afaik. Now here's mmap to the rescue! It has a very nice feature to map to a virtual (non existing) file, allowing to allocate disk-mapped memory on the fly. For as long there's real memory it works nearly as fast as a regular malloc, and when you go to the swap boundary, it knows nicely what to swap first. The upcoming commit will use mmap for all large memory blocks, like the composit stack, render layers, lamp buffers and images. Tested here on my 1 GB system, and compositing huge images with a total of 2.5 gig still works acceptable here. :) http://www.blender.org/bf/memory.jpg This is a silly composit test, using 64 MB images with a load of nodes. Check the header print... the (2323.33M) is the mmap disk-cache in use. BTW: note that is still limited to the virtual address space of 4 GB. The new call is: MEM_mapalloc() Per definition, mmap() returns zero'ed memory, so a calloc isn't required. For Windows there's no mmap() available, but I'm pretty sure there's an equivalent. Windows gurus here are invited to insert that here in code! At the moment it's nicely ifdeffed, so for Windows the mmap defaults to a regular alloc.
Diffstat (limited to 'intern')
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h13
-rw-r--r--intern/guardedalloc/intern/mallocn.c145
2 files changed, 96 insertions, 62 deletions
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index e909e7eee45..c9338d0ae8a 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -87,12 +87,17 @@ extern "C" {
* Allocate a block of memory of size len, with tag name str. The
* memory is cleared. The name must be static, because only a
* pointer to it is stored ! */
- void *MEM_callocN(unsigned int len, char * str);
+ void *MEM_callocN(unsigned int len, const char * str);
/** Allocate a block of memory of size len, with tag name str. The
- * name must be a static, because only a pointer to it is stored !
- * */
- void *MEM_mallocN(unsigned int len, char * str);
+ * name must be a static, because only a pointer to it is stored !
+ * */
+ void *MEM_mallocN(unsigned int len, const char * str);
+
+ /** Same as callocN, clears memory and uses mmap (disk cached) if supported.
+ Can be free'd with MEM_freeN as usual.
+ * */
+ void *MEM_mapallocN(unsigned int len, const char * str);
/** Print a list of the names and sizes of all allocated memory
* blocks. */
diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c
index cd1917cd3c7..763cb655c8d 100644
--- a/intern/guardedalloc/intern/mallocn.c
+++ b/intern/guardedalloc/intern/mallocn.c
@@ -40,8 +40,11 @@
#include <string.h> /* memcpy */
#include <stdarg.h>
-#ifdef HAVE_CONFIG_H
-#include <config.h>
+/* mmap exception */
+#if defined(AMIGA) || defined(__BeOS) || defined(WIN32)
+#else
+#include <sys/types.h>
+#include <sys/mman.h>
#endif
#include "MEM_guardedalloc.h"
@@ -60,20 +63,22 @@ typedef struct localListBase
void *first, *last;
} localListBase;
+ /* note: keep this struct aligned (e.g., irix/gcc) - Hos */
typedef struct MemHead {
int tag1;
int len;
struct MemHead *next,*prev;
- char * name;
- char * nextname;
+ const char * name;
+ const char * nextname;
int tag2;
- int pad; /* keep this in, due to alignment issues (e.g., irix/gcc) - Hos */
+ int mmap; /* if true, memory was mmapped */
} MemHead;
typedef struct MemTail {
int tag3, pad;
} MemTail;
+
/* --------------------------------------------------------------------- */
/* local functions */
/* --------------------------------------------------------------------- */
@@ -81,8 +86,8 @@ typedef struct MemTail {
static void addtail(localListBase *listbase, void *vlink);
static void remlink(localListBase *listbase, void *vlink);
static void rem_memblock(MemHead *memh);
-static void MemorY_ErroR(char *block, char *error);
-static char *check_memlist(MemHead *memh);
+static void MemorY_ErroR(const char *block, const char *error);
+static const char *check_memlist(MemHead *memh);
/* --------------------------------------------------------------------- */
/* locally used defines */
@@ -107,7 +112,7 @@ static char *check_memlist(MemHead *memh);
int totblock= 0;
-int mem_in_use= 0;
+unsigned long mem_in_use= 0, mmap_in_use= 0;
static struct localListBase _membase;
static struct localListBase *membase = &_membase;
@@ -130,7 +135,7 @@ static void (*error_callback)(char *) = NULL;
/* implementation */
/* --------------------------------------------------------------------- */
-static void print_error(char *str, ...)
+static void print_error(const char *str, ...)
{
char buf[1024];
va_list ap;
@@ -144,7 +149,7 @@ static void print_error(char *str, ...)
int MEM_check_memory_integrity()
{
- char* err_val = NULL;
+ const char* err_val = NULL;
MemHead* listend;
/* check_memlist starts from the front, and runs until it finds
* the requested chunk. For this test, that's the last one. */
@@ -180,76 +185,94 @@ void *MEM_dupallocN(void *vmemh)
if (vmemh) {
MemHead *memh= vmemh;
memh--;
-
- newp= MEM_mallocN(memh->len, "dupli_alloc");
+
+ if(memh->mmap)
+ newp= MEM_mapallocN(memh->len, "dupli_alloc");
+ else
+ newp= MEM_mallocN(memh->len, "dupli_mapalloc");
memcpy(newp, vmemh, memh->len);
}
return newp;
}
-void *MEM_mallocN(unsigned int len, char *str)
+static void make_memhead_header(MemHead *memh, unsigned int len, const char *str)
{
- MemHead *memh;
MemTail *memt;
+
+ memh->tag1 = MEMTAG1;
+ memh->name = str;
+ memh->nextname = 0;
+ memh->len = len;
+ memh->mmap = 0;
+ memh->tag2 = MEMTAG2;
+
+ memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
+ memt->tag3 = MEMTAG3;
+
+ addtail(membase,&memh->next);
+ if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
+
+ totblock++;
+ mem_in_use += len;
+}
+
+void *MEM_mallocN(unsigned int len, const char *str)
+{
+ MemHead *memh;
len = (len + 3 ) & ~3; /* allocate in units of 4 */
memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail));
- if(memh!=0) {
- memh->tag1 = MEMTAG1;
- memh->name = str;
- memh->nextname = 0;
- memh->len = len;
-/* memh->level = 0; */
- memh->tag2 = MEMTAG2;
-
- memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
- memt->tag3 = MEMTAG3;
-
- addtail(membase,&memh->next);
- if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
-
- totblock++;
- mem_in_use += len;
+ if(memh) {
+ make_memhead_header(memh, len, str);
return (++memh);
}
print_error("Malloc returns nill: len=%d in %s\n",len,str);
- return 0;
+ return NULL;
}
-void *MEM_callocN(unsigned int len, char *str)
+void *MEM_callocN(unsigned int len, const char *str)
{
MemHead *memh;
- MemTail *memt;
len = (len + 3 ) & ~3; /* allocate in units of 4 */
memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1);
- if(memh!=0) {
- memh->tag1 = MEMTAG1;
- memh->name = str;
- memh->nextname = 0;
- memh->len = len;
-/* memh->level = 0; */
- memh->tag2 = MEMTAG2;
-
- memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
- memt->tag3 = MEMTAG3;
-
- addtail(membase,&memh->next);
- if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
-
- totblock++;
- mem_in_use += len;
+ if(memh) {
+ make_memhead_header(memh, len, str);
return (++memh);
}
print_error("Calloc returns nill: len=%d in %s\n",len,str);
return 0;
}
+/* note; mmap returns zero'd memory */
+void *MEM_mapallocN(unsigned int len, const char *str)
+{
+#if defined(AMIGA) || defined(__BeOS) || defined(WIN32)
+ return MEM_callocN(len, str);
+#else
+ MemHead *memh;
+
+ len = (len + 3 ) & ~3; /* allocate in units of 4 */
+
+ memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail),
+ PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
+
+ if(memh!=(MemHead *)-1) {
+ make_memhead_header(memh, len, str);
+ memh->mmap= 1;
+ mmap_in_use += len;
+ return (++memh);
+ }
+ print_error("Mapalloc returns nill: len=%d in %s\n",len, str);
+ return NULL;
+#endif
+}
+
void MEM_printmemlist()
{
@@ -270,9 +293,9 @@ short MEM_freeN(void *vmemh) /* anders compileertie niet meer */
short error = 0;
MemTail *memt;
MemHead *memh= vmemh;
- char *name;
+ const char *name;
- if (memh == 0){
+ if (memh == NULL){
MemorY_ErroR("free","attempt to free NULL pointer");
/* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
return(-1);
@@ -304,7 +327,7 @@ short MEM_freeN(void *vmemh) /* anders compileertie niet meer */
memh->tag1 = MEMFREE;
memh->tag2 = MEMFREE;
memt->tag3 = MEMFREE;
- /* na tags !!! */
+ /* after tags !!! */
rem_memblock(memh);
return(0);
@@ -323,7 +346,7 @@ short MEM_freeN(void *vmemh) /* anders compileertie niet meer */
}
totblock--;
- /* hier moet een DUMP plaatsvinden */
+ /* here a DUMP should happen */
return(error);
}
@@ -371,18 +394,24 @@ static void rem_memblock(MemHead *memh)
totblock--;
mem_in_use -= memh->len;
- free(memh);
+ if(memh->mmap) {
+ mmap_in_use -= memh->len;
+ if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail)))
+ printf("Couldn't unmap memory %s\n", memh->name);
+ }
+ else
+ free(memh);
}
-static void MemorY_ErroR(char *block, char *error)
+static void MemorY_ErroR(const char *block, const char *error)
{
- print_error("Memoryblock %s: %s\n",block,error);
+ print_error("Memoryblock %s: %s\n",block, error);
}
-static char *check_memlist(MemHead *memh)
+static const char *check_memlist(MemHead *memh)
{
MemHead *forw,*back,*forwok,*backok;
- char *name;
+ const char *name;
forw = membase->first;
if (forw) forw = MEMNEXT(forw);