LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_resource.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 69 81.2 %
Date: 2024-04-26 00:35:57 Functions: 4 4 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             : /* (author) M.L. Kersten
      14             :  */
      15             : #include "monetdb_config.h"
      16             : #include "mal_exception.h"
      17             : #include "mal_resource.h"
      18             : #include "mal_private.h"
      19             : #include "mal_internal.h"
      20             : #include "mal_instruction.h"
      21             : 
      22             : /* Memory based admission does not seem to have a major impact so far. */
      23             : static lng memorypool = 0;              /* memory claimed by concurrent threads */
      24             : 
      25             : static MT_Lock admissionLock = MT_LOCK_INITIALIZER(admissionLock);
      26             : 
      27             : void
      28         339 : mal_resource_reset(void)
      29             : {
      30         339 :         MT_lock_set(&admissionLock);
      31         339 :         memorypool = (lng) MEMORY_THRESHOLD;
      32         339 :         MT_lock_unset(&admissionLock);
      33         339 : }
      34             : 
      35             : /*
      36             :  * Running all eligible instructions in parallel creates
      37             :  * resource contention. This means we should implement
      38             :  * an admission control scheme where threads are temporarily
      39             :  * postponed if the claim for memory exceeds a threshold
      40             :  * In general such contentions will be hard to predict,
      41             :  * because they depend on the algorithm, the input sizes,
      42             :  * concurrent use of the same variables, and the output produced.
      43             :  *
      44             :  * One heuristic is based on calculating the storage footprint
      45             :  * of the operands and assuming it preferrably should fit in memory.
      46             :  * Ofcourse, there may be intermediate structures being
      47             :  * used and the size of the result is not a priori known.
      48             :  * For this, we use a high watermark on the amount of
      49             :  * physical memory we pre-allocate for the claims.
      50             :  *
      51             :  * Instructions are eligible to be executed when the
      52             :  * total footprint of all concurrent executions stays below
      53             :  * the high-watermark or it is the single expensive
      54             :  * instruction being started.
      55             :  *
      56             :  * When we run out of memory, the instruction is delayed.
      57             :  * How long depends on the other instructions to free up
      58             :  * resources. The current policy simple takes a local
      59             :  * decision by delaying the instruction based on its
      60             :  * claim of the memory.
      61             :  */
      62             : 
      63             : /*
      64             :  * The memory claim is the estimate for the amount of memory hold.
      65             :  * Views are consider cheap and ignored.
      66             :  * Given that auxiliary structures are important for performance,
      67             :  * we use their maximum as an indication of the memory footprint.
      68             :  * An alternative would be to focus solely on the base table cost.
      69             :  * (Good for a MSc study)
      70             :  */
      71             : lng
      72    17308673 : getMemoryClaim(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int i, int flag)
      73             : {
      74    17308673 :         lng total = 0, itotal = 0, t;
      75    17308673 :         BAT *b;
      76             : 
      77    17308673 :         (void) mb;
      78    17308673 :         if (stk->stk[getArg(pci, i)].bat) {
      79    10338553 :                 bat bid = stk->stk[getArg(pci, i)].val.bval;
      80    10338553 :                 if (!BBPcheck(bid))
      81             :                         return 0;
      82     9857215 :                 b = BBP_desc(bid);
      83     9857215 :                 MT_lock_set(&b->theaplock);
      84     9854263 :                 if (flag && isVIEW(b)) {
      85           0 :                         MT_lock_unset(&b->theaplock);
      86           0 :                         return 0;
      87             :                 }
      88             : 
      89             :                 /* calculate the basic scan size */
      90     9854263 :                 total += BATcount(b) << b->tshift;
      91     9854263 :                 total += heapinfo(b->tvheap, b->batCacheid);
      92     9854263 :                 MT_lock_unset(&b->theaplock);
      93             : 
      94             :                 /* indices should help, find their maximum footprint */
      95     9860998 :                 MT_rwlock_rdlock(&b->thashlock);
      96     9861548 :                 itotal = hashinfo(b->thash, d->batCacheid);
      97     9861548 :                 MT_rwlock_rdunlock(&b->thashlock);
      98     9860776 :                 t = IMPSimprintsize(b);
      99     9858799 :                 if (t > itotal)
     100             :                         itotal = t;
     101             :                 /* We should also consider the ordered index size */
     102    19717598 :                 t = b->torderidx
     103     9858799 :                                 && b->torderidx != (Heap *) 1 ? (lng) b->torderidx->free : 0;
     104     9858799 :                 if (t > itotal)
     105             :                         itotal = t;
     106             :                 //total = total > (lng)(MEMORY_THRESHOLD ) ? (lng)(MEMORY_THRESHOLD ) : total;
     107     9858799 :                 if (total < itotal)
     108             :                         total = itotal;
     109             :         }
     110             :         return total;
     111             : }
     112             : 
     113             : /*
     114             :  * The argclaim provides a hint on how much we actually may need to execute
     115             :  *
     116             :  * The client context also keeps bounds on the memory claim/client.
     117             :  * Surpassing this bound may be a reason to not admit the instruction to proceed.
     118             :  */
     119             : bool
     120    11580452 : MALadmission_claim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     121             :                                    lng argclaim)
     122             : {
     123    11580452 :         (void) pci;
     124             : 
     125             :         /* Check if we are allowed to allocate another worker thread for this client */
     126             :         /* It is somewhat tricky, because we may be in a dataflow recursion, each of which should be counted for.
     127             :          * A way out is to attach the thread count to the MAL stacks, which just limits the level
     128             :          * of parallism for a single dataflow graph.
     129             :          */
     130    11580452 :         if (cntxt->workerlimit > 0
     131           0 :                 && (int) ATOMIC_GET(&cntxt->workers) >= cntxt->workerlimit)
     132             :                 return false;
     133             : 
     134    11580452 :         if (argclaim == 0)
     135             :                 return true;
     136             : 
     137     5610872 :         MT_lock_set(&admissionLock);
     138             :         /* Determine if the total memory resource is exhausted, because it is overall limitation.  */
     139     5625000 :         if (memorypool <= 0) {
     140             :                 // we accidently released too much memory or need to initialize
     141         330 :                 memorypool = (lng) MEMORY_THRESHOLD;
     142             :         }
     143             : 
     144             :         /* the argument claim is based on the input for an instruction */
     145     5625000 :         if (memorypool > argclaim || ATOMIC_GET(&cntxt->workers) == 0) {
     146             :                 /* If we are low on memory resources, limit the user if he exceeds his memory budget
     147             :                  * but make sure there is at least one worker thread active */
     148     5625000 :                 if (cntxt->memorylimit) {
     149           0 :                         if (argclaim + stk->memory >
     150           0 :                                 (lng) cntxt->memorylimit * LL_CONSTANT(1048576)
     151           0 :                                 && ATOMIC_GET(&cntxt->workers) > 0) {
     152           0 :                                 MT_lock_unset(&admissionLock);
     153           0 :                                 return false;
     154             :                         }
     155           0 :                         stk->memory += argclaim;
     156             :                 }
     157     5625000 :                 memorypool -= argclaim;
     158     5625000 :                 stk->memory += argclaim;
     159     5625000 :                 MT_lock_set(&mal_delayLock);
     160     5625000 :                 if (mb->memory < stk->memory)
     161       46768 :                         mb->memory = stk->memory;
     162     5625000 :                 MT_lock_unset(&mal_delayLock);
     163     5625000 :                 MT_lock_unset(&admissionLock);
     164     5625000 :                 return true;
     165             :         }
     166           0 :         MT_lock_unset(&admissionLock);
     167           0 :         return false;
     168             : }
     169             : 
     170             : void
     171    11534188 : MALadmission_release(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     172             :                                          lng argclaim)
     173             : {
     174             :         /* release memory claimed before */
     175    11534188 :         (void) cntxt;
     176    11534188 :         (void) mb;
     177    11534188 :         (void) pci;
     178    11534188 :         if (argclaim == 0)
     179             :                 return;
     180             : 
     181     5615472 :         MT_lock_set(&admissionLock);
     182     5625000 :         if (cntxt->memorylimit) {
     183           0 :                 stk->memory -= argclaim;
     184             :         }
     185     5625000 :         memorypool += argclaim;
     186     5625000 :         if (memorypool > (lng) MEMORY_THRESHOLD) {
     187           0 :                 memorypool = (lng) MEMORY_THRESHOLD;
     188             :         }
     189     5625000 :         stk->memory -= argclaim;
     190     5625000 :         MT_lock_unset(&admissionLock);
     191     5625000 :         return;
     192             : }

Generated by: LCOV version 1.14