LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_multiplex.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 122 143 85.3 %
Date: 2021-10-13 02:24:04 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "opt_multiplex.h"
      11             : #include "manifold.h"
      12             : #include "mal_interpreter.h"
      13             : 
      14             : /*
      15             :  * The generic solution to the multiplex operators is to translate
      16             :  * them to a MAL loop.
      17             :  * The call optimizer.multiplex(MOD,FCN,A1,...An) introduces the following code
      18             :  * structure:
      19             :  *
      20             :  *      resB:= bat.new(restype, A1);
      21             :  * barrier (h,t1):= iterator.new(A1);
      22             :  *      t2:= algebra.fetch(A2,h)
      23             :  *      ...
      24             :  *      cr:= MOD.FCN(t1,...,tn);
      25             :  *      bat.append(resB,cr);
      26             :  *      redo (h,t):= iterator.next(A1);
      27             :  * end h;
      28             :  *
      29             :  * The algorithm consists of two phases: phase one deals with
      30             :  * collecting the relevant information, phase two is the actual
      31             :  * code construction.
      32             :  */
      33             : static str
      34         602 : OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      35             : {
      36             :         int i = 2, iter = 0;
      37             :         int hvar, tvar;
      38             :         const char *mod, *fcn;
      39             :         int *alias, *resB;
      40             :         InstrPtr q;
      41             :         int tt;
      42         602 :         int bat = (getModuleId(pci) == batmalRef) ;
      43             : 
      44             :         (void) cntxt;
      45             :         (void) stk;
      46        1205 :         for (i = 0; i < pci->retc; i++) {
      47         603 :                 tt = getBatType(getArgType(mb, pci, i));
      48         603 :                 if (tt== TYPE_any)
      49           0 :                         throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Target tail type is missing");
      50         603 :                 if (isAnyExpression(getArgType(mb, pci, i)))
      51           0 :                         throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Target type is missing");
      52             :         }
      53             : 
      54         602 :         mod = VALget(&getVar(mb, getArg(pci, pci->retc))->value);
      55         602 :         mod = putName(mod);
      56         602 :         fcn = VALget(&getVar(mb, getArg(pci, pci->retc+1))->value);
      57         602 :         fcn = putName(fcn);
      58         602 :         if(mod == NULL || fcn == NULL)
      59           0 :                 throw(MAL, "optimizer.multiplex", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      60             : 
      61             : #ifndef NDEBUG
      62             :         TRC_WARNING_IF(MAL_OPTIMIZER) {
      63         602 :                 char *ps = instruction2str(mb, stk, pci, LIST_MAL_DEBUG);
      64         602 :                 TRC_WARNING_ENDIF(MAL_OPTIMIZER, "To speedup %s.%s a bulk operator implementation is needed%s%s\n", mod, fcn, ps ? " for " : "", ps ? ps : "");
      65         602 :                 GDKfree(ps);
      66             :         }
      67             : #endif
      68             : 
      69             :         /* search the iterator bat */
      70         758 :         for (i = pci->retc+2; i < pci->argc; i++)
      71         758 :                 if (isaBatType(getArgType(mb, pci, i))) {
      72             :                         iter = getArg(pci, i);
      73             :                         break;
      74             :                 }
      75         602 :         if( i == pci->argc)
      76           0 :                 throw(MAL, "optimizer.multiplex", SQLSTATE(HY002) "Iterator BAT type is missing");
      77             : 
      78             :         /*
      79             :          * Beware, the operator constant (arg=1) is passed along as well,
      80             :          * because in the end we issue a recursive function call that should
      81             :          * find the actual arguments at the proper place of the callee.
      82             :          */
      83             : 
      84         602 :         alias= (int*) GDKmalloc(sizeof(int) * pci->maxarg);
      85         602 :         resB = (int*) GDKmalloc(sizeof(int) * pci->retc);
      86         602 :         if (alias == NULL || resB == NULL)  {
      87           0 :                 GDKfree(alias);
      88           0 :                 GDKfree(resB);
      89           0 :                 throw(MAL, "optimizer.multiplex", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      90             :         }
      91             : 
      92             :         /* resB := new(refBat) */
      93        1205 :         for (i = 0; i < pci->retc; i++) {
      94         603 :                 q = newFcnCallArgs(mb, batRef, newRef, 2);
      95         603 :                 resB[i] = getArg(q, 0);
      96             : 
      97         603 :                 tt = getBatType(getArgType(mb, pci, i));
      98             : 
      99         603 :                 setVarType(mb, getArg(q, 0), newBatType(tt));
     100         603 :                 q = pushType(mb, q, tt);
     101         603 :                 q = pushArgument(mb, q, iter);
     102         603 :                 assert(q->argc==3);
     103             :         }
     104             : 
     105             :         /* barrier (h,r) := iterator.new(refBat); */
     106         602 :         q = newFcnCall(mb, iteratorRef, newRef);
     107         602 :         q->barrier = BARRIERsymbol;
     108         602 :         hvar = newTmpVariable(mb, TYPE_any);
     109         602 :         getArg(q,0) = hvar;
     110         602 :         tvar = newTmpVariable(mb, TYPE_any);
     111         602 :         q= pushReturn(mb, q, tvar);
     112         602 :         (void) pushArgument(mb,q,iter);
     113             : 
     114             :         /* $1:= algebra.fetch(Ai,h) or constant */
     115        2070 :         for (i = pci->retc+2; i < pci->argc; i++) {
     116        1468 :                 if (getArg(pci, i) != iter && isaBatType(getArgType(mb, pci, i))) {
     117         637 :                         q = newFcnCall(mb, algebraRef, "fetch");
     118         637 :                         alias[i] = newTmpVariable(mb, getBatType(getArgType(mb, pci, i)));
     119         637 :                         getArg(q, 0) = alias[i];
     120         637 :                         q= pushArgument(mb, q, getArg(pci, i));
     121         637 :                         (void) pushArgument(mb, q, hvar);
     122             :                 }
     123             :         }
     124             : 
     125             :         /* cr:= mod.CMD($1,...,$n); */
     126         602 :         q = newFcnCallArgs(mb, mod, fcn, pci->argc - 2);
     127        1205 :         for (i = 0; i < pci->retc; i++) {
     128             :                 int nvar = 0;
     129         603 :                 if (bat) {
     130          19 :                         tt = getBatType(getArgType(mb, pci, i));
     131          19 :                         nvar = newTmpVariable(mb, newBatType(tt));
     132             :                 } else {
     133         584 :                         nvar = newTmpVariable(mb, TYPE_any);
     134             :                 }
     135         603 :                 if (i)
     136           1 :                         q = pushReturn(mb, q, nvar);
     137             :                 else
     138         602 :                         getArg(q, 0) = nvar;
     139             :         }
     140             : 
     141        2070 :         for (i = pci->retc+2; i < pci->argc; i++) {
     142        1468 :                 if (getArg(pci, i) == iter) {
     143         602 :                         q = pushArgument(mb, q, tvar);
     144         866 :                 } else if (isaBatType(getArgType(mb, pci, i))) {
     145         637 :                         q = pushArgument(mb, q, alias[i]);
     146             :                 } else {
     147         229 :                         q = pushArgument(mb, q, getArg(pci, i));
     148             :                 }
     149             :         }
     150             : 
     151        1205 :         for (i = 0; i < pci->retc; i++) {
     152         603 :                 InstrPtr a = newFcnCall(mb, batRef, appendRef);
     153         603 :                 a = pushArgument(mb, a, resB[i]);
     154         603 :                 a = pushArgument(mb, a, getArg(q,i));
     155         603 :                 getArg(a,0) = resB[i];
     156             :         }
     157             : 
     158             : /* redo (h,r):= iterator.next(refBat); */
     159         602 :         q = newFcnCall(mb, iteratorRef, nextRef);
     160         602 :         q->barrier = REDOsymbol;
     161         602 :         getArg(q,0) = hvar;
     162         602 :         q= pushReturn(mb, q, tvar);
     163         602 :         (void) pushArgument(mb,q,iter);
     164             : 
     165         602 :         q = newAssignment(mb);
     166         602 :         q->barrier = EXITsymbol;
     167         602 :         getArg(q,0) = hvar;
     168         602 :         (void) pushReturn(mb, q, tvar);
     169             : 
     170        1205 :         for (i = 0; i < pci->retc; i++) {
     171         603 :                 q = newAssignment(mb);
     172         603 :                 getArg(q, 0) = getArg(pci, i);
     173         603 :                 (void) pushArgument(mb, q, resB[i]);
     174             :         }
     175         602 :         GDKfree(alias);
     176         602 :         GDKfree(resB);
     177         602 :         return MAL_SUCCEED;
     178             : }
     179             : 
     180             : /*
     181             :  * The multiplexSimple is called by the MAL scenario. It bypasses
     182             :  * the optimizer infrastructure, to avoid excessive space allocation
     183             :  * and interpretation overhead.
     184             :  */
     185             : str
     186        9055 : OPTmultiplexSimple(Client cntxt, MalBlkPtr mb)
     187             : {
     188             :         int i, doit=0;
     189             :         InstrPtr p;
     190             :         str msg = MAL_SUCCEED;
     191             : 
     192        9055 :         if(mb)
     193       44047 :                 for( i=0; i<mb->stop; i++){
     194       34992 :                         p= getInstrPtr(mb,i);
     195       34992 :                         if(isMultiplex(p)) {
     196           0 :                                 p->typechk = TYPE_UNKNOWN;
     197           0 :                                 doit++;
     198             :                         }
     199             :                 }
     200        9055 :         if( doit) {
     201           0 :                 msg = OPTmultiplexImplementation(cntxt, mb, 0, 0);
     202           0 :                 if (!msg)
     203           0 :                         msg = chkTypes(cntxt->usermodule, mb,TRUE);
     204           0 :                 if (!msg)
     205           0 :                         msg = chkFlow(mb);
     206           0 :                 if (!msg)
     207           0 :                         msg = chkDeclarations(mb);
     208             :         }
     209        9055 :         return msg;
     210             : }
     211             : 
     212             : str
     213      356714 : OPTmultiplexImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     214             : {
     215             :         InstrPtr *old = 0, p;
     216             :         int i, limit, slimit, actions= 0;
     217             :         str msg= MAL_SUCCEED;
     218             : 
     219             :         (void) stk;
     220    23139831 :         for (i = 0; i < mb->stop; i++) {
     221    22783507 :                 p = getInstrPtr(mb,i);
     222    22783507 :                 if (isMultiplex(p)) {
     223             :                         break;
     224             :                 }
     225             :         }
     226      356714 :         if( i == mb->stop){
     227      356324 :                 goto wrapup;
     228             :         }
     229             : 
     230         390 :         old = mb->stmt;
     231             :         limit = mb->stop;
     232         390 :         slimit = mb->ssize;
     233         390 :         if ( newMalBlkStmt(mb, mb->ssize) < 0 )
     234           0 :                 throw(MAL,"optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     235             : 
     236       50077 :         for (i = 0; i < limit; i++) {
     237       49687 :                 p = old[i];
     238       49687 :                 if (msg == MAL_SUCCEED && isMultiplex(p)) {
     239        1005 :                         if ( MANIFOLDtypecheck(cntxt,mb,p,0) != NULL){
     240         403 :                                 setFunctionId(p, manifoldRef);
     241         403 :                                 p->typechk = TYPE_UNKNOWN;
     242         403 :                                 pushInstruction(mb, p);
     243         403 :                                 actions++;
     244         403 :                                 continue;
     245             :                         }
     246         602 :                         msg = OPTexpandMultiplex(cntxt, mb, stk, p);
     247         602 :                         if( msg== MAL_SUCCEED){
     248         602 :                                 freeInstruction(p);
     249         602 :                                 old[i]=0;
     250         602 :                                 actions++;
     251         602 :                                 continue;
     252             :                         }
     253             : 
     254           0 :                         pushInstruction(mb, p);
     255           0 :                         actions++;
     256       48682 :                 } else if( old[i])
     257       48682 :                         pushInstruction(mb, p);
     258             :         }
     259       74607 :         for(;i<slimit; i++)
     260       74217 :                 if( old[i])
     261           0 :                         pushInstruction(mb, old[i]);
     262         390 :         GDKfree(old);
     263             : 
     264             :         /* Defense line against incorrect plans */
     265         390 :         if( msg == MAL_SUCCEED && actions > 0){
     266         390 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     267         390 :                 if (!msg)
     268         390 :                         msg = chkFlow(mb);
     269         390 :                 if (!msg)
     270         390 :                         msg = chkDeclarations(mb);
     271             :         }
     272           0 : wrapup:
     273             :         /* keep actions taken as a fake argument*/
     274      356714 :         (void) pushInt(mb, pci, actions);
     275             : 
     276      356714 :         return msg;
     277             : }

Generated by: LCOV version 1.14