Coverage Report

Created: 2019-07-03 22:50

/home/liu/buildslave/linux-x64-runtests/build/lib/ccv_memory.c
Line
Count
Source (jump to first uncovered line)
1
#include "ccv.h"
2
#include "ccv_internal.h"
3
#include "3rdparty/siphash/siphash24.h"
4
5
static __thread ccv_cache_t ccv_cache;
6
7
/**
8
 * For new typed cache object:
9
 * ccv_dense_matrix_t: type 0
10
 * ccv_array_t: type 1
11
 **/
12
13
/* option to enable/disable cache */
14
static __thread int ccv_cache_opt = 0;
15
16
ccv_dense_matrix_t* ccv_dense_matrix_new(int rows, int cols, int type, void* data, uint64_t sig)
17
12.8M
{
18
12.8M
  ccv_dense_matrix_t* mat;
19
12.8M
  if (ccv_cache_opt && 
sig != 05.81M
&&
!data2.81M
&&
!(type & CCV_NO_DATA_ALLOC)2.81M
)
20
2.81M
  {
21
2.81M
    uint8_t type;
22
2.81M
    mat = (ccv_dense_matrix_t*)ccv_cache_out(&ccv_cache, sig, &type);
23
2.81M
    if (mat)
24
2.25M
    {
25
2.25M
      assert(type == 0);
26
2.25M
      mat->type |= CCV_GARBAGE; // set the flag so the upper level function knows this is from recycle-bin
27
2.25M
      mat->refcount = 1;
28
2.25M
      return mat;
29
10.6M
    }
30
2.81M
  }
31
10.6M
  if (type & CCV_NO_DATA_ALLOC)
32
1
  {
33
1
    mat = (ccv_dense_matrix_t*)ccmalloc(sizeof(ccv_dense_matrix_t));
34
1
    mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC) & ~CCV_GARBAGE;
35
1
    mat->data.u8 = data;
36
10.6M
  } else {
37
10.6M
    const size_t hdr_size = (sizeof(ccv_dense_matrix_t) + 15) & -16;
38
10.6M
    mat = (ccv_dense_matrix_t*)(data ? 
data0
: ccmalloc(ccv_compute_dense_matrix_size(rows, cols, type)));
39
10.6M
    mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE) & ~CCV_GARBAGE;
40
10.6M
    mat->type |= data ? 
CCV_UNMANAGED0
: CCV_REUSABLE; // it still could be reusable because the signature could be derived one.
41
10.6M
    mat->data.u8 = (unsigned char*)mat + hdr_size;
42
10.6M
  }
43
10.6M
  mat->sig = sig;
44
10.6M
#if CCV_NNC_TENSOR_TFB
45
10.6M
  mat->reserved0 = 0;
46
10.6M
  mat->resides = CCV_TENSOR_CPU_MEMORY;
47
10.6M
  mat->format = CCV_TENSOR_FORMAT_NHWC;
48
10.6M
  mat->datatype = CCV_GET_DATA_TYPE(type);
49
10.6M
  mat->channels = CCV_GET_CHANNEL(type);
50
10.6M
  mat->reserved1 = 0;
51
10.6M
#endif
52
10.6M
  mat->rows = rows;
53
10.6M
  mat->cols = cols;
54
10.6M
  mat->step = CCV_GET_STEP(cols, type);
55
10.6M
  mat->refcount = 1;
56
10.6M
  return mat;
57
10.6M
}
58
59
ccv_dense_matrix_t* ccv_dense_matrix_renew(ccv_dense_matrix_t* x, int rows, int cols, int types, int prefer_type, uint64_t sig)
60
8.75M
{
61
8.75M
  if (x != 0)
62
1.76M
  {
63
1.76M
    assert(x->rows == rows && x->cols == cols && (CCV_GET_DATA_TYPE(x->type) & types) && (CCV_GET_CHANNEL(x->type) == CCV_GET_CHANNEL(types)));
64
1.76M
    
prefer_type = 1.76M
CCV_GET_DATA_TYPE1.76M
(x->type) |
CCV_GET_CHANNEL1.76M
(x->type);
65
1.76M
  }
66
8.75M
  
if (8.75M
sig != 08.75M
)
67
43
    sig = ccv_cache_generate_signature((const char*)&prefer_type, sizeof(int), sig, CCV_EOF_SIGN);
68
8.75M
  if (x == 0)
69
6.96M
  {
70
6.96M
    x = ccv_dense_matrix_new(rows, cols, prefer_type, 0, sig);
71
6.96M
  } else {
72
1.78M
    x->sig = sig;
73
1.78M
  }
74
8.75M
  return x;
75
8.75M
}
76
77
void ccv_make_matrix_mutable(ccv_matrix_t* mat)
78
0
{
79
0
  int type = *(int*)mat;
80
0
  if (type & CCV_MATRIX_DENSE)
81
0
  {
82
0
    ccv_dense_matrix_t* dmt = (ccv_dense_matrix_t*)mat;
83
0
    dmt->sig = 0;
84
0
    dmt->type &= ~CCV_REUSABLE;
85
0
  }
86
0
}
87
88
void ccv_make_matrix_immutable(ccv_matrix_t* mat)
89
72
{
90
72
  int type = *(int*)mat;
91
72
  if (type & CCV_MATRIX_DENSE)
92
72
  {
93
72
    ccv_dense_matrix_t* dmt = (ccv_dense_matrix_t*)mat;
94
72
    assert(dmt->sig == 0); // you cannot make matrix with derived signature immutable (it is immutable already)
95
72
    /* immutable matrix made this way is not reusable (collected), because its signature
96
72
     * only depends on the content, not the operation to generate it */
97
72
    dmt->type &= ~CCV_REUSABLE;
98
72
    dmt->sig = ccv_cache_generate_signature((char*)dmt->data.u8, dmt->rows * dmt->step, (uint64_t)dmt->type, CCV_EOF_SIGN);
99
72
  }
100
72
}
101
102
ccv_dense_matrix_t ccv_dense_matrix(int rows, int cols, int type, void* data, uint64_t sig)
103
44.8k
{
104
44.8k
  ccv_dense_matrix_t mat;
105
44.8k
  mat.reserved0 = 0;
106
44.8k
  mat.sig = sig;
107
44.8k
  mat.type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC | CCV_UNMANAGED) & ~CCV_GARBAGE;
108
44.8k
  mat.rows = rows;
109
44.8k
  mat.cols = cols;
110
44.8k
  mat.step = CCV_GET_STEP(cols, type);
111
44.8k
  mat.refcount = 1;
112
44.8k
#if CCV_NNC_TENSOR_TFB
113
44.8k
  mat.reserved0 = 0;
114
44.8k
  mat.resides = CCV_TENSOR_CPU_MEMORY;
115
44.8k
  mat.format = CCV_TENSOR_FORMAT_NHWC;
116
44.8k
  mat.datatype = CCV_GET_DATA_TYPE(type);
117
44.8k
  mat.channels = CCV_GET_CHANNEL(type);
118
44.8k
  mat.reserved1 = 0;
119
44.8k
#endif
120
44.8k
  mat.data.u8 = (unsigned char*)data;
121
44.8k
  return mat;
