1 //------------------------------------------------------------------------------
2 // GB_Global: global values in GraphBLAS
3 //------------------------------------------------------------------------------
4 
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7 
8 //------------------------------------------------------------------------------
9 
10 // All Global storage is declared, initialized, and accessed here.  The
11 // contents of the GB_Global struct are only accessible to functions in this
12 // file.  Global storage is used to keep track of the GraphBLAS mode (blocking
13 // or non-blocking), for pointers to malloc/calloc/realloc/free functions,
14 // global matrix options, and other settings.
15 
16 #include "GB_atomics.h"
17 
18 //------------------------------------------------------------------------------
19 // Global storage: for all threads in a user application that uses GraphBLAS
20 //------------------------------------------------------------------------------
21 
22 typedef struct
23 {
24 
25     //--------------------------------------------------------------------------
26     // blocking/non-blocking mode, set by GrB_init
27     //--------------------------------------------------------------------------
28 
29     GrB_Mode mode ;             // GrB_NONBLOCKING or GrB_BLOCKING
30     bool GrB_init_called ;      // true if GrB_init already called
31 
32     //--------------------------------------------------------------------------
33     // threading control
34     //--------------------------------------------------------------------------
35 
36     int nthreads_max ;          // max number of threads to use
37     double chunk ;              // chunk size for determining # threads to use
38 
39     //--------------------------------------------------------------------------
40     // hypersparsity and CSR/CSC format control
41     //--------------------------------------------------------------------------
42 
43     float bitmap_switch [GxB_NBITMAP_SWITCH] ; // default bitmap_switch
44     float hyper_switch ;        // default hyper_switch for new matrices
45     bool is_csc ;               // default CSR/CSC format for new matrices
46 
47     //--------------------------------------------------------------------------
48     // abort function: only used for debugging
49     //--------------------------------------------------------------------------
50 
51     void (* abort_function ) (void) ;
52 
53     //--------------------------------------------------------------------------
54     // malloc/calloc/realloc/free: memory management functions
55     //--------------------------------------------------------------------------
56 
57     // All threads must use the same malloc/calloc/realloc/free functions.
58     // They default to the ANSI C11 functions, but can be defined by GxB_init.
59 
60     void * (* malloc_function  ) (size_t)         ;     // required
61 //  void * (* calloc_function  ) (size_t, size_t) ;     // no longer used
62     void * (* realloc_function ) (void *, size_t) ;     // may be NULL
63     void   (* free_function    ) (void *)         ;     // required
64     bool malloc_is_thread_safe ;   // default is true
65 
66     //--------------------------------------------------------------------------
67     // memory usage tracking: for testing and debugging only
68     //--------------------------------------------------------------------------
69 
70     // malloc_tracking:  default is false.  There is no user-accessible API for
71     // setting this to true.  If true, the following statistics are computed.
72     // If false, all of the following are unused.
73 
74     // nmalloc:  To aid in searching for memory leaks, GraphBLAS keeps track of
75     // the number of blocks of allocated that have not yet been freed.  The
76     // count starts at zero.  GB_malloc_memory and GB_calloc_memory increment
77     // this count, and free (of a non-NULL pointer) decrements it.  realloc
78     // increments the count it if is allocating a new block, but it does this
79     // by calling GB_malloc_memory.
80 
81     // malloc_debug: this is used for testing only (GraphBLAS/Tcov).  If true,
82     // then use malloc_debug_count for testing memory allocation and
83     // out-of-memory conditions.  If malloc_debug_count > 0, the value is
84     // decremented after each allocation of memory.  If malloc_debug_count <=
85     // 0, the GB_*_memory routines pretend to fail; returning NULL and not
86     // allocating anything.
87 
88     bool malloc_tracking ;          // true if allocations are being tracked
89     int64_t nmalloc ;               // number of blocks allocated but not freed
90     bool malloc_debug ;             // if true, test memory handling
91     int64_t malloc_debug_count ;    // for testing memory handling
92 
93     //--------------------------------------------------------------------------
94     // for testing and development
95     //--------------------------------------------------------------------------
96 
97     int64_t hack [2] ;              // settings for testing/developement only
98 
99     //--------------------------------------------------------------------------
100     // diagnostic output
101     //--------------------------------------------------------------------------
102 
103     bool burble ;                   // controls GBURBLE output
104     GB_printf_function_t printf_func ;  // pointer to printf
105     GB_flush_function_t flush_func ;   // pointer to flush
106 
107     //--------------------------------------------------------------------------
108     // for MATLAB interface only
109     //--------------------------------------------------------------------------
110 
111     bool print_one_based ;          // if true, print 1-based indices
112 
113     //--------------------------------------------------------------------------
114     // timing: for code development only
115     //--------------------------------------------------------------------------
116 
117     double timing [40] ;
118 
119     //--------------------------------------------------------------------------
120     // for malloc debugging only
121     //--------------------------------------------------------------------------
122 
123     #ifdef GB_DEBUG
124     #define GB_MEMTABLE_SIZE 10000
125     GB_void *memtable_p [GB_MEMTABLE_SIZE] ;
126     size_t   memtable_s [GB_MEMTABLE_SIZE] ;
127     #endif
128     int nmemtable ;
129 
130     //--------------------------------------------------------------------------
131     // internal memory pool
132     //--------------------------------------------------------------------------
133 
134     // free_pool [k] is a pointer to a link list of freed blocks, all of size
135     // exactly equal to 2^k.  The total number of blocks in the kth pool is
136     // given by free_pool_nblocks [k], and the upper bound on this is given by
137     // free_pool_limit [k].  If any additional blocks of size 2^k above that
138     // limit are freed by GB_dealloc_memory, they are not placed in the pool,
139     // but actually freed instead.
140 
141     void *free_pool [64] ;
142     int64_t free_pool_nblocks [64] ;
143     int64_t free_pool_limit [64] ;
144 
145     //--------------------------------------------------------------------------
146     // CUDA (DRAFT: in progress)
147     //--------------------------------------------------------------------------
148 
149     int gpu_count ;                 // # of GPUs in the system
150     GrB_Desc_Value gpu_control ;    // always, never, or default
151     double gpu_chunk ;              // min problem size for using a GPU
152     // properties of each GPU:
153     GB_cuda_device gpu_properties [GB_CUDA_MAX_GPUS] ;
154 
155 }
156 GB_Global_struct ;
157 
158 GB_PUBLIC GB_Global_struct GB_Global ;
159 
160 GB_Global_struct GB_Global =
161 {
162 
163     // GraphBLAS mode
164     .mode = GrB_NONBLOCKING,    // default is nonblocking
165 
166     // initialization flag
167     .GrB_init_called = false,   // GrB_init has not yet been called
168 
169     // max number of threads and chunk size
170     .nthreads_max = 1,
171     .chunk = GB_CHUNK_DEFAULT,
172 
173     // min dimension                density
174     #define GB_BITSWITCH_1          ((float) 0.04)
175     #define GB_BITSWITCH_2          ((float) 0.05)
176     #define GB_BITSWITCH_3_to_4     ((float) 0.06)
177     #define GB_BITSWITCH_5_to_8     ((float) 0.08)
178     #define GB_BITSWITCH_9_to_16    ((float) 0.10)
179     #define GB_BITSWITCH_17_to_32   ((float) 0.20)
180     #define GB_BITSWITCH_33_to_64   ((float) 0.30)
181     #define GB_BITSWITCH_gt_than_64 ((float) 0.40)
182 
183     // default format
184     .bitmap_switch = {
185         GB_BITSWITCH_1,
186         GB_BITSWITCH_2,
187         GB_BITSWITCH_3_to_4,
188         GB_BITSWITCH_5_to_8,
189         GB_BITSWITCH_9_to_16,
190         GB_BITSWITCH_17_to_32,
191         GB_BITSWITCH_33_to_64,
192         GB_BITSWITCH_gt_than_64 },
193     .hyper_switch = GB_HYPER_SWITCH_DEFAULT,
194 
195     .is_csc = (GB_FORMAT_DEFAULT != GxB_BY_ROW),    // default is GxB_BY_ROW
196 
197     // abort function for debugging only
198     .abort_function   = abort,
199 
200     // malloc/calloc/realloc/free functions: default to ANSI C11 functions
201     .malloc_function  = malloc,
202 //  .calloc_function  = NULL,   // no longer used
203     .realloc_function = realloc,
204     .free_function    = free,
205     .malloc_is_thread_safe = true,
206 
207     // malloc tracking, for testing, statistics, and debugging only
208     .malloc_tracking = false,
209     .nmalloc = 0,                // memory block counter
210     .malloc_debug = false,       // do not test memory handling
211     .malloc_debug_count = 0,     // counter for testing memory handling
212 
213     // for testing and development only
214     .hack = {0, 0},
215 
216     // diagnostics
217     .burble = false,
218     .printf_func = NULL,
219     .flush_func = NULL,
220 
221     // for MATLAB interface only
222     .print_one_based = false,   // if true, print 1-based indices
223 
224     .timing = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
225                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
226 
227     // for malloc debugging only
228     .nmemtable = 0,     // memtable is empty
229 
230     // all free_pool lists start out empty
231     .free_pool = {
232         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
233         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
234         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
235         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
236         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
237         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
238         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
239         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
240 
241     .free_pool_nblocks = {
242         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
243         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
244         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
245         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
246 
247     // default limits on the number of free blocks in each list:
248     .free_pool_limit = {
249         0,      // size 2^0 = 1 byte   none
250         0,      // size 2^1 = 2        none
251         0,      // size 2^2 = 4        none
252 
253         16483,  // size 2^3 = 8        (2^14 blocks * 2^3  = 128 KB total)
254         16483,  // size 2^4 = 16 bytes (2^14 blocks * 2^4  = 256 KB total)
255         16483,  // size 2^5 = 32       (2^14 blocks * 2^5  = 512 KB total)
256         16483,  // size 2^6 = 64       (2^14 blocks * 2^6  = 1 MB total)
257         16483,  // size 2^7 = 128      (2^14 blocks * 2^7  = 2 MB total)
258 
259         16483,  // size 2^8 = 256      (2^14 blocks * 2^8  = 4 MB total)
260         8192,   // size 2^9 = 512      (2^13 blocks * 2^9  = 4 MB total)
261         4096,   // size 2^10 = 1 KB    (2^12 blocks * 2^10 = 4 MB total)
262         2048,   // size 2^11 = 2 KB    (2^11 blocks * 2^11 = 4 MB total)
263 
264         1024,   // size 2^12 = 4 KB    (2^10 blocks * 2^12 = 4 MB total)
265         512,    // size 2^13 = 8 KB    (2^9  blocks * 2^13 = 4 MB total)
266         256,    // size 2^14 = 16 KB   (2^8  blocks * 2^14 = 4 MB total)
267         128,    // size 2^15 = 32 KB   (2^7  blocks * 2^15 = 4 MB total)
268 
269         64,     // size 2^16 = 64 KB   (2^6  blocks * 2^16 = 4 MB total)
270         32,     // size 2^17 = 128 KB  (2^5  blocks * 2^17 = 4 MB total)
271         16,     // size 2^18 = 256 KB  (2^4  blocks * 2^18 = 4 MB total)
272         8,      // size 2^19 = 512 KB  (2^3  blocks * 2^19 = 4 MB total)
273 
274         // maximum total size = about 52 MB
275         // by default, no blocks larger than 512 KB are kept in the free_pool
276 
277         0,      // size 2^20 = 1 MB
278         0,      // size 2^21
279         0,      // size 2^22
280         0,      // size 2^23
281         0,      // size 2^24
282         0,      // size 2^25
283         0,      // size 2^26
284         0,      // size 2^27
285         0,      // size 2^28
286         0,      // size 2^29
287 
288         0,      // size 2^30 (1 GB)
289         0,      // size 2^31
290         0,      // size 2^32
291         0,      // size 2^33
292         0,      // size 2^34
293         0,      // size 2^35
294         0,      // size 2^36
295         0,      // size 2^37
296         0,      // size 2^38
297         0,      // size 2^39
298 
299         // These larger sizes are of course unlikely to appear, but adding all
300         // 64 possibilities means that the free_pool does not need to check an
301         // upper bound.
302 
303         0,      // size 2^40 (1 TB)
304         0,      // size 2^41
305         0,      // size 2^42
306         0,      // size 2^43
307         0,      // size 2^44
308         0,      // size 2^45
309         0,      // size 2^46
310         0,      // size 2^47
311         0,      // size 2^48
312         0,      // size 2^49
313 
314         0,      // size 2^50 (1 PB)
315         0,      // size 2^51
316         0,      // size 2^52
317         0,      // size 2^53
318         0,      // size 2^54
319         0,      // size 2^55
320         0,      // size 2^56
321         0,      // size 2^57
322         0,      // size 2^58
323         0,      // size 2^59
324 
325         0,      // size 2^60 (1 exabyte)
326         0,      // size 2^61
327         0,      // size 2^62
328         0 },    // size 2^63 (4 exabytes!)
329 
330     // CUDA environment (DRAFT: in progress)
331     .gpu_count = 0,                     // # of GPUs in the system
332     .gpu_control = GxB_DEFAULT,         // always, never, or default
333     .gpu_chunk = GB_GPU_CHUNK_DEFAULT,  // min problem size for using a GPU
334 
335 } ;
336 
337 //==============================================================================
338 // GB_Global access functions
339 //==============================================================================
340 
341 //------------------------------------------------------------------------------
342 // mode
343 //------------------------------------------------------------------------------
344 
GB_Global_mode_set(GrB_Mode mode)345 void GB_Global_mode_set (GrB_Mode mode)
346 {
347     GB_Global.mode = mode ;
348 }
349 
GB_Global_mode_get(void)350 GrB_Mode GB_Global_mode_get (void)
351 {
352     return (GB_Global.mode) ;
353 }
354 
355 //------------------------------------------------------------------------------
356 // GrB_init_called
357 //------------------------------------------------------------------------------
358 
359 GB_PUBLIC
GB_Global_GrB_init_called_set(bool GrB_init_called)360 void GB_Global_GrB_init_called_set (bool GrB_init_called)
361 {
362     GB_Global.GrB_init_called = GrB_init_called ;
363 }
364 
365 GB_PUBLIC
GB_Global_GrB_init_called_get(void)366 bool GB_Global_GrB_init_called_get (void)
367 {
368     return (GB_Global.GrB_init_called) ;
369 }
370 
371 //------------------------------------------------------------------------------
372 // nthreads_max
373 //------------------------------------------------------------------------------
374 
375 GB_PUBLIC
GB_Global_nthreads_max_set(int nthreads_max)376 void GB_Global_nthreads_max_set (int nthreads_max)
377 {
378     GB_Global.nthreads_max = GB_IMAX (nthreads_max, 1) ;
379 }
380 
381 GB_PUBLIC
GB_Global_nthreads_max_get(void)382 int GB_Global_nthreads_max_get (void)
383 {
384     return (GB_Global.nthreads_max) ;
385 }
386 
387 //------------------------------------------------------------------------------
388 // OpenMP max_threads
389 //------------------------------------------------------------------------------
390 
391 GB_PUBLIC
GB_Global_omp_get_max_threads(void)392 int GB_Global_omp_get_max_threads (void)
393 {
394     return (GB_OPENMP_MAX_THREADS) ;
395 }
396 
397 //------------------------------------------------------------------------------
398 // chunk
399 //------------------------------------------------------------------------------
400 
401 GB_PUBLIC
GB_Global_chunk_set(double chunk)402 void GB_Global_chunk_set (double chunk)
403 {
404     if (chunk <= GxB_DEFAULT) chunk = GB_CHUNK_DEFAULT ;
405     GB_Global.chunk = fmax (chunk, 1) ;
406 }
407 
408 GB_PUBLIC
GB_Global_chunk_get(void)409 double GB_Global_chunk_get (void)
410 {
411     return (GB_Global.chunk) ;
412 }
413 
414 //------------------------------------------------------------------------------
415 // hyper_switch
416 //------------------------------------------------------------------------------
417 
418 GB_PUBLIC
GB_Global_hyper_switch_set(float hyper_switch)419 void GB_Global_hyper_switch_set (float hyper_switch)
420 {
421     GB_Global.hyper_switch = hyper_switch ;
422 }
423 
424 GB_PUBLIC
GB_Global_hyper_switch_get(void)425 float GB_Global_hyper_switch_get (void)
426 {
427     return (GB_Global.hyper_switch) ;
428 }
429 
430 //------------------------------------------------------------------------------
431 // bitmap_switch
432 //------------------------------------------------------------------------------
433 
434 GB_PUBLIC
GB_Global_bitmap_switch_set(int k,float b)435 void GB_Global_bitmap_switch_set (int k, float b)
436 {
437     k = GB_IMAX (k, 0) ;
438     k = GB_IMIN (k, 7) ;
439     GB_Global.bitmap_switch [k] = b ;
440 }
441 
442 GB_PUBLIC
GB_Global_bitmap_switch_get(int k)443 float GB_Global_bitmap_switch_get (int k)
444 {
445     k = GB_IMAX (k, 0) ;
446     k = GB_IMIN (k, 7) ;
447     return (GB_Global.bitmap_switch [k]) ;
448 }
449 
450 GB_PUBLIC
GB_Global_bitmap_switch_matrix_get(int64_t vlen,int64_t vdim)451 float GB_Global_bitmap_switch_matrix_get (int64_t vlen, int64_t vdim)
452 {
453     int64_t d = GB_IMIN (vlen, vdim) ;
454     if (d <=  1) return (GB_Global.bitmap_switch [0]) ;
455     if (d <=  2) return (GB_Global.bitmap_switch [1]) ;
456     if (d <=  4) return (GB_Global.bitmap_switch [2]) ;
457     if (d <=  8) return (GB_Global.bitmap_switch [3]) ;
458     if (d <= 16) return (GB_Global.bitmap_switch [4]) ;
459     if (d <= 32) return (GB_Global.bitmap_switch [5]) ;
460     if (d <= 64) return (GB_Global.bitmap_switch [6]) ;
461     return (GB_Global.bitmap_switch [7]) ;
462 }
463 
464 GB_PUBLIC
GB_Global_bitmap_switch_default(void)465 void GB_Global_bitmap_switch_default (void)
466 {
467     GB_Global.bitmap_switch [0] = GB_BITSWITCH_1 ;
468     GB_Global.bitmap_switch [1] = GB_BITSWITCH_2 ;
469     GB_Global.bitmap_switch [2] = GB_BITSWITCH_3_to_4 ;
470     GB_Global.bitmap_switch [3] = GB_BITSWITCH_5_to_8 ;
471     GB_Global.bitmap_switch [4] = GB_BITSWITCH_9_to_16 ;
472     GB_Global.bitmap_switch [5] = GB_BITSWITCH_17_to_32 ;
473     GB_Global.bitmap_switch [6] = GB_BITSWITCH_33_to_64 ;
474     GB_Global.bitmap_switch [7] = GB_BITSWITCH_gt_than_64 ;
475 }
476 
477 //------------------------------------------------------------------------------
478 // is_csc
479 //------------------------------------------------------------------------------
480 
GB_Global_is_csc_set(bool is_csc)481 void GB_Global_is_csc_set (bool is_csc)
482 {
483     GB_Global.is_csc = is_csc ;
484 }
485 
GB_Global_is_csc_get(void)486 bool GB_Global_is_csc_get (void)
487 {
488     return (GB_Global.is_csc) ;
489 }
490 
491 //------------------------------------------------------------------------------
492 // abort_function
493 //------------------------------------------------------------------------------
494 
495 GB_PUBLIC
GB_Global_abort_function_set(void (* abort_function)(void))496 void GB_Global_abort_function_set (void (* abort_function) (void))
497 {
498     GB_Global.abort_function = abort_function ;
499 }
500 
501 GB_PUBLIC
GB_Global_abort_function(void)502 void GB_Global_abort_function (void)
503 {
504     GB_Global.abort_function ( ) ;
505 }
506 
507 //------------------------------------------------------------------------------
508 // malloc debuging
509 //------------------------------------------------------------------------------
510 
511 // These functions keep a separate record of the pointers to all allocated
512 // blocks of memory and their sizes, just for sanity checks.
513 
514 GB_PUBLIC
GB_Global_memtable_dump(void)515 void GB_Global_memtable_dump (void)
516 {
517     #ifdef GB_DEBUG
518     printf ("\nmemtable dump: %d nmalloc %ld\n", GB_Global.nmemtable,
519         GB_Global.nmalloc) ;
520     for (int k = 0 ; k < GB_Global.nmemtable ; k++)
521     {
522         printf ("  %4d: %12p : %ld\n", k,
523             GB_Global.memtable_p [k],
524             GB_Global.memtable_s [k]) ;
525     }
526     #endif
527 }
528 
529 GB_PUBLIC
GB_Global_memtable_n(void)530 int GB_Global_memtable_n (void)
531 {
532     return (GB_Global.nmemtable) ;
533 }
534 
535 GB_PUBLIC
GB_Global_memtable_clear(void)536 void GB_Global_memtable_clear (void)
537 {
538     GB_Global.nmemtable = 0 ;
539 }
540 
541 // add a pointer to the table of malloc'd blocks
542 GB_PUBLIC
GB_Global_memtable_add(void * p,size_t size)543 void GB_Global_memtable_add (void *p, size_t size)
544 {
545     #ifdef GB_DEBUG
546     ASSERT ((p == NULL) == (size == 0)) ;
547     if (p == NULL) return ;
548     bool fail = false ;
549     // printf ("memtable add %p size %ld\n", p, size) ;
550     #pragma omp critical(GB_memtable)
551     {
552         int n = GB_Global.nmemtable  ;
553         fail = (n > GB_MEMTABLE_SIZE) ;
554         if (!fail)
555         {
556             for (int i = 0 ; i < n ; i++)
557             {
558                 if (p == GB_Global.memtable_p [i])
559                 {
560                     printf ("\nadd duplicate %p size %ld\n", p, size) ;
561                     GB_Global_memtable_dump ( ) ;
562                     printf ("Hey %d %p\n", i,p) ;
563                     fail = true ;
564                     break ;
565                 }
566             }
567         }
568         if (!fail && p != NULL)
569         {
570             GB_Global.memtable_p [n] = p ;
571             GB_Global.memtable_s [n] = size ;
572             GB_Global.nmemtable++ ;
573         }
574     }
575     ASSERT (!fail) ;
576     // GB_Global_memtable_dump ( ) ;
577     #endif
578 }
579 
580 // get the size of a malloc'd block
581 GB_PUBLIC
GB_Global_memtable_size(void * p)582 size_t GB_Global_memtable_size (void *p)
583 {
584     size_t size = 0 ;
585     #ifdef GB_DEBUG
586     if (p == NULL) return (0) ;
587     bool found = false ;
588     #pragma omp critical(GB_memtable)
589     {
590         int n = GB_Global.nmemtable  ;
591         for (int i = 0 ; i < n ; i++)
592         {
593             if (p == GB_Global.memtable_p [i])
594             {
595                 size = GB_Global.memtable_s [i] ;
596                 found = true ;
597                 break ;
598             }
599         }
600     }
601     if (!found)
602     {
603         printf ("\nFAIL: %p not found\n", p) ;
604         GB_Global_memtable_dump ( ) ;
605         ASSERT (0) ;
606     }
607     #endif
608     return (size) ;
609 }
610 
611 // test if a malloc'd block is in the table
612 GB_PUBLIC
GB_Global_memtable_find(void * p)613 bool GB_Global_memtable_find (void *p)
614 {
615     bool found = false ;
616     #ifdef GB_DEBUG
617     if (p == NULL) return (false) ;
618     #pragma omp critical(GB_memtable)
619     {
620         int n = GB_Global.nmemtable  ;
621         for (int i = 0 ; i < n ; i++)
622         {
623             if (p == GB_Global.memtable_p [i])
624             {
625                 found = true ;
626                 break ;
627             }
628         }
629     }
630     #endif
631     return (found) ;
632 }
633 
634 // remove a pointer from the table of malloc'd blocks
635 GB_PUBLIC
GB_Global_memtable_remove(void * p)636 void GB_Global_memtable_remove (void *p)
637 {
638     #ifdef GB_DEBUG
639     if (p == NULL) return ;
640     bool found = false ;
641     // printf ("memtable remove %p ", p) ;
642     #pragma omp critical(GB_memtable)
643     {
644         int n = GB_Global.nmemtable  ;
645         for (int i = 0 ; i < n ; i++)
646         {
647             if (p == GB_Global.memtable_p [i])
648             {
649                 // found p in the table; remove it
650                 // printf ("size %ld\n", GB_Global.memtable_s [i]) ;
651                 GB_Global.memtable_p [i] = GB_Global.memtable_p [n-1] ;
652                 GB_Global.memtable_s [i] = GB_Global.memtable_s [n-1] ;
653                 GB_Global.nmemtable -- ;
654                 found = true ;
655                 break ;
656             }
657         }
658     }
659     if (!found)
660     {
661         printf ("remove %p NOT FOUND\n", p) ;
662         GB_Global_memtable_dump ( ) ;
663     }
664     ASSERT (found) ;
665     // GB_Global_memtable_dump ( ) ;
666     #endif
667 }
668 
669 //------------------------------------------------------------------------------
670 // malloc_function
671 //------------------------------------------------------------------------------
672 
GB_Global_malloc_function_set(void * (* malloc_function)(size_t))673 void GB_Global_malloc_function_set (void * (* malloc_function) (size_t))
674 {
675     GB_Global.malloc_function = malloc_function ;
676 }
677 
GB_Global_malloc_function(size_t size)678 void * GB_Global_malloc_function (size_t size)
679 {
680     void *p = NULL ;
681     if (GB_Global.malloc_is_thread_safe)
682     {
683         p = GB_Global.malloc_function (size) ;
684     }
685     else
686     {
687         #pragma omp critical(GB_malloc_protection)
688         {
689             p = GB_Global.malloc_function (size) ;
690         }
691     }
692     #ifdef GB_DEBUG
693     GB_Global_memtable_add (p, size) ;
694     #endif
695     return (p) ;
696 }
697 
698 //------------------------------------------------------------------------------
699 // calloc_function: no longer used
700 //------------------------------------------------------------------------------
701 
702 //  void GB_Global_calloc_function_set (void * (* calloc_function) (size_t, size_t))
703 //  {
704 //      GB_Global.calloc_function = calloc_function ;
705 //  }
706 
707 //  bool GB_Global_have_calloc_function (void)
708 //  {
709 //      return (GB_Global.calloc_function != NULL) ;
710 //  }
711 
712 //  void * GB_Global_calloc_function (size_t count, size_t size)
713 //  {
714 //      void *p = NULL ;
715 //      if (GB_Global.malloc_is_thread_safe)
716 //      {
717 //          p = GB_Global.calloc_function (count, size) ;
718 //      }
719 //      else
720 //      {
721 //          #pragma omp critical(GB_malloc_protection)
722 //          {
723 //              p = GB_Global.calloc_function (count, size) ;
724 //          }
725 //      }
726 //      #ifdef GB_DEBUG
727 //      GB_Global_memtable_add (p, count * size) ;
728 //      #endif
729 //      return (p) ;
730 //  }
731 
732 //------------------------------------------------------------------------------
733 // realloc_function
734 //------------------------------------------------------------------------------
735 
GB_Global_realloc_function_set(void * (* realloc_function)(void *,size_t))736 void GB_Global_realloc_function_set
737 (
738     void * (* realloc_function) (void *, size_t)
739 )
740 {
741     GB_Global.realloc_function = realloc_function ;
742 }
743 
GB_Global_have_realloc_function(void)744 bool GB_Global_have_realloc_function (void)
745 {
746     return (GB_Global.realloc_function != NULL) ;
747 }
748 
GB_Global_realloc_function(void * p,size_t size)749 void * GB_Global_realloc_function (void *p, size_t size)
750 {
751     void *pnew = NULL ;
752     if (GB_Global.malloc_is_thread_safe)
753     {
754         pnew = GB_Global.realloc_function (p, size) ;
755     }
756     else
757     {
758         #pragma omp critical(GB_malloc_protection)
759         {
760             pnew = GB_Global.realloc_function (p, size) ;
761         }
762     }
763     #ifdef GB_DEBUG
764     if (pnew != NULL)
765     {
766         GB_Global_memtable_remove (p) ;
767         GB_Global_memtable_add (pnew, size) ;
768     }
769     #endif
770     return (pnew) ;
771 }
772 
773 //------------------------------------------------------------------------------
774 // free_function
775 //------------------------------------------------------------------------------
776 
GB_Global_free_function_set(void (* free_function)(void *))777 void GB_Global_free_function_set (void (* free_function) (void *))
778 {
779     GB_Global.free_function = free_function ;
780 }
781 
GB_Global_free_function(void * p)782 void GB_Global_free_function (void *p)
783 {
784     if (GB_Global.malloc_is_thread_safe)
785     {
786         GB_Global.free_function (p) ;
787     }
788     else
789     {
790         #pragma omp critical(GB_malloc_protection)
791         {
792             GB_Global.free_function (p) ;
793         }
794     }
795     #ifdef GB_DEBUG
796     GB_Global_memtable_remove (p) ;
797     #endif
798 }
799 
800 //------------------------------------------------------------------------------
801 // malloc_is_thread_safe
802 //------------------------------------------------------------------------------
803 
804 GB_PUBLIC
GB_Global_malloc_is_thread_safe_set(bool malloc_is_thread_safe)805 void GB_Global_malloc_is_thread_safe_set (bool malloc_is_thread_safe)
806 {
807     GB_Global.malloc_is_thread_safe = malloc_is_thread_safe ;
808 }
809 
810 GB_PUBLIC
GB_Global_malloc_is_thread_safe_get(void)811 bool GB_Global_malloc_is_thread_safe_get (void)
812 {
813     return (GB_Global.malloc_is_thread_safe) ;
814 }
815 
816 //------------------------------------------------------------------------------
817 // malloc_tracking
818 //------------------------------------------------------------------------------
819 
820 GB_PUBLIC
GB_Global_malloc_tracking_set(bool malloc_tracking)821 void GB_Global_malloc_tracking_set (bool malloc_tracking)
822 {
823     GB_Global.malloc_tracking = malloc_tracking ;
824 }
825 
GB_Global_malloc_tracking_get(void)826 bool GB_Global_malloc_tracking_get (void)
827 {
828     return (GB_Global.malloc_tracking) ;
829 }
830 
831 //------------------------------------------------------------------------------
832 // nmalloc
833 //------------------------------------------------------------------------------
834 
GB_Global_nmalloc_clear(void)835 void GB_Global_nmalloc_clear (void)
836 {
837     GB_ATOMIC_WRITE
838     GB_Global.nmalloc = 0 ;
839 }
840 
841 GB_PUBLIC
GB_Global_nmalloc_get(void)842 int64_t GB_Global_nmalloc_get (void)
843 {
844     int64_t nmalloc ;
845     GB_ATOMIC_READ
846     nmalloc = GB_Global.nmalloc ;
847     return (nmalloc) ;
848 }
849 
GB_Global_nmalloc_increment(void)850 void GB_Global_nmalloc_increment (void)
851 {
852     GB_ATOMIC_UPDATE
853     GB_Global.nmalloc++ ;
854 }
855 
856 GB_PUBLIC
GB_Global_nmalloc_decrement(void)857 void GB_Global_nmalloc_decrement (void)
858 {
859     GB_ATOMIC_UPDATE
860     GB_Global.nmalloc-- ;
861 }
862 
863 //------------------------------------------------------------------------------
864 // malloc_debug
865 //------------------------------------------------------------------------------
866 
867 GB_PUBLIC
GB_Global_malloc_debug_set(bool malloc_debug)868 void GB_Global_malloc_debug_set (bool malloc_debug)
869 {
870     GB_ATOMIC_WRITE
871     GB_Global.malloc_debug = malloc_debug ;
872 }
873 
GB_Global_malloc_debug_get(void)874 bool GB_Global_malloc_debug_get (void)
875 {
876     bool malloc_debug ;
877     GB_ATOMIC_READ
878     malloc_debug = GB_Global.malloc_debug ;
879     return (malloc_debug) ;
880 }
881 
882 //------------------------------------------------------------------------------
883 // malloc_debug_count
884 //------------------------------------------------------------------------------
885 
886 GB_PUBLIC
GB_Global_malloc_debug_count_set(int64_t malloc_debug_count)887 void GB_Global_malloc_debug_count_set (int64_t malloc_debug_count)
888 {
889     GB_ATOMIC_WRITE
890     GB_Global.malloc_debug_count = malloc_debug_count ;
891 }
892 
GB_Global_malloc_debug_count_decrement(void)893 bool GB_Global_malloc_debug_count_decrement (void)
894 {
895     GB_ATOMIC_UPDATE
896     GB_Global.malloc_debug_count-- ;
897 
898     int64_t malloc_debug_count ;
899     GB_ATOMIC_READ
900     malloc_debug_count = GB_Global.malloc_debug_count ;
901     return (malloc_debug_count <= 0) ;
902 }
903 
904 //------------------------------------------------------------------------------
905 // hack: for setting an internal flag for testing and development only
906 //------------------------------------------------------------------------------
907 
908 GB_PUBLIC
GB_Global_hack_set(int k,int64_t hack)909 void GB_Global_hack_set (int k, int64_t hack)
910 {
911     GB_Global.hack [k] = hack ;
912 }
913 
914 GB_PUBLIC
GB_Global_hack_get(int k)915 int64_t GB_Global_hack_get (int k)
916 {
917     return (GB_Global.hack [k]) ;
918 }
919 
920 //------------------------------------------------------------------------------
921 // burble: for controlling the burble output
922 //------------------------------------------------------------------------------
923 
GB_Global_burble_set(bool burble)924 void GB_Global_burble_set (bool burble)
925 {
926     GB_Global.burble = burble ;
927 }
928 
929 GB_PUBLIC
GB_Global_burble_get(void)930 bool GB_Global_burble_get (void)
931 {
932     return (GB_Global.burble) ;
933 }
934 
935 GB_PUBLIC
GB_Global_printf_get()936 GB_printf_function_t GB_Global_printf_get ( )
937 {
938     return (GB_Global.printf_func) ;
939 }
940 
941 GB_PUBLIC
GB_Global_flush_get()942 GB_flush_function_t GB_Global_flush_get ( )
943 {
944     return (GB_Global.flush_func) ;
945 }
946 
947 GB_PUBLIC
GB_Global_printf_set(GB_printf_function_t pr_func)948 void GB_Global_printf_set (GB_printf_function_t pr_func)
949 {
950     GB_Global.printf_func = pr_func ;
951 }
952 
953 GB_PUBLIC
GB_Global_flush_set(GB_flush_function_t fl_func)954 void GB_Global_flush_set (GB_flush_function_t fl_func)
955 {
956     GB_Global.flush_func = fl_func ;
957 }
958 
959 //------------------------------------------------------------------------------
960 // for MATLAB interface only
961 //------------------------------------------------------------------------------
962 
963 GB_PUBLIC
GB_Global_print_one_based_set(bool onebased)964 void GB_Global_print_one_based_set (bool onebased)
965 {
966     GB_Global.print_one_based = onebased ;
967 }
968 
969 GB_PUBLIC
GB_Global_print_one_based_get(void)970 bool GB_Global_print_one_based_get (void)
971 {
972     return (GB_Global.print_one_based) ;
973 }
974 
975 //------------------------------------------------------------------------------
976 // CUDA (DRAFT: in progress)
977 //------------------------------------------------------------------------------
978 
GB_Global_gpu_control_set(GrB_Desc_Value gpu_control)979 void GB_Global_gpu_control_set (GrB_Desc_Value gpu_control)
980 {
981     // set the GPU control to always, never, or default
982     if (GB_Global.gpu_count > 0)
983     {
984         // one or more GPUs are available: set gpu_control to
985         // always, never, or default.
986         if (gpu_control == GxB_GPU_ALWAYS || gpu_control == GxB_GPU_NEVER)
987         {
988             GB_Global.gpu_control = gpu_control ;
989         }
990         else
991         {
992             GB_Global.gpu_control = GxB_DEFAULT ;
993         }
994     }
995     else
996     {
997         // no GPUs available: never use a GPU
998         GB_Global.gpu_control = GxB_GPU_NEVER ;
999     }
1000 }
1001 
GB_Global_gpu_control_get(void)1002 GrB_Desc_Value GB_Global_gpu_control_get (void)
1003 {
1004     // get the GPU control parameter
1005     return (GB_Global.gpu_control) ;
1006 }
1007 
GB_Global_gpu_chunk_set(double gpu_chunk)1008 void GB_Global_gpu_chunk_set (double gpu_chunk)
1009 {
1010     // set the GPU chunk factor
1011     if (gpu_chunk < 1) gpu_chunk = GB_GPU_CHUNK_DEFAULT ;
1012     GB_Global.gpu_chunk = gpu_chunk ;
1013 }
1014 
GB_Global_gpu_chunk_get(void)1015 double GB_Global_gpu_chunk_get (void)
1016 {
1017     // get the GPU chunk factor
1018     return (GB_Global.gpu_chunk) ;
1019 }
1020 
GB_Global_gpu_count_set(bool enable_cuda)1021 bool GB_Global_gpu_count_set (bool enable_cuda)
1022 {
1023     // set the # of GPUs in the system;
1024     // this function is only called once, by GB_init.
1025     #if defined ( GBCUDA )
1026     if (enable_cuda)
1027     {
1028         return (GB_cuda_get_device_count (&GB_Global.gpu_count)) ;
1029     }
1030     else
1031     #endif
1032     {
1033         // no GPUs available, or available but not requested
1034         GB_Global.gpu_count = 0 ;
1035         return (true) ;
1036     }
1037 }
1038 
GB_Global_gpu_count_get(void)1039 int GB_Global_gpu_count_get (void)
1040 {
1041     // get the # of GPUs in the system
1042     return (GB_Global.gpu_count) ;
1043 }
1044 
1045 #define GB_GPU_DEVICE_CHECK(error) \
1046     if (device < 0 || device >= GB_Global.gpu_count) return (error) ;
1047 
GB_Global_gpu_memorysize_get(int device)1048 size_t GB_Global_gpu_memorysize_get (int device)
1049 {
1050     // get the memory size of a specific GPU
1051     GB_GPU_DEVICE_CHECK (0) ;       // memory size zero if invalid GPU
1052     return (GB_Global.gpu_properties [device].total_global_memory) ;
1053 }
1054 
GB_Global_gpu_sm_get(int device)1055 int GB_Global_gpu_sm_get (int device)
1056 {
1057     // get the # of SMs in a specific GPU
1058     GB_GPU_DEVICE_CHECK (0) ;       // zero if invalid GPU
1059     return (GB_Global.gpu_properties [device].number_of_sms)  ;
1060 }
1061 
GB_Global_gpu_device_pool_size_set(int device,size_t size)1062 bool GB_Global_gpu_device_pool_size_set( int device, size_t size)
1063 {
1064     GB_GPU_DEVICE_CHECK (0) ;       // zero if invalid GPU
1065     GB_Global.gpu_properties [device].pool_size = (int) size ;
1066     return( true);
1067 }
1068 
GB_Global_gpu_device_max_pool_size_set(int device,size_t size)1069 bool GB_Global_gpu_device_max_pool_size_set( int device, size_t size)
1070 {
1071     GB_GPU_DEVICE_CHECK (0) ;       // zero if invalid GPU
1072     GB_Global.gpu_properties[device].max_pool_size = (int) size ;
1073     return( true);
1074 }
1075 
GB_Global_gpu_device_memory_resource_set(int device,void * resource)1076 bool GB_Global_gpu_device_memory_resource_set( int device, void *resource)
1077 {
1078     GB_GPU_DEVICE_CHECK (0) ;       // zero if invalid GPU
1079     GB_Global.gpu_properties[device].memory_resource = resource;
1080     return( true);
1081 }
1082 
GB_Global_gpu_device_memory_resource_get(int device)1083 void* GB_Global_gpu_device_memory_resource_get( int device )
1084 {
1085     GB_GPU_DEVICE_CHECK (0) ;       // zero if invalid GPU
1086     return ( GB_Global.gpu_properties [device].memory_resource ) ;
1087     //NOTE: this returns a void*, needs to be cast to be used
1088 }
1089 
GB_Global_gpu_device_properties_get(int device)1090 bool GB_Global_gpu_device_properties_get (int device)
1091 {
1092     // get all properties of a specific GPU;
1093     // this function is only called once per GPU, by GB_init.
1094     GB_GPU_DEVICE_CHECK (false) ;   // fail if invalid GPU
1095     #if defined ( GBCUDA )
1096     return (GB_cuda_get_device_properties (device,
1097         &(GB_Global.gpu_properties [device]))) ;
1098     #else
1099     // if no GPUs exist, they cannot be queried
1100     return (false) ;
1101     #endif
1102 }
1103 
1104 //------------------------------------------------------------------------------
1105 // timing: for code development only
1106 //------------------------------------------------------------------------------
1107 
1108 GB_PUBLIC
GB_Global_timing_clear_all(void)1109 void GB_Global_timing_clear_all (void)
1110 {
1111     for (int k = 0 ; k < 40 ; k++)
1112     {
1113         GB_Global.timing [k] = 0 ;
1114     }
1115 }
1116 
1117 GB_PUBLIC
GB_Global_timing_clear(int k)1118 void GB_Global_timing_clear (int k)
1119 {
1120     GB_Global.timing [k] = 0 ;
1121 }
1122 
1123 GB_PUBLIC
GB_Global_timing_set(int k,double t)1124 void GB_Global_timing_set (int k, double t)
1125 {
1126     GB_Global.timing [k] = t ;
1127 }
1128 
1129 GB_PUBLIC
GB_Global_timing_add(int k,double t)1130 void GB_Global_timing_add (int k, double t)
1131 {
1132     GB_Global.timing [k] += t ;
1133 }
1134 
1135 GB_PUBLIC
GB_Global_timing_get(int k)1136 double GB_Global_timing_get (int k)
1137 {
1138     return (GB_Global.timing [k]) ;
1139 }
1140 
1141 //------------------------------------------------------------------------------
1142 // free_pool: fast access to free memory blocks
1143 //------------------------------------------------------------------------------
1144 
1145 // each free block contains a pointer to the next free block.  This requires
1146 // the free block to be at least 8 bytes in size.
1147 #define GB_NEXT(p) ((void **) p) [0]
1148 
1149 // free_pool_init: initialize the free_pool
1150 GB_PUBLIC
GB_Global_free_pool_init(bool clear)1151 void GB_Global_free_pool_init (bool clear)
1152 {
1153     #pragma omp critical(GB_free_pool)
1154     {
1155         if (clear)
1156         {
1157             // clear the free pool
1158             for (int k = 0 ; k < 64 ; k++)
1159             {
1160                 GB_Global.free_pool [k] = NULL ;
1161                 GB_Global.free_pool_nblocks [k] = 0 ;
1162             }
1163         }
1164         // set the default free_pool_limit
1165         for (int k = 0 ; k < 64 ; k++)
1166         {
1167             GB_Global.free_pool_limit [k] = 0 ;
1168         }
1169         int64_t n = 16384 ;
1170         for (int k = 3 ; k <= 8 ; k++)
1171         {
1172             GB_Global.free_pool_limit [k] = n ;
1173         }
1174         for (int k = 9 ; k <= 19 ; k++)
1175         {
1176             n = n/2 ;
1177             GB_Global.free_pool_limit [k] = n ;
1178         }
1179     }
1180 }
1181 
1182 #ifdef GB_DEBUG
1183 // check if a block is valid
GB_Global_free_pool_check(void * p,int k,char * where)1184 static inline void GB_Global_free_pool_check (void *p, int k, char *where)
1185 {
1186     // check the size of the block
1187     // printf ("check %p\n", p) ;
1188     ASSERT (k >= 3 && k < 64) ;
1189     ASSERT (p != NULL) ;
1190     size_t size = GB_Global_memtable_size (p) ;
1191     ASSERT (size == ((size_t) 1) << k) ;
1192 }
1193 #endif
1194 
1195 // free_pool_get: get a block from the free_pool, or return NULL if none
1196 GB_PUBLIC
GB_Global_free_pool_get(int k)1197 void *GB_Global_free_pool_get (int k)
1198 {
1199     void *p = NULL ;
1200     ASSERT (k >= 3 && k < 64) ;
1201     #pragma omp critical(GB_free_pool)
1202     {
1203         p = GB_Global.free_pool [k] ;
1204         if (p != NULL)
1205         {
1206             // remove the block from the kth free_pool
1207             GB_Global.free_pool_nblocks [k]-- ;
1208             GB_Global.free_pool [k] = GB_NEXT (p) ;
1209         }
1210     }
1211     if (p != NULL)
1212     {
1213         // clear the next pointer inside the block, since the block needs
1214         // to be all zero
1215         // printf ("got %p k %d\n", p, k) ;
1216         #ifdef GB_DEBUG
1217         GB_Global_free_pool_check (p, k, "get") ;
1218         #endif
1219         // GB_Global_free_pool_dump (2) ; printf ("\ndid get\n\n") ;
1220     }
1221     return (p) ;
1222 }
1223 
1224 // free_pool_put: put a block in the free_pool, unless it is full
1225 GB_PUBLIC
GB_Global_free_pool_put(void * p,int k)1226 bool GB_Global_free_pool_put (void *p, int k)
1227 {
1228     #ifdef GB_DEBUG
1229     GB_Global_free_pool_check (p, k, "put") ;
1230     #endif
1231     bool returned_to_pool = false ;
1232     #pragma omp critical(GB_free_pool)
1233     {
1234         returned_to_pool =
1235             (GB_Global.free_pool_nblocks [k] < GB_Global.free_pool_limit [k]) ;
1236         if (returned_to_pool)
1237         {
1238             // add the block to the head of the free_pool list
1239             // printf ("put %p k %d\n", p, k) ;
1240             GB_Global.free_pool_nblocks [k]++ ;
1241             GB_NEXT (p) = GB_Global.free_pool [k] ;
1242             GB_Global.free_pool [k] = p ;
1243         }
1244     }
1245     // GB_Global_free_pool_dump (2) ; printf ("\ndid put\n\n") ;
1246     return (returned_to_pool) ;
1247 }
1248 
1249 // free_pool_dump: check the validity of the free_pool
1250 GB_PUBLIC
GB_Global_free_pool_dump(int pr)1251 void GB_Global_free_pool_dump (int pr)
1252 {
1253     #ifdef GB_DEBUG
1254     bool fail = false ;
1255     #pragma omp critical(GB_free_pool)
1256     {
1257         for (int k = 0 ; k < 64 && !fail ; k++)
1258         {
1259             int64_t nblocks = GB_Global.free_pool_nblocks [k] ;
1260             int64_t limit   = GB_Global.free_pool_limit [k] ;
1261             if (nblocks != 0 && pr > 0)
1262             {
1263                 printf ("pool %2d: %8ld blocks, %8ld limit\n",
1264                     k, nblocks, limit) ;
1265             }
1266             int64_t nblocks_actual = 0 ;
1267             void *p = GB_Global.free_pool [k] ;
1268             for ( ; p != NULL && !fail ; p = GB_NEXT (p))
1269             {
1270                 if (pr > 1) printf ("  %16p ", p) ;
1271                 size_t size = GB_Global_memtable_size (p) ;
1272                 if (pr > 1) printf ("size: %ld\n", size) ;
1273                 nblocks_actual++ ;
1274                 fail = fail || (size != ((size_t) 1) << k) ;
1275                 if (fail && pr > 0) printf ("    fail\n") ;
1276                 fail = fail || (nblocks_actual > nblocks) ;
1277             }
1278             if (nblocks_actual != nblocks)
1279             {
1280                 if (pr > 0) printf ("fail: # blocks %ld %ld\n",
1281                     nblocks_actual, nblocks) ;
1282                 fail = true ;
1283             }
1284         }
1285     }
1286     ASSERT (!fail) ;
1287     #endif
1288 }
1289 
1290 // free_pool_limit_get: get the limit on the # of blocks in the kth pool
1291 GB_PUBLIC
GB_Global_free_pool_limit_get(int k)1292 int64_t GB_Global_free_pool_limit_get (int k)
1293 {
1294     int64_t nblocks = 0 ;
1295     if (k >= 3 && k < 64)
1296     {
1297         #pragma omp critical(GB_free_pool)
1298         {
1299             nblocks = GB_Global.free_pool_limit [k] ;
1300         }
1301     }
1302     return (nblocks) ;
1303 }
1304 
1305 // free_pool_limit_set: set the limit on the # of blocks in the kth pool
1306 GB_PUBLIC
GB_Global_free_pool_limit_set(int k,int64_t nblocks)1307 void GB_Global_free_pool_limit_set (int k, int64_t nblocks)
1308 {
1309     if (k >= 3 && k < 64)
1310     {
1311         #pragma omp critical(GB_free_pool)
1312         {
1313             GB_Global.free_pool_limit [k] = nblocks ;
1314         }
1315     }
1316 }
1317 
1318 // free_pool_nblocks_total:  total # of blocks in free_pool (for debug only)
1319 GB_PUBLIC
GB_Global_free_pool_nblocks_total(void)1320 int64_t GB_Global_free_pool_nblocks_total (void)
1321 {
1322     int64_t nblocks = 0 ;
1323     #pragma omp critical(GB_free_pool)
1324     {
1325         for (int k = 0 ; k < 64 ; k++)
1326         {
1327             nblocks += GB_Global.free_pool_nblocks [k] ;
1328         }
1329     }
1330     return (nblocks) ;
1331 }
1332 
1333