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-12-20 20:06:10 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        2350 : OPTexpandMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
      39             : {
      40        2350 :         int i = 2, iter = 0;
      41        2350 :         int hvar, tvar;
      42        2350 :         const char *mod, *fcn;
      43        2350 :         int *alias, *resB;
      44        2350 :         InstrPtr q;
      45        2350 :         int tt;
      46        2350 :         int bat = (getModuleId(pci) == batmalRef);
      47             : 
      48        2350 :         (void) cntxt;
      49        2350 :         (void) stk;
      50        4733 :         for (i = 0; i < pci->retc; i++) {
      51        2383 :                 tt = getBatType(getArgType(mb, pci, i));
      52        2383 :                 if (tt == TYPE_any)
      53           0 :                         throw(MAL, "optimizer.multiplex",
      54             :                                   SQLSTATE(HY002) "Target tail type is missing");
      55        2383 :                 if (isAnyExpression(getArgType(mb, pci, i)))
      56           0 :                         throw(MAL, "optimizer.multiplex",
      57             :                                   SQLSTATE(HY002) "Target type is missing");
      58             :         }
      59        2350 :         int plus_one = getArgType(mb, pci, pci->retc) == TYPE_lng ? 1 : 0;
      60        2350 :         mod = VALget(&getVar(mb, getArg(pci, pci->retc + plus_one))->value);
      61        2350 :         mod = putName(mod);
      62        2350 :         fcn = VALget(&getVar(mb, getArg(pci, pci->retc + 1 + plus_one))->value);
      63        2350 :         fcn = putName(fcn);
      64        2350 :         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        2350 :                 char *ps = instruction2str(mb, stk, pci, LIST_MAL_DEBUG);
      70        2350 :                 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        2350 :                 GDKfree(ps);
      74             :         }
      75             : #endif
      76             : 
      77        2350 :         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        2368 :                 for (i = pci->retc + 2; i < pci->argc; i++)
      87        2368 :                         if (isaBatType(getArgType(mb, pci, i))) {
      88             :                                 iter = getArg(pci, i);
      89             :                                 break;
      90             :                         }
      91        2350 :         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        2350 :         alias = (int *) GDKmalloc(sizeof(int) * pci->maxarg);
     102        2350 :         resB = (int *) GDKmalloc(sizeof(int) * pci->retc);
     103        2350 :         if (alias == NULL || resB == NULL) {
     104           0 :                 goto nomem;
     105             :         }
     106             : 
     107             :         /* resB := new(refBat) */
     108        4733 :         for (i = 0; i < pci->retc; i++) {
     109        2383 :                 q = newFcnCallArgs(mb, batRef, newRef, 3);
     110        2383 :                 if (q == NULL) {
     111           0 :                         goto nomem;
     112             :                 }
     113        2383 :                 resB[i] = getArg(q, 0);
     114             : 
     115        2383 :                 tt = getBatType(getArgType(mb, pci, i));
     116             : 
     117        2383 :                 setVarType(mb, getArg(q, 0), newBatType(tt));
     118        2383 :                 q = pushType(mb, q, tt);
     119        2383 :                 q = pushArgument(mb, q, iter);
     120        2383 :                 pushInstruction(mb, q);
     121        2383 :                 assert(q->argc == 3);
     122             :         }
     123             : 
     124             :         /* barrier (h,r) := iterator.new(refBat); */
     125        2350 :         q = newFcnCall(mb, iteratorRef, newRef);
     126        2350 :         if (q == NULL) {
     127           0 :                 goto nomem;
     128             :         }
     129        2350 :         q->barrier = BARRIERsymbol;
     130        2350 :         hvar = newTmpVariable(mb, TYPE_any);
     131        2350 :         getArg(q, 0) = hvar;
     132        2350 :         tvar = newTmpVariable(mb, TYPE_any);
     133        2350 :         q = pushReturn(mb, q, tvar);
     134        2350 :         q = pushArgument(mb, q, iter);
     135        2350 :         pushInstruction(mb, q);
     136             : 
     137             :         /* $1:= algebra.fetch(Ai,h) or constant */
     138        7165 :         for (i = pci->retc + 2 + plus_one; i < pci->argc; i++) {
     139        4815 :                 if (getArg(pci, i) != iter &&isaBatType(getArgType(mb, pci, i))) {
     140        2285 :                         q = newFcnCall(mb, algebraRef, "fetch");
     141        2285 :                         if (q == NULL) {
     142           0 :                                 goto nomem;
     143             :                         }
     144        2285 :                         alias[i] = newTmpVariable(mb, getBatType(getArgType(mb, pci, i)));
     145        2285 :                         getArg(q, 0) = alias[i];
     146        2285 :                         q = pushArgument(mb, q, getArg(pci, i));
     147        2285 :                         q = pushArgument(mb, q, hvar);
     148        2285 :                         pushInstruction(mb, q);
     149             :                 }
     150             :         }
     151             : 
     152             :         /* cr:= mod.CMD($1,...,$n); */
     153        2350 :         q = newFcnCallArgs(mb, mod, fcn, pci->argc - 2 - plus_one);
     154        2350 :         if (q == NULL) {
     155           0 :                 goto nomem;
     156             :         }
     157        4733 :         for (i = 0; i < pci->retc; i++) {
     158        2383 :                 int nvar = 0;
     159        2383 :                 if (bat) {
     160          42 :                         tt = getBatType(getArgType(mb, pci, i));
     161          42 :                         nvar = newTmpVariable(mb, newBatType(tt));
     162             :                 } else {
     163        2341 :                         nvar = newTmpVariable(mb, TYPE_any);
     164             :                 }
     165        2383 :                 if (i)
     166          33 :                         q = pushReturn(mb, q, nvar);
     167             :                 else
     168        2350 :                         getArg(q, 0) = nvar;
     169             :         }
     170             : 
     171        7165 :         for (i = pci->retc + 2 + plus_one; i < pci->argc; i++) {
     172        4815 :                 if (getArg(pci, i) == iter) {
     173        2353 :                         q = pushArgument(mb, q, tvar);
     174        2462 :                 } else if (isaBatType(getArgType(mb, pci, i))) {
     175        2285 :                         q = pushArgument(mb, q, alias[i]);
     176             :                 } else {
     177         177 :                         q = pushArgument(mb, q, getArg(pci, i));
     178             :                 }
     179             :         }
     180        2350 :         pushInstruction(mb, q);
     181             : 
     182        7083 :         for (i = 0; i < pci->retc; i++) {
     183        2383 :                 InstrPtr a = newFcnCall(mb, batRef, appendRef);
     184        2383 :                 if (a == NULL) {
     185           0 :                         goto nomem;
     186             :                 }
     187        2383 :                 a = pushArgument(mb, a, resB[i]);
     188        2383 :                 a = pushArgument(mb, a, getArg(q, i));
     189        2383 :                 getArg(a, 0) = resB[i];
     190        2383 :                 pushInstruction(mb, a);
     191             :         }
     192             : 
     193             : /* redo (h,r):= iterator.next(refBat); */
     194        2350 :         q = newFcnCall(mb, iteratorRef, nextRef);
     195        2350 :         if (q == NULL) {
     196           0 :                 goto nomem;
     197             :         }
     198        2350 :         q->barrier = REDOsymbol;
     199        2350 :         getArg(q, 0) = hvar;
     200        2350 :         q = pushReturn(mb, q, tvar);
     201        2350 :         q = pushArgument(mb, q, iter);
     202        2350 :         pushInstruction(mb, q);
     203             : 
     204        2350 :         q = newAssignment(mb);
     205        2350 :         if (q == NULL) {
     206           0 :                 goto nomem;
     207             :         }
     208        2350 :         q->barrier = EXITsymbol;
     209        2350 :         getArg(q, 0) = hvar;
     210        2350 :         q = pushReturn(mb, q, tvar);
     211        2350 :         pushInstruction(mb, q);
     212             : 
     213        7083 :         for (i = 0; i < pci->retc; i++) {
     214        2383 :                 q = newAssignment(mb);
     215        2383 :                 if (q == NULL) {
     216           0 :                         goto nomem;
     217             :                 }
     218        2383 :                 getArg(q, 0) = getArg(pci, i);
     219        2383 :                 q = pushArgument(mb, q, resB[i]);
     220        2383 :                 pushInstruction(mb, q);
     221             :         }
     222        2350 :         GDKfree(alias);
     223        2350 :         GDKfree(resB);
     224        2350 :         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           7 : OPTmultiplexSimple(Client cntxt, MalBlkPtr mb)
     239             : {
     240           7 :         int i, doit = 0;
     241           7 :         InstrPtr p;
     242           7 :         str msg = MAL_SUCCEED;
     243             : 
     244           7 :         if (mb)
     245        1289 :                 for (i = 0; i < mb->stop; i++) {
     246        1282 :                         p = getInstrPtr(mb, i);
     247        1282 :                         if (isMultiplex(p)) {
     248           0 :                                 p->typeresolved = false;
     249           0 :                                 doit++;
     250             :                         }
     251             :                 }
     252           7 :         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           7 :         return msg;
     262             : }
     263             : 
     264             : str
     265      455596 : OPTmultiplexImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
     266             :                                                    InstrPtr pci)
     267             : {
     268      455596 :         InstrPtr *old = 0, p;
     269      455596 :         int i, limit, slimit, actions = 0;
     270      455596 :         str msg = MAL_SUCCEED;
     271             : 
     272      455596 :         (void) stk;
     273    23831429 :         for (i = 0; i < mb->stop; i++) {
     274    23376766 :                 p = getInstrPtr(mb, i);
     275    23376766 :                 if (isMultiplex(p)) {
     276             :                         break;
     277             :                 }
     278             :         }
     279      455595 :         if (i == mb->stop) {
     280      454663 :                 goto wrapup;
     281             :         }
     282             : 
     283         932 :         old = mb->stmt;
     284         932 :         limit = mb->stop;
     285         932 :         slimit = mb->ssize;
     286         932 :         if (newMalBlkStmt(mb, mb->ssize) < 0)
     287           0 :                 throw(MAL, "optimizer.multiplex", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     288             : 
     289      219298 :         for (i = 0; i < limit; i++) {
     290      218366 :                 p = old[i];
     291      218366 :                 if (msg == MAL_SUCCEED && isMultiplex(p)) {
     292        2982 :                         if (MANIFOLDtypecheck(cntxt, mb, p, 0) != NULL) {
     293         632 :                                 setFunctionId(p, manifoldRef);
     294         632 :                                 p->typeresolved = false;
     295         632 :                                 pushInstruction(mb, p);
     296         632 :                                 actions++;
     297         632 :                                 continue;
     298             :                         }
     299        2350 :                         msg = OPTexpandMultiplex(cntxt, mb, stk, p);
     300        2350 :                         if (msg == MAL_SUCCEED) {
     301        2350 :                                 freeInstruction(p);
     302        2350 :                                 old[i] = 0;
     303        2350 :                                 actions++;
     304        2350 :                                 continue;
     305             :                         }
     306             : 
     307           0 :                         pushInstruction(mb, p);
     308           0 :                         actions++;
     309      215384 :                 } else if (old[i])
     310      215384 :                         pushInstruction(mb, p);
     311             :         }
     312      186278 :         for (; i < slimit; i++)
     313      185346 :                 if (old[i])
     314           0 :                         pushInstruction(mb, old[i]);
     315         932 :         GDKfree(old);
     316             : 
     317             :         /* Defense line against incorrect plans */
     318         932 :         if (msg == MAL_SUCCEED && actions > 0) {
     319         932 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
     320         932 :                 if (!msg)
     321         932 :                         msg = chkFlow(mb);
     322         932 :                 if (!msg)
     323         932 :                         msg = chkDeclarations(mb);
     324             :         }
     325           0 :   wrapup:
     326             :         /* keep actions taken as a fake argument */
     327      455595 :         (void) pushInt(mb, pci, actions);
     328             : 
     329      455595 :         return msg;
     330             : }

Generated by: LCOV version 1.14