122
44.8k
}
123
124
ccv_sparse_matrix_t* ccv_sparse_matrix_new(int rows, int cols, int type, int major, uint64_t sig)
125
5.93k
{
126
5.93k
  ccv_sparse_matrix_t* mat;
127
5.93k
  mat = (ccv_sparse_matrix_t*)ccmalloc(sizeof(ccv_sparse_matrix_t));
128
5.93k
  mat->rows = rows;
129
5.93k
  mat->cols = cols;
130
5.93k
  mat->type = type | CCV_MATRIX_SPARSE | ((type & CCV_DENSE_VECTOR) ? 
CCV_DENSE_VECTOR2
:
CCV_SPARSE_VECTOR5.93k
);
131
5.93k
  mat->major = major;
132
5.93k
  mat->prime_index = 1; // See ccv_util.c to know why this is 1 and why size is 2.
133
5.93k
  mat->size = 2;
134
5.93k
  mat->rnum = 0;
135
5.93k
  mat->refcount = 1;
136
5.93k
  mat->index = (ccv_sparse_matrix_index_t*)cccalloc(sizeof(ccv_sparse_matrix_index_t), mat->size);
137
5.93k
  mat->vector = (ccv_sparse_matrix_vector_t*)ccmalloc(sizeof(ccv_sparse_matrix_vector_t) * mat->size);
138
5.93k
  return mat;
139
5.93k
}
140
141
void ccv_matrix_free_immediately(ccv_matrix_t* mat)
142
3.56M
{
143
3.56M
  int type = *(int*)mat;
144
3.56M
  assert(!(type & CCV_UNMANAGED));
145
3.56M
  if (type & CCV_MATRIX_DENSE)
146
3.56M
  {
147
3.56M
    ccv_dense_matrix_t* dmt = (ccv_dense_matrix_t*)mat;
148
3.56M
    dmt->refcount = 0;
149
3.56M
    ccfree(dmt);
150
3.56M
  } else 
if (0
type & CCV_MATRIX_SPARSE0
) {
151
0
    ccv_sparse_matrix_t* smt = (ccv_sparse_matrix_t*)mat;
152
0
    int i;
153
0
    for (i = 0; i < smt->size; i++)
154
0
      if (smt->index[i].ifbit)
155
0
        ccfree(smt->vector[i].data.u8);
156
0
    ccfree(smt->vector);
157
0
    ccfree(smt);
158
0
  } else if ((type & CCV_MATRIX_CSR) || (type & CCV_MATRIX_CSC)) {
159
0
    ccv_compressed_sparse_matrix_t* csm = (ccv_compressed_sparse_matrix_t*)mat;
160
0
    csm->refcount = 0;
161
0
    ccfree(csm);
162
0
  }
163
3.56M
}
164
165
void ccv_matrix_free(ccv_matrix_t* mat)
166
9.90M
{
167
9.90M
  int type = *(int*)mat;
168
9.90M
  assert(!(type & CCV_UNMANAGED));
169
9.92M
  if (type & CCV_MATRIX_DENSE)
170
9.91M
  {
171
9.91M
    ccv_dense_matrix_t* dmt = (ccv_dense_matrix_t*)mat;
172
9.91M
    dmt->refcount = 0;
173
9.91M
    if (!ccv_cache_opt || // e don't enable cache
174
9.91M
      
!(dmt->type & CCV_REUSABLE)3.00M
|| // or this is not a reusable piece
175
9.91M
      
dmt->sig == 03.00M
|| // or this doesn't have valid signature
176
9.91M
      
(dmt->type & CCV_NO_DATA_ALLOC)3.00M
) // or this matrix is allocated as header-only, therefore we cannot cache it
177
9.91M
      
ccfree6.88M
(dmt)6.88M
;
178
3.02M
    else {
179
3.02M
      assert(CCV_GET_DATA_TYPE(dmt->type) == CCV_8U ||
180
3.02M
           CCV_GET_DATA_TYPE(dmt->type) == CCV_32S ||
181
3.02M
           CCV_GET_DATA_TYPE(dmt->type) == CCV_32F ||
182
3.02M
           CCV_GET_DATA_TYPE(dmt->type) == CCV_64S ||
183
3.02M
           CCV_GET_DATA_TYPE(dmt->type) == CCV_64F);
184
3.02M
      
size_t size = 3.00M
ccv_compute_dense_matrix_size3.00M
(dmt->rows, dmt->cols, dmt->type);
185
3.00M
      ccv_cache_put(&ccv_cache, dmt->sig, dmt, size, 0 /* type 0 */);
186
3.00M
    }
187
9.91M
  } else 
if (6.05k
type & CCV_MATRIX_SPARSE6.05k
) {
188
5.93k
    ccv_sparse_matrix_t* smt = (ccv_sparse_matrix_t*)mat;
189
5.93k
    int i;
190
67.5k
    for (i = 0; i < smt->size; 
i++61.6k
)
191
61.6k
    {
192
61.6k
      if (smt->index[i].ifbit > 1)
193
61.6k
        
ccfree33.0k
(smt->vector[i].index)33.0k
; // It is a union of index / data, can just free them.
194
61.6k
    }
195
5.93k
    ccfree(smt->index);
196
5.93k
    ccfree(smt->vector);
197
5.93k
    ccfree(smt);
198
5.93k
  } else 
if (115
(type & CCV_MATRIX_CSR)115
||
(type & CCV_MATRIX_CSC)0
) {
199
1
    ccv_compressed_sparse_matrix_t* csm = (ccv_compressed_sparse_matrix_t*)mat;
200
1
    csm->refcount = 0;
201
1
    ccfree(csm);
202
1
  }
203
9.92M
}
204
205
ccv_array_t* ccv_array_new(int rsize, int rnum, uint64_t sig)
206
2.12M
{
207
2.12M
  ccv_array_t* array;
208
2.12M
  if (ccv_cache_opt && 
sig != 01.93M
)
209
939k
  {
210
939k
    uint8_t type;
211
939k
    array = (ccv_array_t*)ccv_cache_out(&ccv_cache, sig, &type);
212
939k
    if (array)
213
900k
    {
214
900k
      assert(type == 1);
215
900k
      array->type |= CCV_GARBAGE;
216
900k
      array->refcount = 1;
217
900k
      return array;
218
1.22M
    }
219
939k
  }
220
1.22M
  array = (ccv_array_t*)ccmalloc(sizeof(ccv_array_t));
221
1.22M
  array->sig = sig;
222
1.22M
  array->type = CCV_REUSABLE & ~CCV_GARBAGE;
223
1.22M
  array->rnum = 0;
224
1.22M
  array->rsize = rsize;
225
1.22M
  array->size = ccv_max(rnum, 2 /* allocate memory for at least 2 items */);
226
1.22M
  array->data = ccmalloc((size_t)array->size * (size_t)rsize);
227
1.22M
  return array;
228
1.22M
}
229
230
void ccv_make_array_mutable(ccv_array_t* array)
231
0
{
232
0
  array->sig = 0;
233
0
  array->type &= ~CCV_REUSABLE;
234
0
}
235
236
void ccv_make_array_immutable(ccv_array_t* array)
237
0
{
238
0
  assert(array->sig == 0);
239
0
  array->type &= ~CCV_REUSABLE;
240
0
  /* TODO: trim the array */
241
0
  array->sig = ccv_cache_generate_signature(array->data, array->size * array->rsize, (uint64_t)array->rsize, CCV_EOF_SIGN);
242
0
}
243
244
void ccv_array_free_immediately(ccv_array_t* array)
245
1.03M
{
246
1.03M
  array->refcount = 0;
247
1.03M
  ccfree(array->data);
248
1.03M
  ccfree(array);
249
1.03M
}
250
251
void ccv_array_free(ccv_array_t* array)
252
1.18M
{
253
1.18M
  if (!ccv_cache_opt || 
!(array->type & CCV_REUSABLE)1.00M
||
array->sig == 01.00M
)
254
189k
  {
255
189k
    array->refcount = 0;
256
189k
    ccfree(array->data);
257
189k
    ccfree(array);
258
1.00M
  } else {
259
1.00M
    size_t size = sizeof(ccv_array_t) + array->size * array->rsize;
260
1.00M
    ccv_cache_put(&ccv_cache, array->sig, array, size, 1 /* type 1 */);
261
1.00M
  }
262
1.18M
}
263
264
void ccv_drain_cache(void)
265
0
{
266
0
  if (ccv_cache.rnum > 0)
267
0
    ccv_cache_cleanup(&ccv_cache);
268
0
}
269
270
void ccv_disable_cache(void)
271
3
{
272
3
  ccv_cache_opt = 0;
273
3
  ccv_cache_close(&ccv_cache);
274
3
}
275
276
void ccv_enable_cache(size_t size)
277
3
{
278
3
  ccv_cache_opt = 1;
279
3
  ccv_cache_init(&ccv_cache, size, 2, ccv_matrix_free_immediately, ccv_array_free_immediately);
280
3
}
281
282
void ccv_enable_default_cache(void)
283
0
{
284
0
  ccv_enable_cache(CCV_DEFAULT_CACHE_SIZE);
285
0
}
286
287
static uint8_t key_siphash[16] = "libccvky4siphash";
288
289
uint64_t ccv_cache_generate_signature(const char* msg, int len, uint64_t sig_start, ...)
290
7.76M
{
291
7.76M
  uint64_t sig_out, sig_in[2]; // 1 is in, 0 is out
292
7.76M
  siphash((uint8_t*)&sig_out, (const uint8_t*)msg, len, key_siphash);
293
7.76M
  va_list arguments;
294
7.76M
  va_start(arguments, sig_start);
295
7.76M
  sig_in[0] = sig_out;
296
7.76M
  sig_in[1] = sig_start;
297
7.76M
  while (sig_in[1] != 0)
298
163
  {
299
163
    siphash((uint8_t*)&sig_out, (const uint8_t*)sig_in, sizeof(uint64_t) * 2, key_siphash);
300
163
    sig_in[0] = sig_out;
301
163
    sig_in[1] = va_arg(arguments, uint64_t);
302
163
  }
303
7.76M
  va_end(arguments);
304
7.76M
  return sig_out;
305
7.76M
}