📄 gdk_bbp.c
字号:
MEMDEBUG THRprintf(GDKout, "#TRIMSCAN: mem=%d vm=%d, start=%d, limit=%d\n", mem, vm, (int) bbppos, (int) bbplim); if (bbppos < BBPsize) do { if (BBPvalid(bbppos)) { BAT *b = BBP_cache(bbppos); if (BBPtrimmable(b)) { /* when unloading for memory, treat small BATs with a preference over big ones. * rationale: I/O penalty for cache miss is relatively higher for small bats */ int swap_first = 0; ssize_t cnt = -1; if (b) { cnt = BATcount(b); swap_first = (cnt >= BBPSMALLBAT); } /* however, when we are looking to decrease the number of descriptors, * try to put the small bats in front of the load list instead.. */ /* subtract 2-billion to make sure the swap_first class bats are unloaded first */ bbptrim[bbptrimlast].lastused = BBPLASTUSED(BBP_lastused(bbppos)) | (swap_first << 31); bbptrim[bbptrimlast].bid = bbppos; bbptrim[bbptrimlast].cnt = cnt; if (++bbptrimlast == bbptrimmax) break; } } if (++bbppos == BBPsize) bbppos = 1; /* treat BBP as a circular buffer */ } while (bbppos != bbplim); if (bbptrimlast > 0) { int i; GDKqsort(bbptrim, NULL, bbptrimlast, sizeof(bbptrim_t), TYPE_int, 0); for (i = bbptrimfirst = 0; i < bbptrimlast; i++) { MEMDEBUG THRprintf(GDKout, "#TRIMSCAN: %11d%c %9d=%s\t(#" SSZFMT ")\n", BBPLASTUSED(bbptrim[i].lastused), (bbptrim[i].lastused & 0x80000000) ? '*' : ' ', i, BBPname(bbptrim[i].bid), bbptrim[i].cnt); bbptrim[i].next = i + 1; } bbptrim[bbptrimlast - 1].next = BBPMAXTRIM; } else { bbptrimfirst = BBPMAXTRIM; } MEMDEBUG THRprintf(GDKout, "#TRIMSCAN: end at %d (size=%d)\n", bbppos, (int) BBPsize); return bbppos;}/* insert BATs to unload from bbptrim list into bbpunload list; rebuild bbptrimlist only with the useful leftovers */static voidBBPtrim_select(size_t * memtarget, size_t * vmtarget, int dirty){ int bbptrimtail = BBPMAXTRIM, next = bbptrimfirst; MEMDEBUG THRprintf(GDKout, "#TRIMSELECT: dirty = %d\n", dirty ); /* make the bbptrim-list empty; we will insert the untouched elements in it */ bbptrimfirst = BBPMAXTRIM; while (next != BBPMAXTRIM) { int cur = next; /* cur is the entry in the old bbptrimlist we are processing */ int untouched = BBPLASTUSED(BBP_lastused(bbptrim[cur].bid)) <= BBPLASTUSED(bbptrim[cur].lastused); BAT *b = BBP_cache(bbptrim[cur].bid); next = bbptrim[cur].next; /* do now, because we overwrite bbptrim[cur].next below */ MEMDEBUG if (b) { THRprintf(GDKout, "#TRIMSELECT: candidate=%s BAT*=" PTRFMT "\n", BBPname(bbptrim[cur].bid), PTRFMTCAST(void *)b); THRprintf(GDKout, "# (cnt=" SSZFMT ", mode=%d, refs=%d, wait=%d, parent=%d, lastused=%d,%d,%d)\n", bbptrim[cur].cnt, b->batPersistence, BBP_refs(b->batCacheid), (BBP_status(b->batCacheid) & BBPWAITING) != 0, VIEWparent(b), BBP_lastused(b->batCacheid), BBPLASTUSED(bbptrim[cur].lastused), bbptrim[cur].lastused); } /* recheck if conditions encountered by trimscan in the past still hold */ if (BBPtrimmable(b) && untouched) { size_t memdelta = BATmemsize(b, FALSE); size_t vmdelta = BATvmsize(b, FALSE); size_t memdirty = BATmemsize(b, TRUE); size_t vmdirty = BATvmsize(b, TRUE); if (((b->batPersistence == TRANSIENT && BBP_lrefs(bbptrim[cur].bid) == 0) || /* needs not be saved when unloaded, OR.. */ (vmdirty == 0 && memdirty <= sizeof(BATstore)) || /* the BAT is actually clean, OR.. */ dirty) /* we are allowed to cause I/O (second run).. */ && /* AND ... */ ((*memtarget > 0 && (memdelta > 0)) || (*vmtarget > 0 && (vmdelta > 0)))) /* there is some reward in terms of memory requirements */ { /* only then we unload! */ MEMDEBUG { THRprintf(GDKout, "#TRIMSELECT: unload %s [" SZFMT "," SZFMT "] bytes [" SZFMT "," SZFMT "] dirty\n", BBPname(b->batCacheid), memdelta, vmdelta, memdirty, vmdirty); } BBP_status_on(bbptrim[cur].bid, BBPUNLOADING, "BBPtrim_select"); BBP_unload_inc(bbptrim[cur].bid, "BBPtrim_select"); *memtarget = *memtarget > memdelta ? *memtarget - memdelta : 0; *vmtarget = *vmtarget > vmdelta ? *vmtarget - vmdelta : 0; /* add to bbpunload list */ if (bbpunload == BBPMAXTRIM) { bbpunload = cur; } else { bbptrim[bbpunloadtail].next = cur; } bbptrim[cur].next = BBPMAXTRIM; bbpunloadtail = cur; } else if (!dirty) { /* do not unload now, but keep around; insert at the end of the new bbptrim list */ MEMDEBUG { THRprintf(GDKout, "#TRIMSELECT: keep %s [" SZFMT "," SZFMT "] bytes [" SZFMT "," SZFMT "] dirty target(mem=" SZFMT " vm=" SZFMT ")\n", BBPname(b->batCacheid), memdelta, vmdelta, memdirty, vmdirty, MAX(0, *memtarget), MAX(0, *vmtarget)); } if (bbptrimtail == BBPMAXTRIM) { bbptrimfirst = cur; } else { bbptrim[bbptrimtail].next = cur; } bbptrim[cur].next = BBPMAXTRIM; bbptrimtail = cur; } else { /* bats that even in the second (dirty) run are not selected, should be acquitted from the trimlist until a next scan */ MEMDEBUG THRprintf(GDKout, "#TRIMSELECT: delete %s from trimlist (does not match trim needs)\n", BBPname(bbptrim[cur].bid)); } } else { /* BAT was touched (or unloaded) since trimscan => it is discarded from both lists */ char buf[80], *bnme = BBP_logical(bbptrim[cur].bid); if (bnme == NULL) { bnme = BBPtmpname(buf, 64, bbptrim[cur].bid); } MEMDEBUG THRprintf(GDKout, "#TRIMSELECT: delete %s from trimlist (has been %s)\n", bnme, b ? "touched since last scan" : "unloaded already"); } if (*memtarget == 0 && *vmtarget == 0) { /* we're done; glue the rest of the old bbptrim list to the new bbptrim list */ if (bbptrimtail == BBPMAXTRIM) { bbptrimfirst = next; } else { bbptrim[bbptrimtail].next = next; } break; } } MEMDEBUG THRprintf(GDKout, "#TRIMSELECT: end\n");}extern int monet_exec(str);voidBBPtrim(size_t memtarget, size_t vmtarget){ int i, limit, scan, did_scan = FALSE; int msec = 0, bats_written = 0, bats_unloaded = 0; /* performance info */ MT_Id t = BBP_getpid(); PERFDEBUG msec = GDKms(); if (BBP_notrim == t) return; /* avoid deadlock by one thread going here twice */ gdk_set_lock(GDKtrimLock, "BBPtrim"); BBP_notrim = t; /* recheck targets to see whether the work was already done by another thread */ if (memtarget && memtarget != BBPTRIM_ALL) { memtarget = GDKmem_inuse(); if (memtarget > GDK_mem_maxsize) memtarget -= GDK_mem_maxsize; else memtarget = 0; } if (vmtarget && vmtarget != BBPTRIM_ALL) { vmtarget = GDKvm_cursize(); if (vmtarget > GDK_vm_maxsize) vmtarget -= GDK_vm_maxsize; else vmtarget = 0; } MEMDEBUG THRprintf(GDKout, "#BBPTRIM_ENTER: memsize=" SZFMT ",vmsize=" SZFMT "\n", GDKmem_inuse(), GDKvm_cursize()); MEMDEBUG THRprintf(GDKout, "#BBPTRIM: memtarget=" SZFMT " vmtarget=" SZFMT "\n", memtarget, vmtarget ); PERFDEBUG THRprintf(GDKout, "#BBPtrim(mem=%d,vm=%d)\n", memtarget > 0, vmtarget > 0 ); scan = (bbptrimfirst == BBPMAXTRIM); if (bbpscanstart >= BBPsize) bbpscanstart = 1; /* sometimes, the BBP shrinks! */ limit = bbpscanstart; while (memtarget > 0 || vmtarget > 0) { /* acquire the BBP locks */ gdk_set_lock(GDKcacheLock, "BBPtrim"); for (i = 0; i <= BBPLOCKMASK; i++) gdk_set_lock(GDKswapLock[i & BBPLOCKMASK], "BBPtrim"); /* gather a list of unload candidate BATs, but try to avoid scanning by reusing previous leftovers first */ if (scan) { did_scan = TRUE; bbpscanstart = BBPtrim_scan((memtarget > 0), (vmtarget > 0), bbpscanstart, limit); scan = (bbpscanstart != limit); } else { scan = TRUE; } /* decide which of the candidates to unload using LRU */ bbpunload = BBPMAXTRIM; BBPtrim_select(&memtarget, &vmtarget, FALSE); /* first try to select only clean BATs */ if (did_scan && (memtarget > 0 || vmtarget > 0)) { BBPtrim_select(&memtarget, &vmtarget, TRUE); /* if that is not enough, also unload dirty BATs */ } /* release the BBP locks */ for (i = 0; i <= BBPLOCKMASK; i++) gdk_unset_lock(GDKswapLock[i & BBPLOCKMASK], "BBPtrim"); gdk_unset_lock(GDKcacheLock, "BBPtrim"); /* do the unload work unlocked */ MEMDEBUG THRprintf(GDKout, "#BBPTRIM: %s\n", (bbpunload != BBPMAXTRIM) ? " lastused batid name" : "no more unload candidates!"); for (i = bbpunload; i != BBPMAXTRIM; i = bbptrim[i].next) { BAT *b = BBP_cache(bbptrim[i].bid); if (b == NULL || !(BBP_status(bbptrim[i].bid)&BBPUNLOADING)) { GDKwarning("BBPtrim: bat(%d) gone\n", bbptrim[i].bid); continue; } MEMDEBUG THRprintf(GDKout, "#BBPTRIM: %9d %7d %s\n", bbptrim[i].lastused, (int) bbptrim[i].bid, BBPname(bbptrim[i].bid)); bats_written += (b->batPersistence != TRANSIENT && BATdirty(b)); bats_unloaded++; BBPfree(b, "BBPtrim" ); } /* continue while we can scan for more candiates */ if (!scan) break; } /* done trimming */ MEMDEBUG THRprintf(GDKout, "#BBPTRIM_EXIT: memsize=" SZFMT ",vmsize=" SZFMT "\n", GDKmem_cursize(), GDKvm_cursize()); PERFDEBUG THRprintf(GDKout, "#BBPtrim(did_scan=%d, bats_unloaded=%d, bats_written=%d) %d ms\n", did_scan, bats_unloaded, bats_written, GDKms() - msec); BBP_notrim = 0; gdk_unset_lock(GDKtrimLock, "BBPtrim");}voidBBPhot(bat i){ if (i < 0) i = -i; if (BBPcheck(i, "BBPhot")) { int lock = locked_by ? BBP_getpid() != locked_by : 1; if (lock) gdk_set_lock(GDKswapLock[i & BBPLOCKMASK], "BBPhot"); BBP_lastused(i) = BBPLASTUSED(BBPstamp() + 30000); if (lock) gdk_unset_lock(GDKswapLock[i & BBPLOCKMASK], "BBPhot"); }}voidBBPcold(bat i){ if (i < 0) i = -i; if (BBPcheck(i, "BBPcold")) { int lock = locked_by ? BBP_getpid() != locked_by : 1; gdk_set_lock(GDKtrimLock, "BBPcold"); if (lock) gdk_set_lock(GDKswapLock[i & BBPLOCKMASK], "BBPcold"); /* make very cold and insert on top of trim list */ BBP_lastused(i) = 0; if (BBP_cache(i) && bbptrimlast < bbptrimmax) { bbptrim[--bbptrimmax].lastused = 0; bbptrim[bbptrimmax].bid = i; bbptrim[bbptrimmax].next = bbptrimfirst; bbptrimfirst = bbptrimmax; } if (lock) gdk_unset_lock(GDKswapLock[i & BBPLOCKMASK], "BBPcold"); gdk_unset_lock(GDKtrimLock, "BBPcold"); }}#line 2066 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB/src/gdk/gdk_bbp.mx"#line 2080 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB/src/gdk/gdk_bbp.mx"static intcomplexatom(int t, int delaccess){ if (t >= 0 && (BATatoms[t].atomFix || (delaccess && BATatoms[t].atomDel))) { return TRUE; } return FALSE;}BAT *BBPquickdesc(bat bid, int delaccess){ BAT *b = BBP_cache(bid); if (bid < 0) { GDKerror("BBPquickdesc: called with negative batid.\n"); return NULL; } if (b) { return b; /* already cached */ } b = (BAT *) BBPgetdesc(bid); if (b == NULL || complexatom(b->htype, delaccess) || complexatom(b->ttype, delaccess)) { b = BATload_intern(bid); BBPin++; } return b;}#line 2112 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB/src/gdk/gdk_bbp.mx"#line 2146 "/export/scratch0/monet/monet.GNU.64.64.d.14791/MonetDB/src/gdk/gdk_bbp.mx"#define BATCACHE_NOTYPE(t) (ATOMstorage(t) > TYPE_str || BATatoms[t].atomFix != NULL)#define BATCACHE_SIZE 64 /* max size: 128 */ #define BATCACHE_DIMS 6 /* 0,1,2,4,8 byte types + str */#define BATCACHE_BIN(h,t) (batcache_headbin[ATOMstorage(h)]+batcache_tailbin[ATOMstorage(t)])Dimensions batcache_dims; /* fast void,void bat dims initialization */int batcache_headbin[TYPE_str+1], batcache_tailbin[TYPE_str+1]; /* fast bin computation */typedef signed char batcache_int; /* make compact, whole structure is < 500 bytes: CPU cache resident */ssize_t batcache_minsize = BATTINY;/* O(1) lookup structure of normalized [htype,ttype] combination (a "bin") */static batcache_int batcache_batbin [BATCACHE_DIMS*BATCACHE_DIMS]; /* each bin starts a bin_next/prev list */static unsigned char batcache_widthbin[BATCACHE_DIMS*BATCACHE_DIMS]; /* bun width */static unsigned char batcache_locbin [BATCACHE_DIMS*BATCACHE_DIMS]; /* tloc *//* the list elements, use int as element pointer type (<0 means: no such element) */typedef struct { bat bid; batcache_int bin_next, bin_prev; /* doubly linked list that connects all BATs for a bin */ batcache_int fifo_next, fifo_prev; /* doubly linked list for getting the LRU BAT O(1) */} batcache_t;batcache_t batcache[BATCACHE_SIZE];/* fifo queue */static batcache_int batcache_first = -1; static batcache_int batcache_last = -1;/* free list */static batcache_int batcache_free = -1; /* misuses ->fifo_next for connecting the list */static voidBBPinitcache(void){ batcache_int i; int j; /* initialize struct for fast void,void header initialization */ batcache_dims.headtype = batcache_dims.tailtype = TYPE_void; batcache_dims.headloc = batcache_dims.tailloc = 0; batcache_dims.headkey = batcache_dims.tailkey = FALSE; batcache_dims.headvarsized = batcache_dims.tailvarsized = TRUE; batcache_dims.bunshift = 0; batcache_dims.bunwidth = 1; batcache_dims.hseq = batcache_dims.tseq = oid_nil; /* initialize the type remap arrays */ for(i = 0; i < TYPE_str; i++) { int k = 0; for(j = ATOMsize(i); j; j/=2) k++; batcache_headbin[i] = k; batcache_tailbin[i] = k*BATCACHE_DIMS; } batcache_headbin[i] = 5; batcache_tailbin[i] = 5*BATCACHE_DIMS; /* TYPE_str */ /* initialize the bun loc/width lookup arrays */ for(i = 0; i <= TYPE_str; i++) { for(j = 0; j <= TYPE_str; j++) { int bin = BATCACHE_BIN(i,j); short bunwidth = ATOMsize(j); short tailloc = ATOMsize(i); if (tailloc > bunwidth) { bunwidth = tailloc + tailloc; } else if (tailloc) { bunwidth += (tailloc = bunwidth); } else if (bunwidth == 0) { bunwidth = 1; } assert(bunwidth < 256); assert(tailloc < 256); batcache_widthbin[bin] = (unsigned char) bunwidth; batcache_locbin[bin] = (unsigned char) tailloc; } } /* initialize the cache */ for(i = 0; i < BATCACHE_SIZE; i++) { batcache[i].bid = 0; batcache[i].fifo_next = i+1; batcache[i].fifo_prev = i-1; batcache[i].bin_next = -1; batcache[i].bin_prev = -1; } batcache[BATCACHE_SIZE-1].fifo_next = -1; /* initialize the lookup mechanism */ for(j = 0; j < BATCACHE_DIMS*BATCACHE_DIMS; j++) { batcache_batbin[j] = -1; } batcache_free = 0;}/* throw the LRU bat out using the fifo list */static INLINE batcache_int batcache_del(void){ batcache_int i = batcache_first; bat bid = batcache[i].bid; BAT *b = BBP_cache(bid); int bin = BATCACHE_BIN(b->htype,b->ttype); /* manage bin-list */ batcache_int j = batcache[i].bin_prev; if (j >= 0) { batcache[j].bin_next = -1; } else { batcache_batbin[bin] = -1; /* had a single entry only */ } assert(batcache[i].bin_next < 0); /* LRU: we are always deleting the last */ /* manage fifo-list */ batcache_first = batcache[i].fifo_next; if (batcache_first >= 0) { batcache[batcache_first].fifo_prev = -1; } else { batcache_last = -1; } /* revive and free the old bat */ *BBP_logical(bid) = 't'; assert(b->batParentid == 0); BATfree(b); bbpclear(bid); return i;}/* insert a new bat into the cache */static INLINE int batcache_put(int bin, bat bid) { /* get a free slot */ batcache_int j, i = batcache_free; if (i >= 0) { batcache_free = batcache[i].fifo_next; } else { i = batcache_del(); /* delete a bat from the cache */ } /* fill in the batcache record */ batcache[i].bid = bid; batcache[i].bin_next = j = batcache_batbin[bin]; if (j >= 0) batcache[j].bin_prev = i; batcache[i].bin_prev = -1; batcache[i].fifo_next = -1; batcache[i].fifo_prev = batcache_last; batcache_batbin[bin] = i; if (batcache_first < 0) batcache_first = i; if (batcache_last >= 0) batcache[batcache_last].fifo_next = i; batcache_last = i; *BBP_logical(bid) = '.'; /* make the bat a zombie */ return i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -