📄 mal_debugger.mx
字号:
b = BATdescriptor(v->val.ival); if (b) { nme = getTypeName(n->type); nmeOnStk = getTypeName(newBatType(b->htype, b->ttype)); if (strcmp(nme, nmeOnStk)) { printTraceCall(cntxt,mb,stk,pc); stream_printf(cntxt->fdout, "!ERROR: %s != :%s\n", nme, nmeOnStk); stk->cmd='n'; } BBPunfix(b->batCacheid); GDKfree(nme); } } }}voidmdbStep(Client cntxt, MalBlkPtr mb, MalStkPtr stk, int pc){ InstrPtr p; char ch; mdbSessionActive= 1; /* for name completion */ /* mdbSanityCheck(cntxt, mb, stk, pc); expensive */ switch (stk->cmd) { case 'c': p = getInstrPtr(mb, pc); ch= isBreakpoint(cntxt,mb, p, pc); if( ch == 't'){ if (cntxt != mal_clients) /* help MapiClients with fake prompt */ stream_printf(cntxt->fdout,"mdb>"); printTraceCall(cntxt,mb,stk,pc); } else if( ch ) mdbCommand(cntxt, mb, stk, p, pc); break; case 's': case 'n': p = getInstrPtr(mb, pc); mdbCommand(cntxt, mb, stk, p, pc); break; case 'C': mdbSessionActive= 0; /* for name completion */ } if( mb->errors) { MalStkPtr su; /* return from this debugger */ for (su = stk; su; su = su->up) su->cmd = 0; stk->cmd = 'x'; /* will force a graceful termination */ } if( mdbSessionActive== 0) return; showErrors(); if (cntxt->flags & timerFlag) cntxt->timer = GDKusec(); mdbSessionActive= 0; /* for name completion */}@-It would come in handy if at any time you could activatethe debugger on a specific function. This calls for thecreation of a minimal execution environment first.@cstrrunMALDebugger(Symbol s){ Client c = MCgetClient(); c->itrace = 'n'; runMAL(c, s->def, 1, 0, 0, 0); return MAL_SUCCEED;}@+ UtilitiesDumping a stack on a file is primarilly used for debugging.Printing the stack requires access to both the symbol table andthe stackframes in most cases.Beware that a stack frame need not be initialized with null values.It has been zeroed upon creation.The routine can also be used to inspect the symbol table ofarbitrary functions.@cvoidprintStack(stream *f, MalBlkPtr mb, MalStkPtr s,int lifespan){ int i = 0; if (s) { stream_printf(f, "#Stack '%s' size=%d top=%d\n", getInstrPtr(mb, 0)->fcnname, s->stksize, s->stktop); for (; i < mb->vtop; i++) printStackElm(f, mb, getVar(mb, i), s->stk + i, i, 0, 0,lifespan); } else for (; i < mb->vtop; i++) printStackElm(f, mb, getVar(mb, i), 0, i, 0, 0,lifespan);}voidprintBATelm(stream *f, int i, size_t cnt, size_t first){ BAT *b, *bs; str tpe ,nme; b = BATdescriptor(i); if (b) { nme= BATgetId(b); tpe = getTypeName(newBatType(b->htype, b->ttype)); /* ignore ref count of this call */ stream_printf(f, "[%d] %s %s count=%d lrefs=%d refs=%d \n", i, nme, tpe, BATcount(b), BBP_lrefs(ABS(b->batCacheid)), BBP_refs(ABS(b->batCacheid)) - 1); /* perform property checking */ if( b->H != b->T) BATpropcheck(BATmirror(b),BATPROPS_QUICK); BATpropcheck(b,BATPROPS_QUICK); if( cnt){ if (cnt < BATcount(b)) { stream_printf(f, "Sample %d out of %d\n", cnt, BATcount(b)); } /* cut out a portion of the BAT for display */ bs = BATslice(b, first, first + cnt); if (bs == NULL) stream_printf(f, "Failed to take chunk\n"); else BATmultiprintf(f, 2, &bs, TRUE, 0, TRUE); BBPunfix(bs->batCacheid); } BBPunfix(b->batCacheid); GDKfree(tpe); }}voidprintStackElm(stream *f, MalBlkPtr mb, VarPtr n, ValPtr v, int index, size_t cnt, int first, int lifespan){ str nme, nmeOnStk; char nmebuf[PATHLENGTH]; (void) mb; /* fool the compiler */ if (n->tmpindex) { snprintf(nmebuf, PATHLENGTH, "%c%d", TMPMARKER, n->tmpindex); nme = nmebuf; } else nme = n->name; if( lifespan) { stream_printf(f, "#[%d,%d:%d,%d] ", index, n->beginLifespan, n->endLifespan,n->lastUpdate); if( isVarGarbage(mb,index) ) stream_printf(f,"G "); stream_printf(f, " %s\t= ", nme); } else stream_printf(f, "#[%d] %s\t= ", index, nme); /* if (n->type == TYPE_void) stream_printf(f, "nil"); else */ if (v) ATOMprint(v->vtype, VALptr(v), f); nme = getTypeName(n->type); stream_printf(f, ":%s", nme); if( lifespan && n->isudftype) stream_printf(f," udftype"); nmeOnStk = v ? getTypeName(v->vtype) : GDKstrdup(nme); if (strcmp(nmeOnStk, nme)) { if (isaBatType(n->type)) { BAT *b; b = BATdescriptor(v->val.ival); if (b) { nmeOnStk = getTypeName(newBatType(b->htype, b->ttype)); if (strcmp(nme, nmeOnStk)) stream_printf(f, " != :%s", nmeOnStk); BBPunfix(b->batCacheid); } } else if (!(isaBatType(n->type) && strcmp(nmeOnStk, "BAT") == 0)) stream_printf(f, " != %s", nmeOnStk); } stream_printf(f, " %s", (n->isaconstant ? " constant" : "")); stream_printf(f, " %s", (n->isused==0 ? " not used" : "")); stream_printf(f, " %s", (n->isatypevar ? " type variable" : "")); GDKfree(nme); GDKfree(nmeOnStk); if (cnt && isaBatType(n->type) && v && v->val.ival) { BAT *b, *bs; b = BATdescriptor(v->val.ival); if (b == NULL) { stream_printf(f, "Could not access descriptor\n"); return; } stream_printf(f, "\n"); if (cnt <= BATcount(b)) { stream_printf(f, "Sample %d out of %d\n", cnt, BATcount(b)); } /* cut out a portion of the BAT for display */ bs = BATslice(b, first, first + cnt); if (bs == NULL) stream_printf(f, "Failed to take chunk\n"); else BATmultiprintf(f, 2, &bs, TRUE, 0, TRUE); BBPunfix(bs->batCacheid); BBPunfix(b->batCacheid); } else if (isaBatType(n->type) && v) { BAT *b; b = BATdescriptor(v->val.ival); if (b) { /* ignore ref count of this call */ stream_printf(f, " count=%d lrefs=%d refs=%d", BATcount(b), BBP_lrefs(ABS(b->batCacheid)), BBP_refs(ABS(b->batCacheid)) - 1); BBPunfix(b->batCacheid); } } if( n->props){ nme= propertySet2str(n->props); stream_printf(f,"%s",nme); GDKfree(nme); } stream_printf(f, "\n");}voidprintBatInfo(stream *f, VarPtr n, ValPtr v){ if (isaBatType(n->type) && v->val.ival) { int bid; int ret; MALfcn fcn; fcn = getAddress("bat","bat","BKCinfo", 0); if (fcn) { BAT *b; bid = v->val.ival; stream_printf(f, "Show info for %d\n", bid); (*fcn) (&ret, &bid); b = BATdescriptor(ret); if (b == NULL) { stream_printf(f, "Could not access descriptor\n"); return; } BATmultiprintf(f, 2, &b, TRUE, 0, TRUE); BBPunfix(b->batCacheid); } }}voidprintBatProperties(stream *f, VarPtr n, ValPtr v, str props){ if (isaBatType(n->type) && v->val.ival) { int bid; int ret; MALfcn fcn; BUN p; fcn = getAddress("bat","bat","BKCinfo", 0); if (fcn) { BAT *b; bid = v->val.ival; stream_printf(f, "BAT %d %s= ", bid,props); (*fcn) (&ret, &bid); b = BATdescriptor(ret); if (b == NULL) { stream_printf(f, "Could not access descriptor\n"); return; } p= BUNfnd(b,props); if( p) { stream_printf(f," %s\n", (str) BUNtail(b,p)); } else stream_printf(f," not found\n"); BBPunfix(b->batCacheid); } }}@-The memory positions for the BATs is useful information toasses for memory fragmentation.@= heapinfohp= b->@1;if(hp && hp->base){ stream_printf(GDKout,"\t@1=%d size=%d\n",hp->base, hp->size);}@= hashinfoh= b->@1;if(h && h->mask){ stream_printf(GDKout,"\t@1=%d size=%d\n",h, sizeof(*h)); stream_printf(GDKout,"\t@1link=%d size=%d\n",h->link, (h->mask+h->lim+1)*sizeof(int));}@-The memProfileVector routine produces a character string to representthe usage of memory by BAT information. The characters are interpretedas follows:.=unused, X=completely used, [0-9]=small elements within the granuleMore then 9 elements makes it full.@= setVector start= (((long)@1)-min)/granule; lim= (((long)@1)-min + @2)/granule; stream_printf(GDKout,"start %d lim %d\n",start,lim);@cstrmemProfileVector(int cells){ str v = GDKmalloc(cells + 1); int i;#ifdef HAVE_SBRK long max = (long) sbrk(0); long min = 0; long granule = 0;#endif if (cells <= 0) { showException(MAL,"memProfileVector", "positive argument expected"); return GDKstrdup(""); } v = GDKmalloc(cells + 1); if (v == 0) GDKfatal("memProfileVector:malloc failure\n"); for (i = 0; i < cells; i++) v[i] = '.'; v[i] = 0; for (i = 1; i < BBPsize; i++) if (BBP_status(i) & BBPLOADED) { BAT *b = BATdescriptor(i); Heap *hp; Hash *h;#ifdef HAVE_SBRK long start, lim;#endif stream_printf(GDKout, "\tdesc=%d size=%d\n", b, sizeof(*b)); hp = b->batBuns; stream_printf(GDKout, "\tbuns=%d size=%d\n", hp->base, hp->size);#ifdef HAVE_SBRK if (min == 0) { min = (long) b; max = min + GDKmem_heapsize(); granule = (max - min) / cells; stream_printf(GDKout, "granule %dK\n", granule / 1024); } @:setVector(b, sizeof(*b))@ @:setVector(hp->base, hp->size)@#endif @:heapinfo(hheap)@ @:heapinfo(theap)@ @:hashinfo(hhash)@ @:hashinfo(thash)@ BBPunfix(b->batCacheid); } return v;}voidprintBBPinfo(stream *out){ str v; stream_printf(out, "#BBP memory layout\n"); stream_printf(out, "#heap maximum =%d/M\n", GDKmem_heapsize() / (1024 * 1024)); v = memProfileVector(32); stream_printf(out, "#%s\n", v); GDKfree(v);#ifdef GDK_VM_KEEPHISTO stream_printf(out, "#BBP VM history available\n");#else stream_printf(out, "#BBP VM history not available\n");#endif}@-Some utilities for the debugger@cvoidmdbHelp(stream *f){ stream_printf(f, "next -- Advance to next statement\n"); stream_printf(f, "continue -- Continue program being debugged\n"); stream_printf(f, "catch -- Catch the next exception \n"); stream_printf(f, "break [<var>] -- set breakpoint on current instruction or <var>\n"); stream_printf(f, "delete [<var>] -- remove break/trace point <var>\n"); stream_printf(f, "debug <int> -- set kernel debugging mask\n"); stream_printf(f, "dot [<int>] [<file>] -- generate the dependency graph\n"); stream_printf(f, "step -- advance to next MAL instruction\n"); stream_printf(f, "module -- display a module signatures\n"); stream_printf(f, "atom -- show atom list\n"); stream_printf(f, "finish -- finish current call\n"); stream_printf(f, "exit -- terminate executionr\n"); stream_printf(f, "quit -- turn off debugging\n"); stream_printf(f, "list <obj> -- list current program block\n"); stream_printf(f, "List <obj> -- list with type information\n"); stream_printf(f, "var <obj> -- print symbol table for module\n"); stream_printf(f, "optimizer <obj> -- display program after optimizer step\n"); stream_printf(f, "print <var> -- display value of a variable\n"); stream_printf(f, "print <var> <cnt>[<first>] -- display BAT chunk\n"); stream_printf(f, "info <var> -- display bat variable properties\n"); stream_printf(f, "run -- restart current procedure\n"); stream_printf(f, "where -- print stack trace\n"); stream_printf(f, "down -- go down the stack\n"); stream_printf(f, "up -- go up the stack\n"); stream_printf(f, "trace <var> -- trace assignment to variables\n"); stream_printf(f, "set {timer,flow,io,memory} -- set trace switches\n"); stream_printf(f, "unset -- turn off switches\n"); stream_printf(f, "help -- this message\n");}@+ Optimizer debuggingThe modular approach to optimize a MAL program brings with it theneed to check individual steps. Two options come to mind. If indebug mode we could stop after each optimizer action for inspection.Alternatively, we keep a history of all MAL program versions foraposteriori analysis.The latter is implemented first.A global stack is used for simplity, later we may have tomake it thread safe by assigning it to a client record.@cint isInvariant(MalBlkPtr mb, int pcf, int pcl, int varid);strdebugOptimizers(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){ Client cntxt = MCgetClient(); (void) stk; cntxt->debugOptimizer = cntxt->debugOptimizer ? FALSE : TRUE; if (pci) removeInstruction(mb, pci); return MAL_SUCCEED;}@}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -