LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_resource.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 67 83.6 %
Date: 2024-11-13 22:44:48 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         297 : mal_resource_reset(void)
      29             : {
      30         297 :         MT_lock_set(&admissionLock);
      31         297 :         memorypool = (lng) MEMORY_THRESHOLD;
      32         297 :         MT_lock_unset(&admissionLock);
      33         297 : }
      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 preferably 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    10231764 : getMemoryClaim(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int i, int flag)
      73             : {
      74    10231764 :         lng total = 0, itotal = 0, t;
      75    10231764 :         BAT *b;
      76             : 
      77    10231764 :         (void) mb;
      78    10231764 :         if (stk->stk[getArg(pci, i)].bat) {
      79     6469528 :                 bat bid = stk->stk[getArg(pci, i)].val.bval;
      80     6469528 :                 if (!BBPcheck(bid))
      81             :                         return 0;
      82     6320616 :                 b = BBP_desc(bid);
      83     6320616 :                 MT_lock_set(&b->theaplock);
      84     6320511 :                 if (flag && isVIEW(b)) {
      85           0 :                         MT_lock_unset(&b->theaplock);
      86           0 :                         return 0;
      87             :                 }
      88             : 
      89             :                 /* calculate the basic scan size */
      90     6320511 :                 total += BATcount(b) << b->tshift;
      91     6320511 :                 total += heapinfo(b->tvheap, b->batCacheid);
      92     6320511 :                 MT_lock_unset(&b->theaplock);
      93             : 
      94             :                 /* indices should help, find their maximum footprint */
      95     6319930 :                 MT_rwlock_rdlock(&b->thashlock);
      96     6320976 :                 itotal = hashinfo(b->thash, d->batCacheid);
      97     6320976 :                 MT_rwlock_rdunlock(&b->thashlock);
      98             :                 /* We should also consider the ordered index size */
      99    12641310 :                 t = b->torderidx
     100     6320655 :                                 && b->torderidx != (Heap *) 1 ? (lng) b->torderidx->free : 0;
     101     6320655 :                 if (t > itotal)
     102             :                         itotal = t;
     103             :                 //total = total > (lng)(MEMORY_THRESHOLD ) ? (lng)(MEMORY_THRESHOLD ) : total;
     104     6320655 :                 if (total < itotal)
     105             :                         total = itotal;
     106             :         }
     107             :         return total;
     108             : }
     109             : 
     110             : /*
     111             :  * The argclaim provides a hint on how much we actually may need to execute
     112             :  *
     113             :  * The client context also keeps bounds on the memory claim/client.
     114             :  * Surpassing this bound may be a reason to not admit the instruction to proceed.
     115             :  */
     116             : bool
     117     7500829 : MALadmission_claim(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     118             :                                    lng argclaim)
     119             : {
     120     7500829 :         (void) pci;
     121             : 
     122             :         /* Check if we are allowed to allocate another worker thread for this client */
     123             :         /* It is somewhat tricky, because we may be in a dataflow recursion, each of which should be counted for.
     124             :          * A way out is to attach the thread count to the MAL stacks, which just limits the level
     125             :          * of parallelism for a single dataflow graph.
     126             :          */
     127     7500829 :         if (cntxt->workerlimit > 0
     128           0 :                 && (int) ATOMIC_GET(&cntxt->workers) >= cntxt->workerlimit)
     129             :                 return false;
     130             : 
     131     7500829 :         if (argclaim == 0)
     132             :                 return true;
     133             : 
     134     3807848 :         MT_lock_set(&admissionLock);
     135             :         /* Determine if the total memory resource is exhausted, because it is overall limitation.  */
     136     3808375 :         if (memorypool <= 0) {
     137             :                 // we accidentally released too much memory or need to initialize
     138         304 :                 memorypool = (lng) MEMORY_THRESHOLD;
     139             :         }
     140             : 
     141             :         /* the argument claim is based on the input for an instruction */
     142     3808375 :         if (memorypool > argclaim || ATOMIC_GET(&cntxt->workers) == 0) {
     143             :                 /* If we are low on memory resources, limit the user if he exceeds his memory budget
     144             :                  * but make sure there is at least one worker thread active */
     145     3784347 :                 if (cntxt->memorylimit) {
     146           0 :                         if (argclaim + stk->memory >
     147           0 :                                 (lng) cntxt->memorylimit * LL_CONSTANT(1048576)
     148           0 :                                 && ATOMIC_GET(&cntxt->workers) > 0) {
     149           0 :                                 MT_lock_unset(&admissionLock);
     150           0 :                                 return false;
     151             :                         }
     152           0 :                         stk->memory += argclaim;
     153             :                 }
     154     3784347 :                 memorypool -= argclaim;
     155     3784347 :                 stk->memory += argclaim;
     156     3784347 :                 MT_lock_set(&mal_delayLock);
     157     3784347 :                 if (mb->memory < stk->memory)
     158       29567 :                         mb->memory = stk->memory;
     159     3784347 :                 MT_lock_unset(&mal_delayLock);
     160     3784347 :                 MT_lock_unset(&admissionLock);
     161     3784347 :                 return true;
     162             :         }
     163       24028 :         MT_lock_unset(&admissionLock);
     164       24028 :         return false;
     165             : }
     166             : 
     167             : void
     168     7472570 : MALadmission_release(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci,
     169             :                                          lng argclaim)
     170             : {
     171             :         /* release memory claimed before */
     172     7472570 :         (void) cntxt;
     173     7472570 :         (void) mb;
     174     7472570 :         (void) pci;
     175     7472570 :         if (argclaim == 0)
     176             :                 return;
     177             : 
     178     3781747 :         MT_lock_set(&admissionLock);
     179     3784347 :         if (cntxt->memorylimit) {
     180           0 :                 stk->memory -= argclaim;
     181             :         }
     182     3784347 :         memorypool += argclaim;
     183     3784347 :         if (memorypool > (lng) MEMORY_THRESHOLD) {
     184           0 :                 memorypool = (lng) MEMORY_THRESHOLD;
     185             :         }
     186     3784347 :         stk->memory -= argclaim;
     187     3784347 :         MT_lock_unset(&admissionLock);
     188     3784347 :         return;
     189             : }

Generated by: LCOV version 1.14