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