Coverage Report

Created: 2017-11-12 13:27

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