LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_multiplex.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 157 194 80.9 %
Date: 2024-04-25 20:03:45 Functions: 3 3 100.0 %

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

Generated by: LCOV version 1.14