Changeset: 96dbe2d01a83 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=96dbe2d01a83
Modified Files:
gdk/gdk_heap.c
gdk/gdk_posix.c
gdk/gdk_private.h
gdk/gdk_utils.c
Branch: Jul2012
Log Message:
Reinstate GDKvmalloc. This is a partial backout of changesets 5ee4cc736169 and
b6e70864037e.
GDKvmalloc and friends are now static functions in gdk_utils.c. They
are used on non-glibc systems for larger allocations (default: >= 1MiB).
This is hopefully the final fix for bug 3067.
On Solaris we found that memory fragmentation became a real issue.
This is solved partially by using libumem (previous changeset), and
partially by using anonymous mmap. Memory fragmentation becomes an
issue when a large chunk of memory is to be allocated, but the system
break (sbrk()) cannot be increased anymore, e.g. because too much
memory has already been committed to processes by the OS, and no large
enough contiguous piece of memory is available on the process heap.
Memory mapped files (anonymous or otherwise) don't use the same
address space and so don't increase the break. The only concern then
is that enough memory is available in the system, but since all large
chunks are memory mapped, we don't waste as much space on the process
heap. Also, when the memory is freed, the memory is returned to the
system and not kept allocated to the process as part of the process
heap.
On Linux (and presumable any other system that uses glibc), malloc
itself already uses this same trick for larger allocations, so we
don't have to do it.
diffs (truncated from 599 to 300 lines):
diff --git a/gdk/gdk_heap.c b/gdk/gdk_heap.c
--- a/gdk/gdk_heap.c
+++ b/gdk/gdk_heap.c
@@ -252,12 +252,10 @@ HEAPmargin(size_t maxsize)
int
HEAPalloc(Heap *h, size_t nitems, size_t itemsize)
{
- char nme[PATHLENGTH], *ext = NULL;
+ char nme[PATHLENGTH];
+ size_t minsize = GDK_mmap_minsize;
+ struct stat st;
- if (h->filename) {
- strcpy(nme, h->filename);
- ext = decompose_filename(nme);
- }
h->base = NULL;
h->maxsize = h->size = 1;
h->copied = 0;
@@ -269,32 +267,43 @@ HEAPalloc(Heap *h, size_t nitems, size_t
if (itemsize && nitems > (h->size / itemsize))
return -1;
- if (h->filename == NULL || (h->size < GDK_mmap_minsize)) {
+ if (h->filename) {
+ GDKfilepath(nme, BATDIR, h->filename, NULL);
+ /* if we're going to use mmap anyway (size >=
+ * GDK_mem_bigsize -- see GDKmallocmax), and the file
+ * we want to use already exists and is large enough
+ * for the size we want, force non-anonymous mmap */
+ if (h->size >= GDK_mem_bigsize &&
+ stat(nme, &st) == 0 && st.st_size >= (off_t) h->size) {
+ minsize = GDK_mem_bigsize; /* force mmap */
+ }
+ }
+
+ if (h->filename == NULL || (h->size < minsize)) {
h->storage = STORE_MEM;
h->base = (char *) GDKmallocmax(h->size, &h->maxsize, 0);
- ALLOCDEBUG fprintf(stderr, "#HEAPalloc " SZFMT " " SZFMT " "
PTRFMT "\n", h->size, h->maxsize, PTRFMTCAST h->base);
+ ALLOCDEBUG fprintf(stderr, "#HEAPalloc " SZFMT " " SZFMT " "
PTRFMT "%s\n", h->size, h->maxsize, PTRFMTCAST h->base, h->base && ((ssize_t*)
h->base)[-1] < 0 ? " VM" : "");
}
if (h->filename && h->base == NULL) {
- long_str ofn;
char *of = h->filename;
FILE *fp;
- struct stat st;
h->filename = NULL;
- GDKfilepath(ofn, BATDIR, of, NULL);
- if (stat(ofn, &st) != 0) {
+ if (stat(nme, &st) != 0) {
h->storage = STORE_MMAP;
h->base = HEAPcacheFind(&h->maxsize, of, h->storage );
h->filename = of;
} else {
+ char *ext;
+
+ strcpy(nme, h->filename);
+ ext = decompose_filename(nme);
fp = GDKfilelocate(nme, "wb", ext);
if (fp != NULL) {
fclose(fp);
h->newstorage = STORE_MMAP;
HEAPload(h, nme, ext, FALSE);
- if (h->base != NULL)
- MT_madvise(h->base, h->size,
MMAP_SEQUENTIAL);
}
GDKfree(of);
}
diff --git a/gdk/gdk_posix.c b/gdk/gdk_posix.c
--- a/gdk/gdk_posix.c
+++ b/gdk/gdk_posix.c
@@ -1633,6 +1633,92 @@ win_errno(void)
#ifndef WIN32
+#define MT_PAGESIZE(s) ((((s)-1)/MT_pagesize()+1)*MT_pagesize())
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+#if defined(MAP_ANONYMOUS)
+#define MMAP_FLAGS(f) f|MAP_ANONYMOUS
+#define MMAP_FD -1
+#define MMAP_OPEN_DEV_ZERO int fd = 1
+#define MMAP_CLOSE_DEV_ZERO (void)fd
+#else
+#define MMAP_FLAGS(f) f
+#define MMAP_FD fd
+#define MMAP_OPEN_DEV_ZERO int fd = open("/dev/zero", O_RDWR, MONETDB_MODE)
+#define MMAP_CLOSE_DEV_ZERO close(fd)
+#endif
+
+void *
+MT_vmalloc(size_t size, size_t *maxsize)
+{
+ MMAP_OPEN_DEV_ZERO;
+ char *q, *r = (char *) -1L;
+
+ if (fd < 0) {
+ return NULL;
+ }
+ size = MT_PAGESIZE(size);
+ *maxsize = MT_PAGESIZE(*maxsize);
+ if (*maxsize > size) {
+ r = (char *) mmap(NULL, *maxsize, PROT_NONE,
MMAP_FLAGS(MAP_PRIVATE | MAP_NORESERVE), MMAP_FD, 0);
+ }
+ if (r == (char *) -1L) {
+ *maxsize = size;
+ q = (char *) mmap(NULL, size, PROT_READ | PROT_WRITE,
MMAP_FLAGS(MAP_PRIVATE), MMAP_FD, 0);
+ } else {
+ q = (char *) mmap(r, size, PROT_READ | PROT_WRITE,
MMAP_FLAGS(MAP_PRIVATE | MAP_FIXED), MMAP_FD, 0);
+ }
+ MMAP_CLOSE_DEV_ZERO;
+ return (void *) ((q == (char *) -1L) ? NULL : q);
+}
+
+void
+MT_vmfree(void *p, size_t size)
+{
+ size = MT_PAGESIZE(size);
+ munmap(p, size);
+}
+
+void *
+MT_vmrealloc(void *voidptr, size_t oldsize, size_t newsize, size_t oldmaxsize,
size_t *newmaxsize)
+{
+ char *p = (char *) voidptr;
+ char *q = (char *) -1L;
+
+ /* sanitize sizes */
+ oldsize = MT_PAGESIZE(oldsize);
+ newsize = MT_PAGESIZE(newsize);
+ oldmaxsize = MT_PAGESIZE(oldmaxsize);
+ *newmaxsize = MT_PAGESIZE(*newmaxsize);
+ if (*newmaxsize < newsize) {
+ *newmaxsize = newsize;
+ }
+
+ if (oldsize > newsize) {
+ munmap(p + oldsize, oldsize - newsize);
+ } else if (oldsize < newsize) {
+ if (newsize < oldmaxsize) {
+ MMAP_OPEN_DEV_ZERO;
+ if (fd >= 0) {
+ q = (char *) mmap(p + oldsize, newsize -
oldsize, PROT_READ | PROT_WRITE, MMAP_FLAGS(MAP_PRIVATE | MAP_FIXED), MMAP_FD,
(off_t) oldsize);
+ MMAP_CLOSE_DEV_ZERO;
+ }
+ }
+ if (q == (char *) -1L) {
+ q = (char *) MT_vmalloc(newsize, newmaxsize);
+ if (q != NULL) {
+ memcpy(q, p, oldsize);
+ MT_vmfree(p, oldmaxsize);
+ return q;
+ }
+ }
+ }
+ *newmaxsize = MAX(oldmaxsize, newsize);
+ return p;
+}
+
void
MT_sleep_ms(unsigned int ms)
{
@@ -1654,6 +1740,93 @@ MT_sleep_ms(unsigned int ms)
#else /* WIN32 */
+#define MT_PAGESIZE(s) (((((s)-1) >> 12) + 1) << 12)
+#define MT_SEGSIZE(s) ((((((s)-1) >> 16) & 65535) + 1) << 16)
+
+#ifndef MEM_TOP_DOWN
+#define MEM_TOP_DOWN 0
+#endif
+
+void *
+MT_vmalloc(size_t size, size_t *maxsize)
+{
+ void *p, *a = NULL;
+ int mode = 0;
+
+ size = MT_PAGESIZE(size);
+ if (*maxsize < size) {
+ *maxsize = size;
+ }
+ *maxsize = MT_SEGSIZE(*maxsize);
+ if (*maxsize < 1000000) {
+ mode = MEM_TOP_DOWN; /* help NT in keeping memory
defragmented */
+ }
+ (void) pthread_mutex_lock(&MT_mmap_lock);
+ if (*maxsize > size) {
+ a = (void *) VirtualAlloc(NULL, *maxsize, MEM_RESERVE | mode,
PAGE_NOACCESS);
+ if (a == NULL) {
+ *maxsize = size;
+ }
+ }
+ p = (void *) VirtualAlloc(a, size, MEM_COMMIT | mode, PAGE_READWRITE);
+ (void) pthread_mutex_unlock(&MT_mmap_lock);
+ if (p == NULL) {
+ mnstr_printf(GDKstdout, "#VirtualAlloc(" PTRFMT "," SZFMT
",MEM_COMMIT,PAGE_READWRITE): failed\n", PTRFMTCAST a, size);
+ }
+ return p;
+}
+
+
+void
+MT_vmfree(void *p, size_t size)
+{
+ if (VirtualFree(p, size, MEM_DECOMMIT) == 0)
+ mnstr_printf(GDKstdout, "#VirtualFree(" PTRFMT "," SZFMT
",MEM_DECOMMIT): failed\n", PTRFMTCAST p, size);
+ if (VirtualFree(p, 0, MEM_RELEASE) == 0)
+ mnstr_printf(GDKstdout, "#VirtualFree(" PTRFMT
",0,MEM_RELEASE): failed\n", PTRFMTCAST p);
+}
+
+void *
+MT_vmrealloc(void *v, size_t oldsize, size_t newsize, size_t oldmaxsize,
size_t *newmaxsize)
+{
+ char *p = (char *) v, *a = p;
+
+ /* sanitize sizes */
+ oldsize = MT_PAGESIZE(oldsize);
+ newsize = MT_PAGESIZE(newsize);
+ oldmaxsize = MT_PAGESIZE(oldmaxsize);
+ *newmaxsize = MT_PAGESIZE(*newmaxsize);
+ if (*newmaxsize < newsize) {
+ *newmaxsize = newsize;
+ }
+
+ if (oldsize > newsize) {
+ size_t ret = VirtualFree(p + newsize, oldsize - newsize,
MEM_DECOMMIT);
+
+ if (ret == 0)
+ mnstr_printf(GDKstdout, "#VirtualFree(" PTRFMT ","
SSZFMT ",MEM_DECOMMIT): failed\n", PTRFMTCAST(p + newsize), (ssize_t) (oldsize
- newsize));
+ } else if (oldsize < newsize) {
+ (void) pthread_mutex_lock(&MT_mmap_lock);
+ a = (char *) VirtualAlloc(p, newsize, MEM_COMMIT,
PAGE_READWRITE);
+ (void) pthread_mutex_unlock(&MT_mmap_lock);
+ if (a != p) {
+ char *q = a;
+
+ if (a == NULL) {
+ q = MT_vmalloc(newsize, newmaxsize);
+ }
+ if (q != NULL) {
+ memcpy(q, p, oldsize);
+ MT_vmfree(p, oldmaxsize);
+ }
+ if (a == NULL)
+ return q;
+ }
+ }
+ *newmaxsize = MAX(oldmaxsize, newsize);
+ return a;
+}
+
void
MT_sleep_ms(unsigned int ms)
{
diff --git a/gdk/gdk_private.h b/gdk/gdk_private.h
--- a/gdk/gdk_private.h
+++ b/gdk/gdk_private.h
@@ -108,6 +108,9 @@ void *MT_mmap_open(MT_mmap_hdl *hdl, cha
void *MT_mmap_remap(MT_mmap_hdl *hdl, off_t off, size_t len);
int MT_mmap_trim(size_t lim, void *err);
int MT_msync(void *p, size_t off, size_t len, int mode);
+void *MT_vmalloc(size_t size, size_t *maxsize);
+void MT_vmfree(void *p, size_t size);
+void *MT_vmrealloc(void *voidptr, size_t oldsize, size_t newsize, size_t
oldmaxsize, size_t *newmaxsize);
int OIDdirty(void);
int OIDinit(void);
oid *oidRead(oid *a, stream *s, size_t cnt);
@@ -168,8 +171,7 @@ typedef struct {
extern int BBP_dirty; /* BBP table dirty? */
extern batlock_t GDKbatLock[BBP_BATMASK + 1];
extern bbplock_t GDKbbpLock[BBP_THREADMASK + 1];
-extern ptr GDK_mem_start; /* sbrk(0) at start of the program */
-extern size_t GDK_mmap_minsize; /* size after which we use tempfile VM
rather than malloc/anonymous VM */
+extern size_t GDK_mmap_minsize; /* size after which we use memory
mapped files */
extern MT_Lock GDKnameLock;
extern int GDKrecovery;
extern int GDKsilent; /* should GDK shut up? */
diff --git a/gdk/gdk_utils.c b/gdk/gdk_utils.c
--- a/gdk/gdk_utils.c
+++ b/gdk/gdk_utils.c
@@ -285,7 +285,7 @@ BATSIGinit(void)
size_t GDK_mmap_minsize = GDK_VM_MAXSIZE;
static size_t GDK_mem_maxsize_max = GDK_VM_MAXSIZE;
size_t GDK_mem_maxsize = GDK_VM_MAXSIZE;
-size_t GDK_mem_bigsize = 1 << 30;
+size_t GDK_mem_bigsize = GDK_VM_MAXSIZE;
size_t GDK_vm_maxsize = GDK_VM_MAXSIZE;
int GDK_vm_trim = 1;
@@ -550,10 +550,10 @@ GDKmem_heapcheck(int t)
gdk_set_lock(GDKthreadLock, fcn); \
GDKmallidx(_idx, _vmdelta); \
GDK_vm_nallocs[_idx]--; \
_______________________________________________
Checkin-list mailing list
[email protected]
http://mail.monetdb.org/mailman/listinfo/checkin-list