/* * Determine the variables being used and clear non-used onces. */ void MSresetVariables(Client cntxt, MalBlkPtr mb, MalStkPtr glb, int start) { int i; bit *used = GDKzalloc(mb->vtop * sizeof(bit)); if( used == NULL){ GDKerror("MSresetVariables" MAL_MALLOC_FAIL); return; } for (i = 0; i < start && start < mb->vtop; i++) used[i] = 1; if (mb->errors == 0) for (i = start; i < mb->vtop; i++) { if (used[i] || !isTmpVar(mb, i)) { assert(!mb->var[i]->value.vtype || isVarConstant(mb, i)); used[i] = 1; } if (glb && !used[i]) { if (isVarConstant(mb, i)) garbageElement(cntxt, &glb->stk[i]); /* clean stack entry */ glb->stk[i].vtype = TYPE_int; glb->stk[i].len = 0; glb->stk[i].val.pval = 0; } } if (mb->errors == 0) trimMalVariables_(mb, used, glb); GDKfree(used); }
/* barrier blocks can only be dropped when they are fully excluded. */ static int OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb) { /* catch and remove constant bounded blocks */ int i, j = 0, action = 0, block = 0, skip = 0, top =0, skiplist[10]; InstrPtr p; for (i = 0; i < mb->stop; i++) { p = mb->stmt[i]; if (blockStart(p)) { block++; if (p->argc == 2 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit && getVarConstant(mb, getArg(p, 1)).val.btval == 0) { if (skip == 0) skip = block; action++; } // Try to remove the barrier statement itself (when true). if (p->argc == 2 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit && getVarConstant(mb, getArg(p, 1)).val.btval == 1 && top <10 && OPTsimpleflow(mb,i)) { skiplist[top++]= getArg(p,0); freeInstruction(p); continue; } } if (blockExit(p)) { if (top > 0 && skiplist[top-1] == getArg(p,0) ){ top--; freeInstruction(p); continue; } if (skip ) freeInstruction(p); else mb->stmt[j++] = p; if (skip == block) skip = 0; block--; if (block == 0) skip = 0; } else if (skip) freeInstruction(p); else mb->stmt[j++] = p; } mb->stop = j; for (; j < i; j++) mb->stmt[j] = NULL; if (action) { chkTypes(cntxt->fdout, cntxt->nspace, mb, TRUE); return mb->errors ? 0 : action; } return action; }
/* barrier blocks can only be dropped when they are fully excluded. */ static str OPTremoveUnusedBlocks(Client cntxt, MalBlkPtr mb) { /* catch and remove constant bounded blocks */ int i, j = 0, action = 0, block = -1, skip = 0, multipass = 1; InstrPtr p; str msg = MAL_SUCCEED; while(multipass--){ block = -1; skip = 0; j = 0; for (i = 0; i < mb->stop; i++) { p = mb->stmt[i]; if (blockExit(p) && block == getArg(p,0) ){ block = -1; skip = 0; freeInstruction(p); mb->stmt[i]= 0; continue; } if (p->argc == 2 && blockStart(p) && block < 0 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit ){ if( getVarConstant(mb, getArg(p, 1)).val.btval == 0) { block = getArg(p,0); skip ++; action++; } // Try to remove the barrier statement itself (when true). if ( getVarConstant(mb, getArg(p, 1)).val.btval == 1 && OPTsimpleflow(mb,i)) { block = getArg(p,0); skip = 0; action++; freeInstruction(p); mb->stmt[i]= 0; continue; } } else if( p->argc == 2 && blockStart(p) && block >= 0 && skip == 0 && isVarConstant(mb, getArg(p, 1)) && getArgType(mb, p, 1) == TYPE_bit && multipass == 0) multipass++; if (skip){ freeInstruction(p); mb->stmt[i]= 0; } else mb->stmt[j++] = p; } mb->stop = j; for (; j < i; j++) mb->stmt[j] = NULL; } if (action) chkTypes(cntxt->usermodule, mb, TRUE); return msg; }
str OPTsql_append(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){ str modnme; str fcnnme; str msg= MAL_SUCCEED; Symbol s= NULL; lng t,clk= GDKusec(); int actions = 0; if( p ) removeInstruction(mb, p); OPTDEBUGsql_append mnstr_printf(cntxt->fdout,"=APPLY OPTIMIZER sql_append\n"); if( p && p->argc > 1 ){ if( getArgType(mb,p,1) != TYPE_str || getArgType(mb,p,2) != TYPE_str || !isVarConstant(mb,getArg(p,1)) || !isVarConstant(mb,getArg(p,2)) ) { throw(MAL, "optimizer.sql_append", ILLARG_CONSTANTS); } if( stk != 0){ modnme= *getArgReference_str(stk,p,1); fcnnme= *getArgReference_str(stk,p,2); } else { modnme= getArgDefault(mb,p,1); fcnnme= getArgDefault(mb,p,2); } s= findSymbol(cntxt->nspace, putName(modnme,strlen(modnme)),putName(fcnnme,strlen(fcnnme))); if( s == NULL) { char buf[1024]; snprintf(buf,1024, "%s.%s",modnme,fcnnme); throw(MAL, "optimizer.sql_append", RUNTIME_OBJECT_UNDEFINED ":%s", buf); } mb = s->def; stk= 0; } if( mb->errors ){ /* when we have errors, we still want to see them */ addtoMalBlkHistory(mb,"sql_append"); return MAL_SUCCEED; } actions= OPTsql_appendImplementation(cntxt, mb,stk,p); msg= optimizerCheck(cntxt, mb, "optimizer.sql_append", actions, t=(GDKusec() - clk)); OPTDEBUGsql_append { mnstr_printf(cntxt->fdout,"=FINISHED sql_append %d\n",actions); printFunction(cntxt->fdout,mb,0,LIST_MAL_ALL ); } DEBUGoptimizers mnstr_printf(cntxt->fdout,"#opt_reduce: " LLFMT " ms\n",t); QOTupdateStatistics("sql_append",actions,t); addtoMalBlkHistory(mb,"sql_append"); return msg; }
static int OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p) { int i; (void)cntxt; if ( !(p->token == ASSIGNsymbol || getModuleId(p) == calcRef || getModuleId(p) == strRef || getModuleId(p) == mtimeRef || getModuleId(p) == mmathRef)) return FALSE; if (getModuleId(p) == mmathRef && strcmp(getFunctionId(p), "rand") == 0) return FALSE; for (i = p->retc; i < p->argc; i++) if (isVarConstant(mb, getArg(p, i)) == FALSE) return FALSE; for (i = 0; i < p->retc; i++) { if (isaBatType(getArgType(mb, p, i))) return FALSE; if ( mb->unsafeProp ) return FALSE; } return TRUE; }
/* the MAL beautifier is meant to simplify correlation of MAL variables and * the columns in the underlying database. * If the status is set, then we consider the instruction DONE and the result variables * should be shown as well. */ static str shortRenderingTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx) { str s, nme; BAT *b; ValRecord *val; char *cv =0; int varid = getArg(p,idx); size_t len = BUFSIZ; s= GDKmalloc(len); if( s == NULL) return NULL; *s = 0; if( isVarConstant(mb,varid) ){ val =&getVarConstant(mb, varid); if ((cv = VALformat(val)) == NULL) { GDKfree(s); return NULL; } if (strlen(cv) >= len) { char *nbuf; len = strlen(cv); nbuf = GDKrealloc(s, len + 1); if (nbuf == NULL) { GDKfree(s); GDKfree(cv); return NULL; } s = nbuf; } snprintf(s,len + 1,"%s",cv); } else { val = &stk->stk[varid]; if ((cv = VALformat(val)) == NULL) { GDKfree(s); return NULL; } nme = getVarName(mb, varid); if ( isaBatType(getArgType(mb,p,idx))){ b = BBPquickdesc(stk->stk[varid].val.bval, true); snprintf(s,BUFSIZ,"%s["BUNFMT"]" ,nme, b?BATcount(b):0); } else snprintf(s,BUFSIZ,"%s=%s ",nme,cv); } GDKfree(cv); return s; }
static int OPTallConstant(Client cntxt, MalBlkPtr mb, InstrPtr p) { int i; (void)cntxt; if ( !( p->token == ASSIGNsymbol || getModuleId(p) == calcRef || getModuleId(p) == strRef || getModuleId(p) == mmathRef )) return FALSE; for (i = p->retc; i < p->argc; i++) if (isVarConstant(mb, getArg(p, i)) == FALSE) return FALSE; for (i = 0; i < p->retc; i++) if (isaBatType(getArgType(mb, p, i))) return FALSE; return p->argc != p->retc; }
/* the MAL beautifier is meant to simplify correlation of MAL variables and * the columns in the underlying database. * If the status is set, then we consider the instruction DONE and the result variables * should be shown as well. */ static str shortRenderingTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx) { str s, nme; BAT *b; ValRecord *val; char *cv =0; int varid = getArg(p,idx); s= GDKmalloc(BUFSIZ); if( s == NULL) return NULL; *s = 0; if( isVarConstant(mb,varid) ){ val =&getVarConstant(mb, varid); VALformat(&cv, val); snprintf(s,BUFSIZ,"%s",cv); } else { val = &stk->stk[varid]; VALformat(&cv, val); nme = getSTC(mb, varid); if( nme == NULL) nme = getVarName(mb, varid); if ( isaBatType(getArgType(mb,p,idx))){ b = BBPquickdesc(abs(stk->stk[varid].val.ival),TRUE); snprintf(s,BUFSIZ,"%s["BUNFMT"]" ,nme, b?BATcount(b):0); } else if( cv) snprintf(s,BUFSIZ,"%s=%s ",nme,cv); else snprintf(s,BUFSIZ,"%s ",nme); } GDKfree(cv); return s; }
str runFactory(Client cntxt, MalBlkPtr mb, MalBlkPtr mbcaller, MalStkPtr stk, InstrPtr pci) { Plant pl=0; int firstcall= TRUE, i, k; InstrPtr psig = getInstrPtr(mb, 0); ValPtr lhs, rhs; char cmd; str msg; #ifdef DEBUG_MAL_FACTORY fprintf(stderr, "#factoryMgr called\n"); #endif /* the lookup can be largely avoided by handing out the index upon factory definition. todo Alternative is to move them to the front */ for(i=0; i< lastPlant; i++) if( plants[i].factory == mb){ if(i > 0 && i< lastPlant ){ PlantRecord prec= plants[i-1]; plants[i-1] = plants[i]; plants[i]= prec; i--; } pl= plants+i; firstcall= FALSE; break; } if (pl == 0) { /* compress the plant table*/ for(k=i=0;i<=lastPlant; i++) if( plants[i].inuse) plants[k++]= plants[i]; lastPlant = k; /* initialize a new plant using the owner policy */ pl = newPlant(mb); if (pl == NULL) throw(MAL, "factory.new", SQLSTATE(HY001) MAL_MALLOC_FAIL); } /* * We have found a factory to process the request. * Let's call it as a synchronous action, without concern on parallelism. */ /* remember context */ pl->client = cntxt; pl->caller = mbcaller; pl->env = stk; pl->pci = pci; pl->inuse = 1; /* inherit debugging */ cmd = stk->cmd; if ( pl->stk == NULL) throw(MAL, "factory.new", "internal error, stack frame missing"); /* copy the calling arguments onto the stack of the factory */ i = psig->retc; for (k = pci->retc; i < pci->argc; i++, k++) { lhs = &pl->stk->stk[psig->argv[k]]; /* variable arguments ? */ if (k == psig->argc - 1) k--; rhs = &pl->env->stk[getArg(pci, i)]; if (VALcopy(lhs, rhs) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); if( lhs->vtype == TYPE_bat ) BBPretain(lhs->val.bval); } if (mb->errors) throw(MAL, "factory.call", PROGRAM_GENERAL); if (firstcall ){ /* initialize the stack */ for(i= psig->argc; i< mb->vtop; i++) { lhs = &pl->stk->stk[i]; if( isVarConstant(mb,i) > 0 ){ if( !isVarDisabled(mb,i)){ rhs = &getVarConstant(mb,i); if (VALcopy(lhs,rhs) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); } } else{ lhs->vtype = getVarGDKType(mb,i); lhs->val.pval = 0; lhs->len = 0; } } pl->stk->stkbot= mb->vtop; /* stack already initialized */ msg = runMAL(cntxt, mb, 0, pl->stk); } else { msg = reenterMAL(cntxt, mb, pl->pc, -1, pl->stk); } /* propagate change in debugging status */ if (cmd && pl->stk && pl->stk->cmd != cmd && cmd != 'x') for (; stk; stk = stk->up) stk->cmd = pl->stk->cmd; return msg; }
str OPTwrapper (Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){ str modnme = "(NONE)"; str fcnnme = 0; str msg= MAL_SUCCEED; Symbol s= NULL; lng t,clk= GDKusec(); int i, actions = 0; char optimizer[256]; InstrPtr q; if( p == NULL) throw(MAL, "opt_wrapper", "missing optimizer statement"); snprintf(optimizer,256,"%s", fcnnme = getFunctionId(p)); q= copyInstruction(p); OPTIMIZERDEBUG mnstr_printf(cntxt->fdout,"=APPLY OPTIMIZER %s\n",fcnnme); if( p && p->argc > 1 ){ if( getArgType(mb,p,1) != TYPE_str || getArgType(mb,p,2) != TYPE_str || !isVarConstant(mb,getArg(p,1)) || !isVarConstant(mb,getArg(p,2)) ) { freeInstruction(q); throw(MAL, optimizer, ILLARG_CONSTANTS); } if( stk != 0){ modnme= *getArgReference_str(stk,p,1); fcnnme= *getArgReference_str(stk,p,2); } else { modnme= getArgDefault(mb,p,1); fcnnme= getArgDefault(mb,p,2); } removeInstruction(mb, p); s= findSymbol(cntxt->nspace, putName(modnme,strlen(modnme)),putName(fcnnme,strlen(fcnnme))); if( s == NULL) { freeInstruction(q); throw(MAL, optimizer, RUNTIME_OBJECT_UNDEFINED ":%s.%s", modnme, fcnnme); } mb = s->def; stk= 0; } else if( p ) removeInstruction(mb, p); if( mb->errors ){ /* when we have errors, we still want to see them */ addtoMalBlkHistory(mb,getModuleId(q)); freeInstruction(q); return MAL_SUCCEED; } for ( i=0; codes[i].nme; i++) if ( strcmp(codes[i].nme, optimizer)== 0 ){ actions = (int)(*(codes[i].fcn))(cntxt, mb, stk,0); break; } if ( codes[i].nme == 0){ freeInstruction(q); throw(MAL, optimizer, RUNTIME_OBJECT_UNDEFINED ":%s.%s", modnme, fcnnme); } msg= optimizerCheck(cntxt, mb, optimizer, actions, t=(GDKusec() - clk)); OPTIMIZERDEBUG { mnstr_printf(cntxt->fdout,"=FINISHED %s %d\n",optimizer, actions); printFunction(cntxt->fdout,mb,0,LIST_MAL_DEBUG ); } DEBUGoptimizers mnstr_printf(cntxt->fdout,"#optimizer %-11s %3d actions %5d MAL instructions ("SZFMT" K) " LLFMT" usec\n", optimizer, actions, mb->stop, ((sizeof( MalBlkRecord) +mb->ssize * offsetof(InstrRecord, argv)+ mb->vtop * sizeof(int) /* argv estimate */ +mb->vtop* sizeof(VarRecord) + mb->vsize*sizeof(VarPtr)+1023)/1024), t); QOTupdateStatistics(getModuleId(q),actions,t); addtoMalBlkHistory(mb,getModuleId(q)); freeInstruction(q); return msg; }
int inlineMALblock(MalBlkPtr mb, int pc, MalBlkPtr mc) { int i, k, l, n; InstrPtr *ns, p,q; int *nv, *np = NULL; p = getInstrPtr(mb, pc); q = getInstrPtr(mc, 0); ns = GDKzalloc((l = (mb->ssize + mc->ssize + p->retc - 3)) * sizeof(InstrPtr)); if (ns == NULL) return -1; if ( mc->ptop > 0){ np = (int*) GDKmalloc(mc->ptop * sizeof(int)); if (np == 0){ GDKfree(ns); return -1; } } nv = (int*) GDKmalloc(mc->vtop * sizeof(int)); if (nv == 0){ GDKfree(ns); if( np) GDKfree(np); return -1; } /* add all properties of the new block to the target environment */ for (n = 0; n < mc->ptop; n++) { int propid = newProperty(mb); if (propid < 0) { assert(0); return -1; } np[n] = propid; mb->prps[propid].idx = mc->prps[n].idx; mb->prps[propid].op = mc->prps[n].op; mb->prps[propid].var = mc->prps[n].var; /* fixed later */ } /* add all variables of the new block to the target environment */ for (n = 0; n < mc->vtop; n++) { VarPtr ov, v; if (isExceptionVariable(mc->var[n]->name)) { nv[n] = newVariable(mb,GDKstrdup(mc->var[n]->name),TYPE_str); if (isVarUDFtype(mc,n)) setVarUDFtype(mb,nv[n]); if (isVarUsed(mc,n)) setVarUsed(mb,nv[n]); } else if (isVarTypedef(mc,n)) { nv[n] = newTypeVariable(mb,getVarType(mc,n)); } else if (isVarConstant(mc,n)) { nv[n] = cpyConstant(mb,getVar(mc,n)); } else { nv[n] = newTmpVariable(mb, getVarType(mc, n)); if (isVarUDFtype(mc,n)) setVarUDFtype(mb,nv[n]); if (isVarUsed(mc,n)) setVarUsed(mb,nv[n]); } /* remap the properties */ ov = getVar(mc, n); v = getVar(mb, nv[n]); if (ov->propc > v->maxprop) { int size = sizeof(VarRecord); VarPtr vnew = (VarPtr) GDKzalloc(size + ov->propc * sizeof(int)); memcpy((char*) vnew, (char*) v, size); vnew->maxprop = ov->propc; mb->var[nv[n]] = vnew; GDKfree(v); v = getVar(mb, nv[n]); } for (i = 0; i < ov->propc; i++) v->prps[i] = np[ov->prps[i]]; v->propc = ov->propc; } /* change the property variables to the new context */ for (n = 0; n < mc->ptop; n++) { if (mc->prps[n].var) mb->prps[np[n]].var = nv[mc->prps[n].var]; assert( mb->prps[np[n]].var >= 0); } /* use an alias mapping to keep track of the actual arguments */ for (n = p->retc; n < p->argc; n++) nv[getArg(q,n)] = getArg(p, n); k = 0; /* find the return statement of the inline function */ for (i = 1; i < mc->stop - 1; i++) { q = mc->stmt[i]; if( q->barrier== RETURNsymbol || q->barrier== YIELDsymbol){ /* add the mapping of the return variables */ for(n=0; n<p->retc; n++) nv[getArg(q,n)] = getArg(p,n); } } /* copy the stable part */ for (i = 0; i < pc; i++) ns[k++] = mb->stmt[i]; for (i = 1; i < mc->stop - 1; i++) { q = mc->stmt[i]; if( q->token == ENDsymbol) break; /* copy the instruction and fix variable references */ ns[k] = copyInstruction(q); for (n = 0; n < q->argc; n++) getArg(ns[k], n) = nv[getArg(q, n)]; if (q->barrier == RETURNsymbol || q->barrier == YIELDsymbol) { for(n=0; n<q->retc; n++) clrVarFixed(mb,getArg(ns[k],n)); /* for typing */ setModuleId(ns[k],getModuleId(q)); setFunctionId(ns[k],getFunctionId(q)); ns[k]->barrier = 0; ns[k]->token = ASSIGNsymbol; } k++; } /* copy the remainder of the stable part */ freeInstruction(p); for (i = pc + 1; i < mb->stop; i++){ ns[k++] = mb->stmt[i]; } /* remove any free instruction */ for(; i<mb->ssize; i++) if( mb->stmt[i]){ freeInstruction(mb->stmt[i]); mb->stmt[i]= 0; } GDKfree(mb->stmt); mb->stmt = ns; mb->ssize = l; mb->stop = k; GDKfree(np); GDKfree(nv); return pc; }
int OPTpushrangesImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i,j, limit,actions=0; InstrPtr p, *old; int x,y,z; Range range; if( mb->errors) return 0; range= (Range) GDKzalloc(mb->vtop * sizeof(RangeRec)); if (range == NULL) return 0; OPTDEBUGpushranges mnstr_printf(cntxt->fdout,"#Range select optimizer started\n"); (void) stk; (void) pci; limit = mb->stop; old = mb->stmt; /* * In phase I we collect information about constants */ for (i = 0; i < limit; i++) { p = old[i]; if( p->barrier) break; /* end of optimizer */ for(j=p->retc; j< p->argc; j++) range[getArg(p,j)].used++; for(j=0; j<p->retc; j++){ range[getArg(p,j)].lastupdate= i; if( range[getArg(p,j)].lastrange == 0) range[getArg(p,j)].lastrange= i; } if( getModuleId(p)== algebraRef && ( getFunctionId(p)== selectRef || getFunctionId(p)== uselectRef) ){ /* * The operation X:= algebra.select(Y,L,H,Li,Hi) is analysed. * First, we attempt to propagate the range known for Y onto the * requested range of X. This may lead to smaller range of * even the conclusion that X is necessarily empty. * Of course, only under the condition that Y has not been changed by a * side-effect since it was bound to X. */ x= getArg(p,1); y= getArg(p,2); if( range[x].lcst && isVarConstant(mb,y) ){ /* merge lowerbound */ if( ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,range[x].lcst)), VALptr( &getVarConstant(mb,y)) ) > 0){ getArg(p,2)= range[x].lcst; z= range[x].srcvar; if( getArg(p,1) == x && range[z].lastupdate == range[z].lastrange){ getArg(p,1) = z; actions++; } } y= getArg(p,3); /* merge higherbound */ if( ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,range[x].hcst)), VALptr( &getVarConstant(mb,y)) ) < 0 || ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,y)), ATOMnilptr(getVarType(mb,y)) ) == 0){ getArg(p,3)= range[x].hcst; z= range[x].srcvar; if( getArg(p,1) == x && range[z].lastupdate == range[z].lastrange){ getArg(p,1) = z; actions++; } } } /* * The second step is to assign the result of this exercise to the * result variable. */ x= getArg(p,0); if( isVarConstant(mb, getArg(p,2)) ){ range[x].lcst = getArg(p,2); range[x].srcvar= getArg(p,1); range[x].lastupdate= range[x].lastrange = i; } if( isVarConstant(mb, getArg(p,3)) ){ range[x].hcst = getArg(p,3); range[x].srcvar= getArg(p,1); range[x].lastupdate= range[x].lastrange = i; } /* * If both range bounds are constant, we can also detect empty results. * It is empty if L> H or when L=H and the bounds are !(true,true). */ x= getArg(p,2); y= getArg(p,3); if( isVarConstant(mb, x) && isVarConstant(mb, y) ){ z =ATOMcmp( getVarGDKType(mb,y), VALptr( &getVarConstant(mb,x)), VALptr( &getVarConstant(mb,y))); x= p->argc > 4; x= x && isVarConstant(mb,getArg(p,4)); x= x && isVarConstant(mb,getArg(p,5)); x= x && getVarConstant(mb,getArg(p,4)).val.btval; x= x && getVarConstant(mb,getArg(p,5)).val.btval; if( z > 0 || (z==0 && p->argc>4 && !x)) { int var = getArg(p, 0); wrd zero = 0; ValRecord v, *vp; vp = VALset(&v, TYPE_wrd, &zero); varSetProp(mb, var, rowsProp, op_eq, vp); /* create an empty replacement */ x = getArgType(mb, p, 1); p->argc=1; getModuleId(p)= batRef; getFunctionId(p)= newRef; p= pushArgument(mb,p, newTypeVariable(mb, getHeadType(x))); (void) pushArgument(mb,p, newTypeVariable(mb, getTailType(x))); actions++; } } } } OPTDEBUGpushranges for(j=0; j< mb->vtop; j++) if( range[j].used ) printRange(cntxt, mb,range,j); /* * Phase II, if we succeeded in pushing constants around and * changing instructions, we might as well try once more to perform * aliasRemoval, constantExpression, and pushranges. */ GDKfree(range); return actions; }
static QEP QEPbuild(MalBlkPtr mb){ QEP qroot= NULL, q= NULL, *vq; InstrPtr p; int i, j, k, *status; vq= (QEP*) GDKmalloc( mb->vtop * sizeof(QEP)); if (vq == NULL) return NULL; status= (int*) GDKmalloc( mb->vtop * sizeof(int)); if (status == NULL){ GDKfree(vq); return NULL; } for(i=0; i<mb->vtop; i++) { status[i]= 0; vq[i] = 0; } for(i=1; i< mb->stop-1; i++){ p= getInstrPtr(mb,i); q= QEPnewNode(mb,p); if( q == NULL) continue; for( k=p->retc; k<p->argc; k++) if( ! isVarConstant(mb, getArg(p,k)) ){ status[getArg(p,k)]= LEAFNODE; if( vq[getArg(p,k)] ) QEPappend(q, vq[getArg(p,k)]); } for( k=0; k<p->retc; k++){ if( vq[getArg(p,k)] == 0) vq[getArg(p,k)] = q; status[getArg(p,k)]= TOPNODE; } } /* We may end up with multiple variables not yet bound to a QEP. */ qroot= QEPnew(MAXPARENT,mb->stop); if( qroot) for(i=1; i< mb->stop-1; i++){ p= getInstrPtr(mb,i); k=0; if( p->barrier){ k++; q= QEPnewNode(mb,p); } else for( j=0; j< p->retc; j++) if( status[getArg(p,j)] == TOPNODE){ q= vq[getArg(p,j)]; k++; break; } if(q && k) QEPappend(qroot,q); } GDKfree(vq); GDKfree(status); return qroot; }
int OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p) { int i, j, cnt, tp, c, actions = 0, marks = 0, delta = 0; Lifespan span; InstrPtr *old, q; int limit, updstmt = 0; char *recycled; short app_sc = -1, in = 0; ValRecord cst; (void) cntxt; (void) stk; limit = mb->stop; old = mb->stmt; for (i = 1; i < limit; i++) { p = old[i]; if (getModuleId(p) == sqlRef && (getFunctionId(p) == affectedRowsRef || getFunctionId(p) == exportOperationRef || getFunctionId(p) == appendRef || getFunctionId(p) == updateRef || getFunctionId(p) == deleteRef)) updstmt = 1; } span = setLifespan(mb); if (span == NULL) return 0; /* watch out, newly created instructions may introduce new variables */ recycled = GDKzalloc(sizeof(char) * mb->vtop * 2); if (recycled == NULL) return 0; if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(recycled); return 0; } pushInstruction(mb, old[0]); mb->recid = recycleSeq++; /* create a handle for recycler */ (void) newFcnCall(mb, "recycle", "prelude"); in = 1; for (i = 1; i < limit; i++) { p = old[i]; if (hasSideEffects(p, TRUE) || isUpdateInstruction(p) || isUnsafeFunction(p)) { if (getModuleId(p) == recycleRef) { /*don't inline recycle instr. */ freeInstruction(p); continue; } pushInstruction(mb, p); /* update instructions are not recycled but monitored*/ if (isUpdateInstruction(p)) { if (getModuleId(p) == batRef && (getArgType(mb, p, 1) == TYPE_bat || isaBatType(getArgType(mb, p, 1)))) { recycled[getArg(p, 1)] = 0; q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, getArg(p, 1)); actions++; } if (getModuleId(p) == sqlRef) { if (getFunctionId(p) == appendRef) { if (app_sc >= 0) continue; else app_sc = getArg(p, 2); } VALset(&cst, TYPE_int, &delta); c = defConstant(mb, TYPE_int, &cst); q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, c); pushArgument(mb, q, getArg(p, 2)); pushArgument(mb, q, getArg(p, 3)); if (getFunctionId(p) == updateRef) pushArgument(mb, q, getArg(p, 4)); actions++; } } /* take care of SQL catalog update instructions */ if (getModuleId(p) == sqlRef && getFunctionId(p) == catalogRef) { tp = *(int *) getVarValue(mb, getArg(p, 1)); if (tp == 22 || tp == 25) { delta = 2; VALset(&cst, TYPE_int, &delta); c = defConstant(mb, TYPE_int, &cst); q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, c); pushArgument(mb, q, getArg(p, 2)); if (tp == 25) pushArgument(mb, q, getArg(p, 3)); actions++; } } continue; } if (p->token == ENDsymbol || p->barrier == RETURNsymbol) { if (in) { /* if (updstmt && app_sc >= 0) { q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, app_sc); pushArgument(mb, q, app_tbl); } */ (void) newFcnCall(mb, "recycle", "epilogue"); in = 0; } pushInstruction(mb, p); continue; } if (p->barrier && p->token != CMDcall) { /* never save a barrier unless it is a command and side-effect free */ pushInstruction(mb, p); continue; } /* don't change instructions in update statements */ if (updstmt) { pushInstruction(mb, p); continue; } /* skip simple assignments */ if (p->token == ASSIGNsymbol) { pushInstruction(mb, p); continue; } if (getModuleId(p) == octopusRef && (getFunctionId(p) == bindRef || getFunctionId(p) == bindidxRef)) { recycled[getArg(p, 0)] = 1; p->recycle = recycleMaxInterest; marks++; } /* During base table recycling skip marking instructions other than octopus.bind */ if (baseTableMode) { pushInstruction(mb, p); continue; } /* general rule: all arguments are constants or recycled, ignore C pointer arguments from mvc */ cnt = 0; for (j = p->retc; j < p->argc; j++) if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j)) || ignoreVar(mb, getArg(p, j))) cnt++; if (cnt == p->argc - p->retc) { OPTDEBUGrecycle { mnstr_printf(cntxt->fdout, "#recycle instruction\n"); printInstruction(cntxt->fdout, mb, 0, p, LIST_MAL_ALL); } marks++; p->recycle = recycleMaxInterest; /* this instruction is to be monitored */ for (j = 0; j < p->retc; j++) if (getLastUpdate(span, getArg(p, j)) == i) recycled[getArg(p, j)] = 1; } /* * The expected gain is largest if we can re-use selections * on the base tables in SQL. These, however, are marked as * uselect() calls, which only produce the oid head. * For cheap types we preselect using select() and re-map uselect() back * over this temporary. * For the time being for all possible selects encountered * are marked for re-use. */ /* take care of semantic driven recyling */ /* for selections check the bat argument only the range is often template parameter*/ if ((getFunctionId(p) == selectRef || getFunctionId(p) == antiuselectRef || getFunctionId(p) == likeselectRef || getFunctionId(p) == likeRef || getFunctionId(p) == thetaselectRef) && recycled[getArg(p, 1)]) { p->recycle = recycleMaxInterest; marks++; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } if ((getFunctionId(p) == uselectRef || getFunctionId(p) == thetauselectRef) && recycled[getArg(p, 1)]) { if (!ATOMvarsized(getGDKType(getArgType(mb, p, 2)))) { q = copyInstruction(p); getArg(q, 0) = newTmpVariable(mb, TYPE_any); if (getFunctionId(p) == uselectRef) setFunctionId(q, selectRef); else setFunctionId(q, thetaselectRef); q->recycle = recycleMaxInterest; marks++; recycled[getArg(q, 0)] = 1; pushInstruction(mb, q); getArg(p, 1) = getArg(q, 0); setFunctionId(p, projectRef); p->argc = 2; } p->recycle = recycleMaxInterest; marks++; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } if (getModuleId(p) == pcreRef) { if ((getFunctionId(p) == selectRef && recycled[getArg(p, 2)]) || (getFunctionId(p) == uselectRef && recycled[getArg(p, 2)])) { p->recycle = recycleMaxInterest; marks++; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } else if (getFunctionId(p) == likeuselectRef && recycled[getArg(p, 1)]) { q = copyInstruction(p); getArg(q, 0) = newTmpVariable(mb, TYPE_any); setFunctionId(q, likeselectRef); q->recycle = recycleMaxInterest; recycled[getArg(q, 0)] = 1; pushInstruction(mb, q); getArg(p, 1) = getArg(q, 0); setFunctionId(p, projectRef); setModuleId(p, algebraRef); p->argc = 2; p->recycle = recycleMaxInterest; marks += 2; if (getLastUpdate(span, getArg(p, 0)) == i) recycled[getArg(p, 0)] = 1; } } /* * The sql.bind instructions should be handled carefully * The delete and update BATs should not be recycled, * because they may lead to view dependencies that later interferes * with the transaction commits. */ /* enable recycling of delta-bats if (getModuleId(p) == sqlRef && (((getFunctionId(p) == bindRef || getFunctionId(p) == putName("bind_idxbat", 11)) && getVarConstant(mb, getArg(p, 5)).val.ival != 0) || getFunctionId(p) == binddbatRef)) { recycled[getArg(p, 0)] = 0; p->recycle = REC_NO_INTEREST; } */ /* * The sql.bind instructions should be handled carefully * The delete and update BATs should not be recycled, * because they may lead to view dependencies that later interferes * with the transaction commits. */ /* enable recycling of delta-bats if (getModuleId(p)== sqlRef && (((getFunctionId(p)==bindRef || getFunctionId(p) == putName("bind_idxbat",11)) && getVarConstant(mb, getArg(p,5)).val.ival != 0) || getFunctionId(p)== binddbatRef) ) { recycled[getArg(p,0)]=0; p->recycle = REC_NO_INTEREST; } */ pushInstruction(mb, p); }
int OPTrecyclerImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci) { int i, j, cnt, cand, actions = 1, marks = 0; InstrPtr *old, q,p; int limit; char *recycled; (void) cntxt; (void) stk; (void) pci; limit = mb->stop; old = mb->stmt; /* watch out, newly created instructions may introduce new variables */ recycled = GDKzalloc(sizeof(char) * mb->vtop * 2); if (recycled == NULL) return 0; if (newMalBlkStmt(mb, mb->ssize) < 0) { GDKfree(recycled); return 0; } pushInstruction(mb, old[0]); for (i = 1; i < limit; i++) { p = old[i]; if (p->token == ENDsymbol ) break; /* the first non-dataflow barrier breaks the recycler code*/ if (blockStart(p) && !(getFunctionId(p) && getFunctionId(p) == dataflowRef) ) break; if ( isUpdateInstruction(p) || hasSideEffects(p,TRUE)){ /* update instructions are not recycled but monitored*/ pushInstruction(mb, p); if (isUpdateInstruction(p)) { if (getModuleId(p) == batRef && isaBatType(getArgType(mb, p, 1))) { q = newFcnCall(mb, "recycle", "reset"); pushArgument(mb, q, getArg(p, 1)); actions++; } if (getModuleId(p) == sqlRef) { q= copyInstruction(p); getModuleId(q) = recycleRef; actions++; } } continue; } // Not all instruction may be recycled. In particular, we should avoid // MAL function with implicit/recursive side effects. // This can not always be detected easily. Likewise, we ignore cheap operations // Therefore, we use a safe subset to start with if ( ! (getModuleId(p) == sqlRef || getModuleId(p)== batRef || getModuleId(p) == algebraRef || getModuleId(p)==batcalcRef || getModuleId(p)== aggrRef || getModuleId(p)== groupRef || getModuleId(p)== batstrRef || getModuleId(p)== batmmathRef || getModuleId(p)== arrayRef || getModuleId(p)== batmtimeRef || getModuleId(p)== batcalcRef || getModuleId(p)== pcreRef || getModuleId(p)== mtimeRef || getModuleId(p) == calcRef || getModuleId(p)== dateRef || getModuleId(p) == timestampRef || getModuleId(p)== matRef ) ){ pushInstruction(mb,p); continue; } /* general rule: all arguments should be constants or recycled*/ cnt = 0; for (j = p->retc; j < p->argc; j++) if (recycled[getArg(p, j)] || isVarConstant(mb, getArg(p, j)) || isFunctionArgument(mb,getArg(p,j)) ) cnt++; cand = 0; for (j =0; j< p->retc; j++) if (recycled[getArg(p, j)] ==0) cand++; if (cnt == p->argc - p->retc && cand == p->retc) { marks++; p->recycle = RECYCLING; /* this instruction is to be monitored */ for (j = 0; j < p->retc; j++) recycled[getArg(p, j)] = 1; } pushInstruction(mb, p); } for (; i < limit; i++) pushInstruction(mb, old[i]); GDKfree(old); GDKfree(recycled); mb->recycle = marks > 0; OPTDEBUGrecycle { mnstr_printf(cntxt->fdout, "#recycle optimizer: "); printFunction(cntxt->fdout,mb, 0, LIST_MAL_ALL); } return actions + marks; }
static str renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg) { char *buf =0; char *nme =0; int nameused = 0; size_t len = 0, maxlen = BUFSIZ; ValRecord *val = 0; char *cv =0; str tpe; int showtype = 0, closequote=0; int varid = getArg(p,idx); buf = GDKzalloc(maxlen); if( buf == NULL) { addMalException(mb, "renderTerm:Failed to allocate"); return NULL; } // show the name when required or is used if ((flg & LIST_MAL_NAME) && !isVarConstant(mb,varid) && !isVarTypedef(mb,varid)) { nme = getVarName(mb,varid); len +=snprintf(buf, maxlen, "%s", nme); nameused =1; } // show the value when required or being a constant if( ((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb,varid) ){ if (nameused){ strcat(buf + len,"="); len++; } // locate value record if (isVarConstant(mb,varid)){ val = &getVarConstant(mb, varid); showtype= getVarType(mb,varid) != TYPE_str && getVarType(mb,varid) != TYPE_bit; } else if( stk) val = &stk->stk[varid]; if ((cv = VALformat(val)) == NULL) { addMalException(mb, "renderTerm:Failed to allocate"); GDKfree(buf); return NULL; } if (len + strlen(cv) >= maxlen) { char *nbuf= GDKrealloc(buf, maxlen =len + strlen(cv) + BUFSIZ); if( nbuf == 0){ GDKfree(buf); GDKfree(cv); addMalException(mb,"renderTerm:Failed to allocate"); return NULL; } buf = nbuf; } if( strcmp(cv,"nil") == 0){ strcat(buf+len,cv); len += strlen(buf+len); GDKfree(cv); showtype = showtype || getBatType(getVarType(mb,varid)) > TYPE_str || ((isVarUDFtype(mb,varid) || isVarTypedef(mb,varid)) && isVarConstant(mb,varid)) || isaBatType(getVarType(mb,varid)); } else{ if ( !isaBatType(getVarType(mb,varid)) && getBatType(getVarType(mb,varid)) > TYPE_str ){ closequote = 1; strcat(buf+len,"\""); len++; } strcat(buf+len,cv); len += strlen(buf+len); GDKfree(cv); if( closequote ){ strcat(buf+len,"\""); len++; } showtype = showtype || closequote > TYPE_str || ((isVarUDFtype(mb,varid) || isVarTypedef(mb,varid) || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE))) && isVarConstant(mb,varid)) || (isaBatType(getVarType(mb,varid)) && idx < p->retc); if (stk && isaBatType(getVarType(mb,varid)) && stk->stk[varid].val.bval ){ BAT *d= BBPquickdesc(stk->stk[varid].val.bval, true); if( d) len += snprintf(buf+len,maxlen-len,"[" BUNFMT "]", BATcount(d)); } } } // show the type when required or frozen by the user // special care should be taken with constants, they may have been casted if ((flg & LIST_MAL_TYPE) || (isVarUDFtype(mb, varid) && idx < p->retc) || isVarTypedef(mb,varid) || showtype){ strcat(buf + len,":"); len++; tpe = getTypeName(getVarType(mb, varid)); len += snprintf(buf+len,maxlen-len,"%s",tpe); GDKfree(tpe); } if( len >= maxlen) addMalException(mb,"renderTerm:Value representation too large"); return buf; }
/* * The shortcut operator for factory calls assumes that the user is * not interested in the results produced. */ str callFactory(Client cntxt, MalBlkPtr mb, ValPtr argv[], char flag){ Plant pl; InstrPtr psig = getInstrPtr(mb, 0); int i; ValPtr lhs,rhs; MalStkPtr stk; str ret; i= findPlant(mb); if( i< 0) { /* first call? prepare the factory */ pl = newPlant(mb); if (pl == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); /* remember context, which does not exist. */ pl->client = cntxt; pl->caller = 0; pl->env = 0; pl->pci = 0; pl->inuse = 1; stk = pl->stk; /* initialize the stack */ stk->stktop= mb->vtop; stk->stksize= mb->vsize; stk->blk= mb; stk->up = 0; stk->cmd= flag; /* initialize the stack */ for(i= psig->argc; i< mb->vtop; i++) if( isVarConstant(mb,i) > 0 ){ lhs = &stk->stk[i]; rhs = &getVarConstant(mb,i); if (VALcopy(lhs,rhs) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); } else { lhs = &stk->stk[i]; lhs->vtype = getVarGDKType(mb,i); } pl->stk= stk; } else { pl= plants+i; /* * When you re-enter the factory the old arguments should be * released to make room for the new ones. */ for (i = psig->retc; i < psig->argc; i++) { lhs = &pl->stk->stk[psig->argv[i]]; if( lhs->vtype == TYPE_bat ) BBPrelease(lhs->val.bval); } } /* copy the calling arguments onto the stack of the factory */ i = psig->retc; for (i = psig->retc; i < psig->argc; i++) { lhs = &pl->stk->stk[psig->argv[i]]; if (VALcopy(lhs, argv[i]) == NULL) throw(MAL, "factory.call", SQLSTATE(HY001) MAL_MALLOC_FAIL); if( lhs->vtype == TYPE_bat ) BBPretain(lhs->val.bval); } ret= reenterMAL(cntxt, mb, pl->pc, -1, pl->stk); /* garbage collect the string arguments, these positions will simply be overwritten the next time. for (i = psig->retc; i < psig->argc; i++) garbageElement(lhs = &pl->stk->stk[psig->argv[i]]); */ return ret; }
/* * The dataflow administration is based on administration of * how many variables are still missing before it can be executed. * For each instruction we keep a list of instructions whose * blocking counter should be decremented upon finishing it. */ static str DFLOWinitBlk(DataFlow flow, MalBlkPtr mb, int size) { int pc, i, j, k, l, n, etop = 0; int *assign; InstrPtr p; if (flow == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Called with flow == NULL"); if (mb == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Called with mb == NULL"); PARDEBUG fprintf(stderr, "#Initialize dflow block\n"); assign = (int *) GDKzalloc(mb->vtop * sizeof(int)); if (assign == NULL) throw(MAL, "dataflow", "DFLOWinitBlk(): Failed to allocate assign"); etop = flow->stop - flow->start; for (n = 0, pc = flow->start; pc < flow->stop; pc++, n++) { p = getInstrPtr(mb, pc); if (p == NULL) { GDKfree(assign); throw(MAL, "dataflow", "DFLOWinitBlk(): getInstrPtr() returned NULL"); } /* initial state, ie everything can run */ flow->status[n].flow = flow; flow->status[n].pc = pc; flow->status[n].state = DFLOWpending; flow->status[n].cost = -1; flow->status[n].flow->error = NULL; /* administer flow dependencies */ for (j = p->retc; j < p->argc; j++) { /* list of instructions that wake n-th instruction up */ if (!isVarConstant(mb, getArg(p, j)) && (k = assign[getArg(p, j)])) { assert(k < pc); /* only dependencies on earlier instructions */ /* add edge to the target instruction for wakeup call */ k -= flow->start; if (flow->nodes[k]) { /* add wakeup to tail of list */ for (i = k; flow->edges[i] > 0; i = flow->edges[i]) ; flow->nodes[etop] = n; flow->edges[etop] = -1; flow->edges[i] = etop; etop++; (void) size; if( etop == size){ flow->nodes = (int*) GDKrealloc(flow->nodes, sizeof(int) * 2 * size); flow->edges = (int*) GDKrealloc(flow->edges, sizeof(int) * 2 * size); size *=2; } } else { flow->nodes[k] = n; flow->edges[k] = -1; } flow->status[n].blocks++; } /* list of instructions to be woken up explicitly */ if (!isVarConstant(mb, getArg(p, j))) { /* be careful, watch out for garbage collection interference */ /* those should be scheduled after all its other uses */ l = getEndOfLife(mb, getArg(p, j)); if (l != pc && l < flow->stop && l > flow->start) { /* add edge to the target instruction for wakeup call */ PARDEBUG fprintf(stderr, "#endoflife for %s is %d -> %d\n", getVarName(mb, getArg(p, j)), n + flow->start, l); assert(pc < l); /* only dependencies on earlier instructions */ l -= flow->start; if (flow->nodes[n]) { /* add wakeup to tail of list */ for (i = n; flow->edges[i] > 0; i = flow->edges[i]) ; flow->nodes[etop] = l; flow->edges[etop] = -1; flow->edges[i] = etop; etop++; if( etop == size){ flow->nodes = (int*) GDKrealloc(flow->nodes, sizeof(int) * 2 * size); flow->edges = (int*) GDKrealloc(flow->edges, sizeof(int) * 2 * size); size *=2; } } else { flow->nodes[n] = l; flow->edges[n] = -1; } flow->status[l].blocks++; } } } for (j = 0; j < p->retc; j++) assign[getArg(p, j)] = pc; /* ensure recognition of dependency on first instruction and constant */ } GDKfree(assign); PARDEBUG { for (n = 0; n < flow->stop - flow->start; n++) { mnstr_printf(GDKstdout, "#[%d] %d: ", flow->start + n, n); printInstruction(GDKstdout, mb, 0, getInstrPtr(mb, n + flow->start), LIST_MAL_STMT | LIST_MAPI); mnstr_printf(GDKstdout, "#[%d]Dependents block count %d wakeup", flow->start + n, flow->status[n].blocks); for (j = n; flow->edges[j]; j = flow->edges[j]) { mnstr_printf(GDKstdout, "%d ", flow->start + flow->nodes[j]); if (flow->edges[j] == -1) break; } mnstr_printf(GDKstdout, "\n"); } } #ifdef USE_MAL_ADMISSION memorypool = memoryclaims = 0; #endif return MAL_SUCCEED; }