1 //------------------------------------------------------------------------------
2 // GB_calloc_memory: wrapper for calloc
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 // A wrapper for calloc.  Space is set to zero.
11 
12 #include "GB.h"
13 
14 //------------------------------------------------------------------------------
15 // GB_calloc_helper:  use calloc or malloc/memset to allocate initialized block
16 //------------------------------------------------------------------------------
17 
GB_calloc_helper(size_t * size,bool malloc_tracking,GB_Context Context)18 static inline void *GB_calloc_helper
19 (
20     // input/output:
21     size_t *size,           // on input: # of bytes requested
22                             // on output: # of bytes actually allocated
23     // input:
24     bool malloc_tracking,
25     GB_Context Context
26 )
27 {
28     bool do_memset = false ;
29     void *p = NULL ;
30 
31     // determine the next higher power of 2
32     size_t size_requested = (*size) ;
33     (*size) = GB_IMAX (*size, 8) ;
34     int k = GB_CEIL_LOG2 (*size) ;
35 
36     // if available, get the block from the pool
37     if (GB_Global_free_pool_limit_get (k) > 0)
38     {
39         // round up the size to the nearest power of two
40         (*size) = ((size_t) 1) << k ;
41         p = GB_Global_free_pool_get (k) ;
42         // memset is required if the block comes from the free_pool
43         do_memset = (p != NULL) ;
44 //      if (p != NULL) printf ("calloc from pool: %p %ld\n", p, *size) ;
45     }
46 
47     if (p == NULL)
48     {
49         // no block in the free_pool, so allocate it
50 //      if (GB_Global_have_calloc_function ( ))
51 //      {
52 //          p = GB_Global_calloc_function (*size, 1) ;
53 //      }
54 //      else
55         {
56 
57 //          if (GB_Global_rmm_get ( ))
58 //          {
59 //              p = GB_rmm_alloc (size) ;
60 //          }
61 //          else
62             {
63                 p = GB_Global_malloc_function (*size) ;
64             }
65             // memset is required if the block comes from malloc
66             do_memset = (p != NULL) ;
67         }
68         if (p != NULL && malloc_tracking)
69         {
70             // success
71             GB_Global_nmalloc_increment ( ) ;
72         }
73 //      printf ("hard calloc %p %ld\n", p, *size) ;
74     }
75 
76 //  GB_Global_free_pool_dump (2) ; GB_Global_memtable_dump ( ) ;
77 
78     if (do_memset)
79     {
80         // clear the block of memory with a parallel memset
81         GB_GET_NTHREADS_MAX (nthreads_max, chunk, Context) ;
82         GB_memset (p, 0, size_requested, nthreads_max) ;
83     }
84 
85     return (p) ;
86 }
87 
88 //------------------------------------------------------------------------------
89 // GB_calloc_memory
90 //------------------------------------------------------------------------------
91 
92 GB_PUBLIC   // accessed by the MATLAB tests in GraphBLAS/Test only
GB_calloc_memory(size_t nitems,size_t size_of_item,size_t * size_allocated,GB_Context Context)93 void *GB_calloc_memory      // pointer to allocated block of memory
94 (
95     size_t nitems,          // number of items to allocate
96     size_t size_of_item,    // sizeof each item
97     // output
98     size_t *size_allocated, // # of bytes actually allocated
99     GB_Context Context
100 )
101 {
102 
103     //--------------------------------------------------------------------------
104     // check inputs
105     //--------------------------------------------------------------------------
106 
107     ASSERT (size_allocated != NULL) ;
108 
109     void *p ;
110     size_t size ;
111 
112     // make sure at least one item is allocated
113     nitems = GB_IMAX (1, nitems) ;
114 
115     // make sure at least one byte is allocated
116     size_of_item = GB_IMAX (1, size_of_item) ;
117 
118     bool ok = GB_size_t_multiply (&size, nitems, size_of_item) ;
119     if (!ok || nitems > GxB_INDEX_MAX || size_of_item > GxB_INDEX_MAX)
120     {
121         // overflow
122         (*size_allocated) = 0 ;
123         return (NULL) ;
124     }
125 
126     //--------------------------------------------------------------------------
127     // allocate the memory block
128     //--------------------------------------------------------------------------
129 
130     if (GB_Global_malloc_tracking_get ( ))
131     {
132 
133         //----------------------------------------------------------------------
134         // for memory usage testing only
135         //----------------------------------------------------------------------
136 
137         // brutal memory debug; pretend to fail if (count-- <= 0).
138         bool pretend_to_fail = false ;
139         if (GB_Global_malloc_debug_get ( ))
140         {
141             pretend_to_fail = GB_Global_malloc_debug_count_decrement ( ) ;
142         }
143 
144         // allocate the memory
145         if (pretend_to_fail)
146         {
147             p = NULL ;
148         }
149         else
150         {
151             p = GB_calloc_helper (&size, true, Context) ;
152         }
153 
154     }
155     else
156     {
157 
158         //----------------------------------------------------------------------
159         // normal use, in production
160         //----------------------------------------------------------------------
161 
162         p = GB_calloc_helper (&size, false, Context) ;
163     }
164 
165     //--------------------------------------------------------------------------
166     // return result
167     //--------------------------------------------------------------------------
168 
169     (*size_allocated) = (p == NULL) ? 0 : size ;
170     ASSERT (GB_IMPLIES (p != NULL, size == GB_Global_memtable_size (p))) ;
171     return (p) ;
172 }
173 
174