[prev in list] [next in list] [prev in thread] [next in thread]
List: monetdb-checkins
Subject: MonetDB: default - added HEAPcache. This reduces time spend in f...
From: Niels Nes <niels () cwi ! nl>
Date: 2011-01-30 15:57:15
Message-ID: hg.7d8e36384020.1296403035.6315528441665844383 () localhost ! localdomain
[Download RAW message or body]
Changeset: 7d8e36384020 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=7d8e36384020
Modified Files:
gdk/gdk.mx
gdk/gdk_heap.mx
gdk/gdk_search.mx
gdk/gdk_storage.mx
gdk/gdk_utils.mx
Branch: default
Log Message:
added HEAPcache. This reduces time spend in freeing MAP_SHARED heaps
(mostly used by hash tables).
diffs (truncated from 310 to 300 lines):
diff --git a/gdk/gdk.mx b/gdk/gdk.mx
--- a/gdk/gdk.mx
+++ b/gdk/gdk.mx
@@ -433,12 +433,14 @@
#define BAKDIR "bat/BACKUP"
#define SUBDIR "bat/BACKUP/SUBCOMMIT"
#define LEFTDIR "bat/LEFTOVERS"
+#define HCDIR "bat/HC"
#else
#define BATDIR "bat"
#define DELDIR "bat\\DELETE_ME"
#define BAKDIR "bat\\BACKUP"
#define SUBDIR "bat\\BACKUP\\SUBCOMMIT"
#define LEFTDIR "bat\\LEFTOVERS"
+#define HCDIR "bat\\HC"
#endif
#define DBLOGFILE "MonetLog"
@@ -1051,6 +1053,7 @@
gdk_export int HEAPdelete(Heap *h, const char *o, const char *ext);
gdk_export size_t HEAPvmsize(Heap *h);
gdk_export size_t HEAPmemsize(Heap *h);
+gdk_export void HEAPcacheInit(void);
/*
@}
diff --git a/gdk/gdk_heap.mx b/gdk/gdk_heap.mx
--- a/gdk/gdk_heap.mx
+++ b/gdk/gdk_heap.mx
@@ -56,6 +56,141 @@
#include "monetdb_config.h"
#include "gdk.h"
+/* The heap cache should reduce mmap/munmap calls which are very expensive.
+ * Instead we try to reuse mmap's. This however requires file renames.
+ * The cache has a limited size!
+ */
+
+#define HEAP_CACHE_SIZE 5
+
+typedef struct heap_cache_e {
+ void *base;
+ size_t maxsz;
+ char fn[PATHLENGTH]; /* tmp file name */
+} heap_cache_e;
+
+typedef struct heap_cache {
+ int sz;
+ int used;
+ heap_cache_e *hc;
+} heap_cache;
+
+static heap_cache *hc = NULL;
+static MT_Lock HEAPcacheLock;
+
+void
+HEAPcacheInit(void)
+{
+ if (!hc) {
+ MT_lock_init(&HEAPcacheLock, "HEAPcache_init");
+ gdk_set_lock(HEAPcacheLock, "HEAPcache_init");
+ hc = (heap_cache*)GDKmalloc(sizeof(heap_cache));
+ hc->used = 0;
+ hc->sz = HEAP_CACHE_SIZE;
+ hc->hc = (heap_cache_e*)GDKmalloc(sizeof(heap_cache_e)*hc->sz);
+ GDKcreatedir(HCDIR DIR_SEP_STR);
+ gdk_unset_lock(HEAPcacheLock, "HEAPcache_init");
+ }
+}
+
+static int
+HEAPcacheAdd( void *base, size_t maxsz, char *fn, int storage, int free_file )
+{
+ int added = 0;
+
+ if (free_file && fn && storage == STORE_MMAP && hc->used < hc->sz) {
+ gdk_set_lock(HEAPcacheLock, "HEAPcache_init");
+ if (hc->used < hc->sz) {
+ heap_cache_e *e = hc->hc+hc->used;
+
+ e->base = base;
+ e->maxsz = maxsz;
+ snprintf(e->fn, PATHLENGTH, "%d", hc->used);
+ GDKunlink(HCDIR, e->fn, NULL);
+ GDKmove(BATDIR, fn, NULL, HCDIR, e->fn, NULL);
+ hc->used++;
+ added = 1;
+ }
+ gdk_unset_lock(HEAPcacheLock, "HEAPcache_init");
+ }
+ if (!added)
+ return GDKmunmap(base, maxsz);
+ return 0;
+}
+
+static void *
+HEAPcacheFind( size_t *maxsz, char *fn, int mode )
+{
+ void *base = NULL;
+
+ *maxsz = (1 + (*maxsz >> 16)) << 16; /* round up to 64K */
+ if (mode == STORE_MMAP && hc->used < hc->sz) {
+ gdk_set_lock(HEAPcacheLock, "HEAPcache_init");
+
+ if (hc->used) {
+ /* Simply use first and extend
+ *
+ * if (hc->hc[0].maxsz < *maxsz) {
+ * only on linux we could use mremap.
+ * instead we do mmap before munmap.
+ * res = MT_mmap_remap(hdl, *maxsz - hc->hc[0].maxsz, hc->hc[0].maxsz)
+ */
+ if (hc->hc[0].maxsz < *maxsz) {
+ /* resize file ? */
+ FILE *fp;
+ long_str fn;
+ int mod = MMAP_READ | MMAP_WRITE | MMAP_SEQUENTIAL | MMAP_SYNC;
+ GDKfilepath(fn, HCDIR, hc->hc[0].fn, NULL);
+
+ if ((fp = fopen(fn, "rb+")) != NULL &&
+#ifdef _WIN64
+ _fseeki64(fp, (ssize_t) *maxsz-1, SEEK_SET) >= 0 &&
+#else
+#ifdef HAVE_FSEEKO
+ fseeko(fp, (off_t) *maxsz-1, SEEK_SET) >= 0 &&
+#else
+ fseek(fp, (long) *maxsz-1, SEEK_SET) >= 0 &&
+#endif
+#endif
+ fputc('\n', fp) >= 0 &&
+ fflush(fp) >= 0 &&
+ fclose(fp) >= 0) {
+ void *base = GDKload(fn, NULL, *maxsz, *maxsz, mod);
+ GDKmunmap(hc->hc[0].base, hc->hc[0].maxsz);
+ hc->hc[0].base = base;
+ hc->hc[0].maxsz = *maxsz;
+ }
+ }
+ base = hc->hc[0].base;
+ *maxsz = hc->hc[0].maxsz;
+ if (GDKmove(HCDIR, hc->hc[0].fn, NULL, BATDIR, fn, NULL)<0) {
+ /* try to create the directory, if that was the problem */
+ char path[PATHLENGTH];
+
+ GDKfilepath(path, BATDIR, fn, NULL);
+ GDKcreatedir(path);
+ GDKmove(HCDIR, hc->hc[0].fn, NULL, BATDIR, fn, NULL);
+ }
+ hc->used--;
+ if (hc->used) {
+ hc->hc[0].base = hc->hc[hc->used].base;
+ hc->hc[0].maxsz = hc->hc[hc->used].maxsz;
+ GDKmove(HCDIR, hc->hc[hc->used].fn, NULL, HCDIR, hc->hc[0].fn, NULL);
+ }
+ }
+ gdk_unset_lock(HEAPcacheLock, "HEAPcache_init");
+ }
+ if (!base) {
+ FILE *fp = GDKfilelocate(fn, "wb", NULL);
+
+ if (fp) {
+ fclose(fp);
+ return GDKload(fn, NULL, *maxsz, *maxsz, mode);
+ }
+ }
+ return base;
+}
+
static int HEAPload_intern(Heap *h, const char *nme, const char *ext, const char \
*suffix, int trunc); static int HEAPsave_intern(Heap *h, const char *nme, const char \
*ext, const char *suffix);
@@ -121,19 +256,29 @@
ALLOCDEBUG fprintf(stderr, "#HEAPalloc " SZFMT " " SZFMT " " PTRFMT "\n", h->size, \
h->maxsize, PTRFMTCAST h->base); }
if (h->filename && h->base == NULL) {
+ long_str ofn;
char *of = h->filename;
FILE *fp;
+ struct stat st;
h->filename = NULL;
- 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);
+
+ GDKfilepath(ofn, BATDIR, of, NULL);
+ if (stat(ofn, &st) != 0) {
+ h->storage = STORE_MMAP;
+ h->base = HEAPcacheFind(&h->maxsize, of, h->storage );
+ h->filename = of;
+ } else {
+ 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);
}
- GDKfree(of);
}
if (h->base == NULL) {
GDKerror("HEAPalloc: Insufficient space for HEAP of " SZFMT " bytes.", h->size);
@@ -385,14 +530,14 @@
simple: alloc and copy.
@{
@c
-int
-HEAPfree(Heap *h)
+static int
+HEAPfree_(Heap *h, int free_file)
{
if (h->base) {
if (h->storage == STORE_MEM) { /* plain memory */
GDKfree(h->base);
} else { /* mapped file, or STORE_PRIV */
- int ret = GDKmunmap(h->base, h->maxsize);
+ int ret = HEAPcacheAdd(h->base, h->maxsize, h->filename, h->storage, free_file);
if (ret < 0) {
GDKsyserror("HEAPfree: %s was not mapped\n", h->filename);
@@ -412,6 +557,12 @@
return 0;
}
+int
+HEAPfree(Heap *h)
+{
+ return HEAPfree_(h, 0);
+}
+
@}
@- HEAPload
@@ -561,22 +712,8 @@
assert(h->base == 0);
return 0;
}
- if (h->base) {
- if (h->copied == 0 && h->storage == STORE_MMAP) {
- /* truncate file, so OS does not try to flush
- dirty data in mmap to file that is deleted
- anyway */
- int ret, fd = GDKfdlocate(h->filename, "rb+", NULL);
- IODEBUG THRprintf(GDKout, "#HEAPdelete(%s) GDKfdlocate(\"rb+\") = %d\n", \
h->filename, fd);
-
- ret = ftruncate(fd, LL_CONSTANT(0));
- IODEBUG THRprintf(GDKout, "#HEAPdelete(%s) ftruncate(%d,0LL) = %d\n", \
h->filename, fd, ret);
-
- ret = close(fd);
- IODEBUG THRprintf(GDKout, "#HEAPdelete(%s) close(%d) = %d\n", h->filename, fd, \
ret);
- }
- HEAPfree(h);
- }
+ if (h->base)
+ HEAPfree_(h, 1);
if (h->copied) {
return 0;
}
diff --git a/gdk/gdk_search.mx b/gdk/gdk_search.mx
--- a/gdk/gdk_search.mx
+++ b/gdk/gdk_search.mx
@@ -625,9 +625,10 @@
hp = BBP_cache(p);
if ((!hp || b->H->hash != hp->H->hash) && b->H->hash != (Hash *) -1) {
- HEAPfree(b->H->hash->heap);
if (b->H->hash->heap->storage != STORE_MEM)
HEAPdelete(b->H->hash->heap, BBP_physical(b->batCacheid), (b->batCacheid > 0) ? \
"hhash" : "thash"); + else
+ HEAPfree(b->H->hash->heap);
GDKfree(b->H->hash->heap);
GDKfree(b->H->hash);
}
diff --git a/gdk/gdk_storage.mx b/gdk/gdk_storage.mx
--- a/gdk/gdk_storage.mx
+++ b/gdk/gdk_storage.mx
@@ -370,12 +370,12 @@
/* mmap storage is auto-extended here */
((fp = fopen(path, "rb+")) != NULL &&
#ifdef _WIN64
- _fseeki64(fp, (ssize_t) maxsize, SEEK_SET) >= 0 &&
+ _fseeki64(fp, (ssize_t) maxsize-1, SEEK_SET) >= 0 &&
#else
#ifdef HAVE_FSEEKO
- fseeko(fp, (off_t) maxsize, SEEK_SET) >= 0 &&
+ fseeko(fp, (off_t) maxsize-1, SEEK_SET) >= 0 &&
#else
- fseek(fp, (long) maxsize, SEEK_SET) >= 0 &&
+ fseek(fp, (long) maxsize-1, SEEK_SET) >= 0 &&
#endif
#endif
fputc('\n', fp) >= 0 &&
diff --git a/gdk/gdk_utils.mx b/gdk/gdk_utils.mx
_______________________________________________
Checkin-list mailing list
Checkin-list@monetdb.org
http://mail.monetdb.org/mailman/listinfo/checkin-list
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic