Coverage Report

Created: 2024-08-18 16:21

/home/liu/actions-runner/_work/ccv/ccv/lib/nnc/ccv_cnnp_dataframe.c
Line
Count
Source (jump to first uncovered line)
1
#include "ccv_nnc.h"
2
#include "ccv_nnc_easy.h"
3
#include "ccv_nnc_internal.h"
4
#include "ccv_internal.h"
5
#include "_ccv_cnnp_dataframe.h"
6
#include "3rdparty/khash/khash.h"
7
#ifdef HAVE_GSL
8
#include <gsl/gsl_rng.h>
9
#include <gsl/gsl_randist.h>
10
#else
11
#include "3rdparty/sfmt/SFMT.h"
12
#endif
13
14
typedef struct {
15
  ccv_array_t* columns;
16
  int hook_id;
17
} ccv_cnnp_data_ctx_t;
18
19
KHASH_MAP_INIT_INT64(ctx, ccv_cnnp_data_ctx_t)
20
21
struct ccv_cnnp_dataframe_s {
22
  int row_count;
23
  int column_size;
24
  int* shuffled_idx;
25
#ifdef HAVE_GSL
26
  gsl_rng* rng;
27
#else
28
  sfmt_t sfmt;
29
#endif
30
  khash_t(ctx)* data_ctx; // The stream context based cache for data entity of columns. This helps us to avoid allocations when iterate through data.
31
  ccv_array_t* derived_column_data;
32
  ccv_cnnp_column_data_t column_data[1];
33
};
34
35
typedef struct {
36
  int stream_type;
37
  int column_idx_size;
38
  int* column_idxs;
39
  char* name;
40
  ccv_cnnp_column_data_enum_f data_enum;
41
  ccv_cnnp_column_data_deinit_f data_deinit;
42
  void* context;
43
  ccv_cnnp_column_data_context_deinit_f context_deinit;
44
  ccv_cnnp_column_data_map_f map;
45
} ccv_cnnp_derived_column_data_t;
46
47
ccv_cnnp_dataframe_t* ccv_cnnp_dataframe_new(const ccv_cnnp_column_data_t* const column_data, const int column_size, const int row_count)
48
56
{
49
56
  assert(column_size >= 0);
50
56
  ccv_cnnp_dataframe_t* const dataframe = (ccv_cnnp_dataframe_t*)cccalloc(1, sizeof(ccv_cnnp_dataframe_t) + sizeof(ccv_cnnp_column_data_t) * (column_size - 1));
51
56
  dataframe->row_count = row_count;
52
56
  dataframe->column_size = column_size;
53
56
  dataframe->data_ctx = kh_init(ctx);
54
56
  if (column_size > 0)
55
55
  {
56
55
    memcpy(dataframe->column_data, column_data, sizeof(ccv_cnnp_column_data_t) * column_size);
57
55
    int i;
58
6.53k
    for (i = 0; i < column_size; 
i++6.48k
)
59
6.48k
      dataframe->column_data[i].name = ccv_cnnp_column_copy_name(column_data[i].name);
60
55
  }
61
56
  return dataframe;
62
56
}
63
64
void ccv_cnnp_dataframe_shuffle(ccv_cnnp_dataframe_t* const dataframe)
65
14
{
66
14
  assert(dataframe->row_count);
67
14
  int i;
68
14
  if (!dataframe->shuffled_idx)
69
9
  {
70
9
    dataframe->shuffled_idx = (int*)ccmalloc(sizeof(int) * dataframe->row_count);
71
150k
    for (i = 0; i < dataframe->row_count; 
i++150k
)
72
150k
      dataframe->shuffled_idx[i] = i;
73
9
#ifdef HAVE_GSL
74
9
    assert(!dataframe->rng);
75
9
    gsl_rng_env_setup();
76
9
    dataframe->rng = gsl_rng_alloc(gsl_rng_default);
77
9
    gsl_rng_set(dataframe->rng, (unsigned long int)ccv_nnc_stream_context_genrand_uint32(0));
78
#else
79
    sfmt_init_gen_rand(&dataframe->sfmt, ccv_nnc_stream_context_genrand_uint32(0));
80
#endif
81
9
  }
82
14
#ifdef HAVE_GSL
83
14
  gsl_ran_shuffle(dataframe->rng, dataframe->shuffled_idx, dataframe->row_count, sizeof(int));
84
#else
85
  sfmt_genrand_shuffle(&dataframe->sfmt, dataframe->shuffled_idx, dataframe->row_count, sizeof(int));
86
#endif
87
14
}
88
89
int ccv_cnnp_dataframe_row_count(ccv_cnnp_dataframe_t* const dataframe)
90
23
{
91
23
  return dataframe->row_count;
92
23
}
93
94
int ccv_cnnp_dataframe_add(ccv_cnnp_dataframe_t* const dataframe, ccv_cnnp_column_data_enum_f data_enum, const int stream_type, ccv_cnnp_column_data_deinit_f data_deinit, void* const context, ccv_cnnp_column_data_context_deinit_f context_deinit, const char* name)
95
19
{
96
19
  if (!dataframe->derived_column_data)
97
1
    dataframe->derived_column_data = ccv_array_new(sizeof(ccv_cnnp_derived_column_data_t), 1, 0);
98
19
  ccv_cnnp_derived_column_data_t column_data = {
99
19
    .stream_type = stream_type,
100
19
    .name = ccv_cnnp_column_copy_name(name),
101
19
    .data_enum = data_enum,
102
19
    .data_deinit = data_deinit,
103
19
    .context = context,
104
19
    .context_deinit = context_deinit,
105
19
  };
106
19
  ccv_array_push(dataframe->derived_column_data, &column_data);
107
19
  return dataframe->column_size + dataframe->derived_column_data->rnum - 1;
108
19
}
109
110
int ccv_cnnp_dataframe_map(ccv_cnnp_dataframe_t* const dataframe, ccv_cnnp_column_data_map_f map, const int stream_type, ccv_cnnp_column_data_deinit_f data_deinit, const int* const column_idxs, const int column_idx_size, void* const context, ccv_cnnp_column_data_context_deinit_f context_deinit, const char* name)
111
192
{
112
192
  assert(column_idx_size > 0);
113
192
  if (!dataframe->derived_column_data)
114
43
    dataframe->derived_column_data = ccv_array_new(sizeof(ccv_cnnp_derived_column_data_t), 1, 0);
115
192
  const int column_size = dataframe->column_size + dataframe->derived_column_data->rnum;
116
192
  int i;
117
424
  for (i = 0; i < column_idx_size; 
i++232
)
118
232
    { assert(column_idxs[i] < column_size); }
119
192
  ccv_cnnp_derived_column_data_t column_data = {
120
192
    .stream_type = stream_type,
121
192
    .name = ccv_cnnp_column_copy_name(name),
122
192
    .column_idx_size = column_idx_size,
123
192
    .column_idxs = (int*)ccmalloc(sizeof(int) * column_idx_size),
124
192
    .map = map,
125
192
    .data_deinit = data_deinit,
126
192
    .context = context,
127
192
    .context_deinit = context_deinit,
128
192
  };
129
192
  memcpy(column_data.column_idxs, column_idxs, sizeof(int) * column_idx_size);
130
192
  ccv_array_push(dataframe->derived_column_data, &column_data);
131
192
  return dataframe->column_size + dataframe->derived_column_data->rnum - 1;
132
192
}
133
134
void* ccv_cnnp_dataframe_column_context(const ccv_cnnp_dataframe_t* const dataframe, const int column_idx)
135
2
{
136
2
  assert(column_idx >= 0);
137
2
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? dataframe->derived_column_data->rnum : 
00
);
138
2
  assert(column_idx < column_size);
139
2
  if (column_idx < dataframe->column_size)
140
0
    return dataframe->column_data[column_idx].context;
141
2
  assert(dataframe->derived_column_data);
142
2
  ccv_cnnp_derived_column_data_t* const derived_column_data = (ccv_cnnp_derived_column_data_t*)ccv_array_get(dataframe->derived_column_data, column_idx - dataframe->column_size);
143
2
  return derived_column_data->context;
144
2
}
145
146
const char* ccv_cnnp_dataframe_column_name(ccv_cnnp_dataframe_t* const dataframe, const int column_idx)
147
4
{
148
4
  assert(column_idx >= 0);
149
4
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum1
:
03
);
150
4
  assert(column_idx < column_size);
151
4
  if (column_idx < dataframe->column_size)
152
3
    return dataframe->column_data[column_idx].name;
153
1
  ccv_cnnp_derived_column_data_t* const derived_column_data = (ccv_cnnp_derived_column_data_t*)ccv_array_get(dataframe->derived_column_data, column_idx - dataframe->column_size);
154
1
  return derived_column_data->name;
155
4
}
156
157
typedef struct {
158
  int flag; // Mark this as cached or not.
159
  int64_t ctx; // The stream context.
160
  void* data;
161
} ccv_cnnp_dataframe_data_item_t;
162
163
typedef struct {
164
  ccv_nnc_stream_context_t* stream_context;
165
} ccv_cnnp_dataframe_column_ctx_t;
166
167
KHASH_MAP_INIT_INT64(iter_ctx, ccv_cnnp_dataframe_column_ctx_t*)
168
169
struct ccv_cnnp_dataframe_iter_s {
170
  int flag; // Whether we called next or not.
171
  int idx;
172
  int prefetch_head;
173
  int prefetch_tail;
174
  int column_size;
175
  int column_idx_size;
176
  int fetched_size; // The size of fetched data.
177
  ccv_cnnp_dataframe_t* dataframe;
178
  void**** derived_data; // This is ridiculous, but it is true.
179
  void** fetched_data; // The cache to store fetched data.
180
  khash_t(iter_ctx)* column_ctx; // Column context specific to a stream context. The key will be a parent stream context and value will be child stream context + signal.
181
  ccv_array_t* prefetches; // The prefetch contents.
182
  int* column_idxs;
183
  ccv_cnnp_dataframe_data_item_t cached_data[1]; // The data cached when deriving data.
184
};
185
186
82.0k
#define INDEX_DATA(iter) ((int*)((iter)->fetched_data))
187
5.12k
#define FETCHED_DATA(iter, idx) ((iter)->fetched_data + ((idx) + 1) * (iter)->fetched_size)
188
189
ccv_cnnp_dataframe_iter_t* ccv_cnnp_dataframe_iter_new(ccv_cnnp_dataframe_t* const dataframe, const int* const column_idxs, const int column_idx_size)
190
61
{
191
61
  assert(column_idx_size > 0);
192
61
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum47
:
014
);
193
61
  int i;
194
196
  for (i = 0; i < column_idx_size; 
i++135
)
195
135
    { assert(column_idxs[i] < column_size); }
196
61
  ccv_cnnp_dataframe_iter_t* const iter = (ccv_cnnp_dataframe_iter_t*)cccalloc(1, sizeof(ccv_cnnp_dataframe_iter_t) + sizeof(ccv_cnnp_dataframe_data_item_t) * column_size + sizeof(void*) * (column_idx_size - 1) + sizeof(int) * column_idx_size);
197
61
  iter->dataframe = dataframe;
198
61
  iter->prefetch_tail = -1;
199
  // After created the iterator, we may continue add more derived columns.
200
  // Hence, keep the number of existing columns for its cached_data and column_ctx tracking.
201
61
  iter->column_size = column_size;
202
61
  iter->column_idx_size = column_idx_size;
203
61
  iter->column_idxs = (int*)(iter->cached_data + column_size);
204
61
  memcpy(iter->column_idxs, column_idxs, sizeof(int) * column_idx_size);
205
  // Preallocate fetched data.
206
61
  iter->fetched_size = 1;
207
61
  iter->fetched_data = (void**)ccmalloc(sizeof(void*) * (column_size + 1));
208
61
  return iter;
209
61
}
210
211
static void _ccv_cnnp_dataframe_data_ctx_columns_free(ccv_cnnp_dataframe_t* const dataframe, ccv_array_t* const columns)
212
62
{
213
62
  int i, j;
214
6.75k
  for (i = 0; i < columns->rnum; 
i++6.69k
)
215
6.69k
  {
216
6.69k
    ccv_array_t* const column = *(ccv_array_t**)ccv_array_get(columns, i);
217
6.69k
    if (!column)
218
6.42k
      continue;
219
269
    void* context;
220
269
    ccv_cnnp_column_data_deinit_f data_deinit;
221
269
    if (i < dataframe->column_size)
222
60
    {
223
60
      data_deinit = dataframe->column_data[i].data_deinit;
224
60
      context = dataframe->column_data[i].context;
225
209
    } else {
226
209
      assert(dataframe->derived_column_data);
227
209
      ccv_cnnp_derived_column_data_t* const derived_column_data = (ccv_cnnp_derived_column_data_t*)ccv_array_get(dataframe->derived_column_data, i - dataframe->column_size);
228
209
      data_deinit = derived_column_data->data_deinit;
229
209
      context = derived_column_data->context;
230
209
    }
231
269
    if (data_deinit)
232
25.4k
      
for (j = 0; 169
j < column->rnum;
j++25.2k
)
233
25.2k
        data_deinit(*(void**)ccv_array_get(column, j), context);
234
269
    ccv_array_free(column);
235
269
  }
236
62
  ccv_array_free(columns);
237
62
}
238
239
static void _ccv_cnnp_dataframe_stream_destructor_hook(const ccv_nnc_stream_context_t* const stream, void* const context)
240
4
{
241
4
  ccv_cnnp_dataframe_t* const dataframe = (ccv_cnnp_dataframe_t*)context;
242
4
  khash_t(ctx)* const data_ctx = dataframe->data_ctx;
243
4
  int64_t ctx = (int64_t)(intptr_t)stream;
244
4
  khiter_t k = kh_get(ctx, data_ctx, ctx);
245
4
  assert(k != kh_end(data_ctx));
246
4
  ccv_array_t* const columns = kh_val(data_ctx, k).columns;
247
4
  _ccv_cnnp_dataframe_data_ctx_columns_free(dataframe, columns);
248
4
  kh_del(ctx, data_ctx, k);
249
4
}
250
251
static void _ccv_cnnp_dataframe_prepare_data_ctx(ccv_cnnp_dataframe_t* const dataframe, ccv_nnc_stream_context_t* const stream_context)
252
182k
{
253
182k
  khash_t(ctx)* const data_ctx = dataframe->data_ctx;
254
182k
  int ret = 0;
255
182k
  int64_t ctx = (int64_t)(intptr_t)stream_context;
256
182k
  khiter_t k = kh_put(ctx, data_ctx, ctx, &ret);
257
182k
  assert(ret >= 0);
258
182k
  if (ret != 0)
259
62
  {
260
62
    const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum50
:
012
);
261
62
    kh_val(data_ctx, k).columns = ccv_array_new(sizeof(ccv_array_t*), column_size, 0);
262
62
    kh_val(data_ctx, k).hook_id = stream_context ? 
ccv_nnc_stream_context_add_destructor_hook(stream_context, _ccv_cnnp_dataframe_stream_destructor_hook, dataframe)16
:
-146
;
263
62
  }
264
182k
}
265
266
static void _ccv_cnnp_dataframe_enqueue_data(ccv_cnnp_dataframe_t* const dataframe, void* const data, const int column_idx, const uint64_t ctx)
267
1.20M
{
268
1.20M
  if (!data)
269
4
    return;
270
1.20M
  khash_t(ctx)* const data_ctx = dataframe->data_ctx;
271
1.20M
  khiter_t k = kh_get(ctx, data_ctx, ctx);
272
1.20M
  if (k == kh_end(data_ctx))
273
40
  {
274
    // Free the data directly.
275
40
    void* context;
276
40
    ccv_cnnp_column_data_deinit_f data_deinit;
277
40
    if (column_idx < dataframe->column_size)
278
2
    {
279
2
      data_deinit = dataframe->column_data[column_idx].data_deinit;
280
2
      context = dataframe->column_data[column_idx].context;
281
38
    } else {
282
38
      assert(dataframe->derived_column_data);
283
38
      ccv_cnnp_derived_column_data_t* const derived_column_data = (ccv_cnnp_derived_column_data_t*)ccv_array_get(dataframe->derived_column_data, column_idx - dataframe->column_size);
284
38
      data_deinit = derived_column_data->data_deinit;
285
38
      context = derived_column_data->context;
286
38
    }
287
40
    if (data_deinit)
288
28
      data_deinit(data, context);
289
40
    return;
290
40
  }
291
1.20M
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum1.20M
:
0113
);
292
1.20M
  assert(column_idx < column_size);
293
  // If ret == 0, the key already exist, we can get the columns directly, otherwise, create and assign back.
294
1.20M
  ccv_array_t* const columns = kh_val(data_ctx, k).columns;
295
1.20M
  if (columns->rnum < column_size)
296
60
    ccv_array_resize(columns, column_size);
297
1.20M
  ccv_array_t* column = *(ccv_array_t**)ccv_array_get(columns, column_idx);
298
1.20M
  if (!column)
299
269
  {
300
269
    column = ccv_array_new(sizeof(void*), 1, 0);
301
269
    *(ccv_array_t**)ccv_array_get(columns, column_idx) = column;
302
269
  }
303
1.20M
  ccv_array_push(column, &data);
304
1.20M
}
305
306
static void* _ccv_cnnp_dataframe_dequeue_data(ccv_cnnp_dataframe_t* const dataframe, const int column_idx, ccv_nnc_stream_context_t* const stream_context)
307
1.20M
{
308
1.20M
  const uint64_t ctx = (uint64_t)(uintptr_t)stream_context;
309
1.20M
  khash_t(ctx)* const data_ctx = dataframe->data_ctx;
310
1.20M
  khiter_t k = kh_get(ctx, data_ctx, ctx);
311
1.20M
  if (k == kh_end(data_ctx))
312
0
    return 0;
313
1.20M
  ccv_array_t* const columns = kh_val(data_ctx, k).columns;
314
1.20M
  if (column_idx >= columns->rnum)
315
44.9k
    return 0;
316
1.16M
  ccv_array_t* const column = *(ccv_array_t**)ccv_array_get(columns, column_idx);
317
1.16M
  if (!column || column->rnum == 0)
318
67
    return 0;
319
1.16M
  void* const data = *(void**)ccv_array_get(column, column->rnum - 1);
320
1.16M
  --column->rnum;
321
1.16M
  return data;
322
1.16M
}
323
324
static ccv_cnnp_dataframe_column_ctx_t _ccv_cnnp_child_column_ctx_for_stream_type(ccv_cnnp_dataframe_t* const dataframe, ccv_cnnp_dataframe_iter_t* const iter, const int column_idx, ccv_nnc_stream_context_t* const stream_context, const int stream_type)
325
4.81k
{
326
4.81k
  ccv_cnnp_dataframe_column_ctx_t child_ctx = {
327
4.81k
    .stream_context = stream_context,
328
4.81k
  };
329
4.81k
  if (stream_context && 
ccv_nnc_stream_context_type(stream_context) != stream_type3.72k
&&
stream_type != 03.13k
)
330
603
  {
331
603
    if (!iter->column_ctx)
332
4
      iter->column_ctx = kh_init(iter_ctx);
333
603
    khash_t(iter_ctx)* const column_ctx = iter->column_ctx;
334
603
    int ret = 0;
335
603
    khiter_t k = kh_put(iter_ctx, column_ctx, (uint64_t)(uintptr_t)stream_context, &ret);
336
603
    assert(ret >= 0);
337
603
    const int column_size = iter->column_size;
338
603
    ccv_cnnp_dataframe_column_ctx_t* const ctx = (ret == 0) ? 
kh_val597
(column_ctx, k) :
cccalloc6
(column_size, sizeof(ccv_cnnp_dataframe_column_ctx_t))6
;
339
603
    if (ret != 0)
340
6
      kh_val(column_ctx, k) = ctx;
341
603
    assert(column_idx < column_size);
342
603
    if (!ctx[column_idx].stream_context)
343
39
      ctx[column_idx].stream_context = ccv_nnc_stream_context_new(stream_type);
344
603
    child_ctx = ctx[column_idx];
345
603
  }
346
4.81k
  return child_ctx;
347
4.81k
}
348
349
static void _ccv_cnnp_dataframe_column_data(ccv_cnnp_dataframe_t* const dataframe, ccv_cnnp_dataframe_iter_t* const iter, ccv_cnnp_dataframe_data_item_t* const cached_data, void** const fetched_data, const int* const row_idxs, const int row_size, const int column_idx, const int cached_step, ccv_nnc_stream_context_t* const stream_context)
350
187k
{
351
187k
  int i;
352
187k
  if (cached_data[column_idx * cached_step].flag)
353
182k
  {
354
334k
    for (i = 1; i < row_size; 
i++151k
)
355
151k
      { assert(cached_data[i + column_idx * cached_step].flag); }
356
516k
    
for (i = 0; 182k
i < row_size;
i++334k
)
357
334k
      fetched_data[i] = cached_data[i + column_idx * cached_step].data;
358
182k
    return;
359
182k
  } else {
360
1.20M
    for (i = 1; i < row_size; 
i++1.20M
)
361
1.20M
      { assert(!cached_data[i + column_idx * cached_step].flag); }
362
1.21M
    
for (i = 0; 4.81k
i < row_size;
i++1.20M
)
363
1.20M
      fetched_data[i] = _ccv_cnnp_dataframe_dequeue_data(dataframe, column_idx, stream_context);
364
4.81k
  }
365
4.81k
  if (column_idx >= dataframe->column_size)
366
3.88k
  {
367
3.88k
    assert(dataframe->derived_column_data);
368
3.88k
    const int derived_column_idx = column_idx - dataframe->column_size;
369
3.88k
    const ccv_cnnp_derived_column_data_t* const derived_column_data = (ccv_cnnp_derived_column_data_t*)ccv_array_get(dataframe->derived_column_data, derived_column_idx);
370
3.88k
    ccv_cnnp_dataframe_column_ctx_t child_ctx = _ccv_cnnp_child_column_ctx_for_stream_type(dataframe, iter, column_idx, stream_context, derived_column_data->stream_type);
371
3.88k
    const int column_idx_size = derived_column_data->column_idx_size;
372
3.88k
    if (derived_column_data->map)
373
3.16k
    {
374
3.16k
      int i;
375
3.16k
      if (!iter->derived_data)
376
45
        iter->derived_data = (void****)cccalloc(dataframe->derived_column_data->rnum, sizeof(void***));
377
3.16k
      if (!iter->derived_data[derived_column_idx])
378
194
        iter->derived_data[derived_column_idx] = (void***)cccalloc(derived_column_data->column_idx_size, sizeof(void**));
379
3.16k
      void*** const derived_data = iter->derived_data[derived_column_idx];
380
6.68k
      for (i = 0; i < column_idx_size; 
i++3.51k
)
381
3.51k
      {
382
3.51k
        derived_data[i] = FETCHED_DATA(iter, derived_column_data->column_idxs[i]);
383
3.51k
        _ccv_cnnp_dataframe_column_data(dataframe, iter, cached_data, derived_data[i], row_idxs, row_size, derived_column_data->column_idxs[i], cached_step, stream_context);
384
3.51k
      }
385
      // Mark it as const.
386
3.16k
      derived_column_data->map((void *const *const *)derived_data, derived_column_data->column_idx_size, row_size, fetched_data, derived_column_data->context, child_ctx.stream_context);
387
3.16k
    } else
388
721
      derived_column_data->data_enum(column_idx, row_idxs, row_size, fetched_data, derived_column_data->context, child_ctx.stream_context);
389
3.88k
    if (child_ctx.stream_context != stream_context)
390
603
    {
391
603
      ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(child_ctx.stream_context);
392
603
      ccv_nnc_stream_context_wait_signal(stream_context, signal);
393
603
    }
394
3.88k
  } else {
395
924
    const ccv_cnnp_column_data_t* const column_data = dataframe->column_data + column_idx;
396
924
    ccv_cnnp_dataframe_column_ctx_t child_ctx = _ccv_cnnp_child_column_ctx_for_stream_type(dataframe, iter, column_idx, stream_context, column_data->stream_type);
397
924
    column_data->data_enum(column_idx, row_idxs, row_size, fetched_data, column_data->context, child_ctx.stream_context);
398
924
    if (child_ctx.stream_context != stream_context)
399
0
    {
400
0
      ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(child_ctx.stream_context);
401
0
      ccv_nnc_stream_context_wait_signal(stream_context, signal);
402
0
    }
403
924
  }
404
1.21M
  
for (i = 0; 4.81k
i < row_size;
i++1.20M
)
405
1.20M
  {
406
1.20M
    cached_data[i + column_idx * cached_step].flag = 1;
407
1.20M
    cached_data[i + column_idx * cached_step].ctx = (uint64_t)(uintptr_t)stream_context;
408
1.20M
    cached_data[i + column_idx * cached_step].data = fetched_data[i];
409
1.20M
  }
410
4.81k
}
411
412
int ccv_cnnp_dataframe_iter_next(ccv_cnnp_dataframe_iter_t* const iter, void** const data_ref, const int column_idx_size, ccv_nnc_stream_context_t* const stream_context)
413
181k
{
414
181k
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
415
181k
  assert(column_idx_size <= iter->column_idx_size);
416
181k
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum181k
:
0120
);
417
181k
  int i;
418
  // Push existing data back to reusable state (note, these may not be reused immediately because they may be on a different stream context).
419
1.54M
  for (i = 0; i < column_size; 
i++1.36M
)
420
1.36M
    if (iter->cached_data[i].flag)
421
1.20M
    {
422
1.20M
      _ccv_cnnp_dataframe_enqueue_data(dataframe, iter->cached_data[i].data, i, iter->cached_data[i].ctx);
423
1.20M
      iter->cached_data[i].flag = 0;
424
1.20M
      iter->cached_data[i].data = 0;
425
1.20M
      iter->cached_data[i].ctx = 0;
426
1.20M
    }
427
181k
  const int idx = iter->idx;
428
181k
  iter->flag = 1; // Mark it as we called next already.
429
181k
  if (idx > dataframe->row_count) // If we exceed row count, return -2.
430
0
    return -2;
431
181k
  if (idx == dataframe->row_count) // Otherwise, no more row, return -1.
432
26
  {
433
26
    ++iter->idx;
434
26
    return -1;
435
26
  }
436
181k
  if (iter->prefetch_tail != -1) // If there is something in prefetch log.
437
181k
  {
438
181k
    ccv_array_t* const prefetches = iter->prefetches;
439
181k
    assert(prefetches);
440
181k
    const int lines = prefetches->rnum / column_size;
441
181k
    if (iter->prefetch_head == iter->prefetch_tail) // Only one item.
442
683
      iter->prefetch_tail = -1;
443
181k
    ccv_cnnp_dataframe_data_item_t* const cached_data = (ccv_cnnp_dataframe_data_item_t*)ccv_array_get(iter->prefetches, iter->prefetch_head);
444
1.41M
    for (i = 0; i < column_size; 
i++1.23M
)
445
1.23M
    {
446
1.23M
      if (!cached_data[i * lines].flag)
447
32.1k
        continue;
448
1.20M
      if (cached_data[i * lines].ctx == (uint64_t)(uintptr_t)stream_context) // If match existing stream context.
449
1.20M
        iter->cached_data[i] = cached_data[i * lines];
450
0
      else // Recycle
451
0
        _ccv_cnnp_dataframe_enqueue_data(dataframe, cached_data[i * lines].data, i, cached_data[i * lines].ctx);
452
1.20M
    }
453
181k
    ++iter->prefetch_head;
454
181k
    assert(prefetches->rnum % column_size == 0);
455
181k
    if (iter->prefetch_head >= lines)
456
670
      iter->prefetch_head = 0;
457
181k
  }
458
  // Now we are about to create cached_data (above code only uses cached data).
459
  // We are ready to prepare the data_ctx cache.
460
181k
  _ccv_cnnp_dataframe_prepare_data_ctx(dataframe, stream_context);
461
363k
  for (i = 0; i < column_idx_size; 
i++182k
)
462
182k
  {
463
182k
    void* fetched_data[1]; // This guards better than just give away data_ref + i.
464
182k
    _ccv_cnnp_dataframe_column_data(dataframe, iter, iter->cached_data, fetched_data, dataframe->shuffled_idx ? 
dataframe->shuffled_idx + idx100k
:
&idx81.9k
, 1, iter->column_idxs[i], 1, stream_context);
465
182k
    data_ref[i] = fetched_data[0];
466
182k
  }
467
181k
  ++iter->idx;
468
181k
  return 0;
469
181k
}
470
471
void ccv_cnnp_dataframe_iter_peek(ccv_cnnp_dataframe_iter_t* const iter, void** const data_ref, const int offset, const int data_ref_size, ccv_nnc_stream_context_t* const stream_context)
472
19
{
473
19
  assert(iter->flag);
474
19
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
475
19
  assert(offset + data_ref_size <= iter->column_idx_size);
476
19
  const int idx = iter->idx - 1; // next is called, therefore, index is already incremented.
477
19
  assert(idx >= 0);
478
19
  assert(idx < dataframe->row_count);
479
19
  int i;
480
51
  for (i = 0; i < data_ref_size; 
i++32
)
481
32
    _ccv_cnnp_dataframe_column_data(dataframe, iter, iter->cached_data, data_ref + i, dataframe->shuffled_idx ? 
dataframe->shuffled_idx + idx0
: &idx, 1, iter->column_idxs[i + offset], 1, stream_context);
482
19
}
483
484
static void _ccv_cnnp_null_prefetches(ccv_cnnp_dataframe_iter_t* const iter)
485
71
{
486
71
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
487
71
  assert(dataframe);
488
71
  int i, j;
489
71
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum54
:
017
);
490
71
  if (iter->prefetch_head <= iter->prefetch_tail)
491
2
  {
492
2
    assert(iter->prefetches);
493
2
    const int lines = iter->prefetches->rnum / column_size;
494
6
    for (i = iter->prefetch_head; i <= iter->prefetch_tail; 
i++4
)
495
4
    {
496
4
      ccv_cnnp_dataframe_data_item_t* const cached_data = ccv_array_get(iter->prefetches, i);
497
10
      for (j = 0; j < column_size; 
j++6
)
498
6
        if (cached_data[j * lines].flag)
499
6
          _ccv_cnnp_dataframe_enqueue_data(dataframe, cached_data[j * lines].data, j, cached_data[j * lines].ctx);
500
4
    }
501
69
  } else if (iter->prefetch_tail >= 0) { // -1 means no item.
502
1
    assert(iter->prefetches);
503
1
    const int lines = iter->prefetches->rnum / column_size;
504
2
    for (i = iter->prefetch_head; i < lines; 
i++1
)
505
1
    {
506
1
      ccv_cnnp_dataframe_data_item_t* const cached_data = ccv_array_get(iter->prefetches, i);
507
3
      for (j = 0; j < column_size; 
j++2
)
508
2
        if (cached_data[j * lines].flag)
509
2
          _ccv_cnnp_dataframe_enqueue_data(dataframe, cached_data[j * lines].data, j, cached_data[j * lines].ctx);
510
1
    }
511
5
    for (i = 0; i <= iter->prefetch_tail; 
i++4
)
512
4
    {
513
4
      ccv_cnnp_dataframe_data_item_t* const cached_data = ccv_array_get(iter->prefetches, i);
514
12
      for (j = 0; j < column_size; 
j++8
)
515
8
        if (cached_data[j * lines].flag)
516
8
          _ccv_cnnp_dataframe_enqueue_data(dataframe, cached_data[j * lines].data, j, cached_data[j * lines].ctx);
517
4
    }
518
1
  }
519
71
  iter->prefetch_head = 0;
520
71
  iter->prefetch_tail = -1;
521
71
}
522
523
static void _ccv_cnnp_prefetch_cached_data(ccv_cnnp_dataframe_iter_t* const iter, ccv_cnnp_dataframe_data_item_t* const cached_data, const int idx, const int max_to_prefetch, ccv_nnc_stream_context_t* const stream_context)
524
719
{
525
719
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
526
719
  assert(dataframe);
527
719
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum698
:
021
);
528
719
  assert(iter->prefetches);
529
719
  const int lines = iter->prefetches->rnum / column_size;
530
719
  int i, j;
531
  // Reset
532
8.07k
  for (i = 0; i < column_size; 
i++7.35k
)
533
1.24M
    
for (j = 0; 7.35k
j < max_to_prefetch;
j++1.23M
)
534
1.23M
    {
535
1.23M
      cached_data[j + i * lines].flag = 0;
536
1.23M
      cached_data[j + i * lines].data = 0;
537
1.23M
      cached_data[j + i * lines].ctx = 0;
538
1.23M
    }
539
719
  if (iter->fetched_size < max_to_prefetch)
540
22
  {
541
22
    iter->fetched_data = ccrealloc(iter->fetched_data, sizeof(void*) * max_to_prefetch * (column_size + 1));
542
22
    iter->fetched_size = max_to_prefetch;
543
22
  }
544
719
  if (dataframe->shuffled_idx)
545
510
    
for (i = 0; 255
i < iter->column_idx_size;
i++255
)
546
255
      _ccv_cnnp_dataframe_column_data(dataframe, iter, cached_data, FETCHED_DATA(iter, iter->column_idxs[i]), dataframe->shuffled_idx + idx, max_to_prefetch, iter->column_idxs[i], lines, stream_context);
547
464
  else {
548
81.1k
    for (i = 0; i < max_to_prefetch; 
i++80.6k
)
549
80.6k
      INDEX_DATA(iter)[i] = idx + i;
550
1.81k
    for (i = 0; i < iter->column_idx_size; 
i++1.34k
)
551
1.34k
      _ccv_cnnp_dataframe_column_data(dataframe, iter, cached_data, FETCHED_DATA(iter, iter->column_idxs[i]), INDEX_DATA(iter), max_to_prefetch, iter->column_idxs[i], lines, stream_context);
552
464
  }
553
719
}
554
555
int ccv_cnnp_dataframe_iter_prefetch(ccv_cnnp_dataframe_iter_t* const iter, const int prefetch_count, ccv_nnc_stream_context_t* const stream_context)
556
725
{
557
725
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
558
725
  assert(dataframe);
559
725
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum703
:
022
);
560
725
  int i, j;
561
725
  assert(iter->idx <= dataframe->row_count);
562
725
  int lines, next, max_to_prefetch;
563
725
  if (iter->prefetch_tail == -1)
564
692
  {
565
692
    if (iter->idx == dataframe->row_count)
566
6
      return -1; // Cannot be done.
567
686
    max_to_prefetch = ccv_min(dataframe->row_count - iter->idx, prefetch_count);
568
686
    if (!iter->prefetches)
569
30
    {
570
30
      iter->prefetches = ccv_array_new(sizeof(ccv_cnnp_dataframe_data_item_t), max_to_prefetch * column_size, 0);
571
30
      ccv_array_resize(iter->prefetches, max_to_prefetch * column_size);
572
30
    }
573
686
    iter->prefetch_tail = iter->prefetch_head = 0; // Advance!
574
686
    next = iter->idx;
575
686
    lines = iter->prefetches->rnum / column_size;
576
    // Reset to enough space.
577
686
    if (lines < max_to_prefetch)
578
1
    {
579
1
      ccv_array_resize(iter->prefetches, max_to_prefetch * column_size);
580
1
      lines = max_to_prefetch;
581
1
    }
582
686
  } else {
583
33
    assert(iter->prefetches);
584
33
    ccv_array_t* const prefetches = iter->prefetches;
585
33
    assert(prefetches->rnum % column_size == 0);
586
33
    lines = prefetches->rnum / column_size;
587
33
    const int prefetched = iter->prefetch_tail >= iter->prefetch_head ? 
iter->prefetch_tail - iter->prefetch_head + 122
:
lines - iter->prefetch_head + iter->prefetch_tail + 111
;
588
33
    if (iter->idx + prefetched == dataframe->row_count) // Nothing to prefetch.
589
2
      return -1;
590
31
    max_to_prefetch = ccv_min(dataframe->row_count - (iter->idx + prefetched), prefetch_count);
591
    // Not enough space, need to resize.
592
31
    if (prefetched + max_to_prefetch > lines)
593
20
    {
594
20
      const int new_lines = prefetched + max_to_prefetch;
595
20
      ccv_array_resize(prefetches, new_lines * column_size);
596
      // These are overlap moves, have to make sure start from the end and move it up to the beginning.
597
20
      if (iter->prefetch_head > iter->prefetch_tail)
598
7
      {
599
7
        const int offset = new_lines - lines;
600
19
        for (i = column_size - 1; i >= 0; 
i--12
)
601
12
        {
602
24
          for (j = lines - 1; j >= iter->prefetch_head; 
j--12
)
603
12
            *(ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, j + offset + i * new_lines) = *(ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, j + i * lines);
604
41
          for (j = iter->prefetch_tail; j >= 0; 
j--29
)
605
29
            *(ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, j + i * new_lines) = *(ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, j + i * lines);
606
12
        }
607
7
        iter->prefetch_head += offset;
608
13
      } else {
609
33
        for (i = column_size - 1; i >= 0; 
i--20
)
610
49
          
for (j = iter->prefetch_tail; 20
j >= iter->prefetch_head;
j--29
)
611
29
            *(ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, j + i * new_lines) = *(ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, j + i * lines);
612
13
      }
613
20
      lines = new_lines;
614
20
    }
615
31
    ++iter->prefetch_tail; // Move to the next ready tail.
616
31
    if (iter->prefetch_tail >= lines)
617
4
      iter->prefetch_tail = 0;
618
31
    next = iter->idx + prefetched;
619
31
  }
620
717
  ccv_array_t* const prefetches = iter->prefetches;
621
717
  ccv_cnnp_dataframe_data_item_t* const cached_data = (ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, iter->prefetch_tail);
622
  // Now we are about to create cached_data (above code only uses cached data).
623
  // We are ready to prepare the data_ctx cache.
624
717
  _ccv_cnnp_dataframe_prepare_data_ctx(dataframe, stream_context);
625
  // If the tail is before the head, we must have enough space for the max_to_prefetch
626
717
  if (iter->prefetch_tail < iter->prefetch_head)
627
15
  {
628
15
    assert(iter->prefetch_tail + max_to_prefetch - 1 < iter->prefetch_head);
629
15
    _ccv_cnnp_prefetch_cached_data(iter, cached_data, next, max_to_prefetch, stream_context);
630
15
    iter->prefetch_tail += max_to_prefetch - 1;
631
702
  } else {
632
    // First, fetch to the end.
633
702
    const int fetch_to_end = ccv_min(max_to_prefetch, lines - iter->prefetch_tail);
634
702
    _ccv_cnnp_prefetch_cached_data(iter, cached_data, next, fetch_to_end, stream_context);
635
702
    if (fetch_to_end == max_to_prefetch)
636
700
      iter->prefetch_tail += fetch_to_end - 1;
637
2
    else {
638
      // Need to fetch more.
639
2
      ccv_cnnp_dataframe_data_item_t* const more_data = (ccv_cnnp_dataframe_data_item_t*)ccv_array_get(prefetches, 0);
640
2
      assert(max_to_prefetch > fetch_to_end);
641
2
      _ccv_cnnp_prefetch_cached_data(iter, more_data, next + fetch_to_end, max_to_prefetch - fetch_to_end, stream_context);
642
2
      iter->prefetch_tail = max_to_prefetch - fetch_to_end - 1;
643
2
    }
644
702
  }
645
717
  return 0;
646
717
}
647
648
int ccv_cnnp_dataframe_iter_set_cursor(ccv_cnnp_dataframe_iter_t* const iter, const int idx)
649
13
{
650
13
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
651
13
  assert(dataframe);
652
13
  if (idx >= dataframe->row_count)
653
0
    return -1;
654
13
  if (idx == iter->idx)
655
3
    return 0;
656
10
  iter->idx = idx;
657
10
  iter->flag = 0;
658
10
  _ccv_cnnp_null_prefetches(iter);
659
10
  return 0;
660
13
}
661
662
void ccv_cnnp_dataframe_iter_free(ccv_cnnp_dataframe_iter_t* const iter)
663
61
{
664
61
  ccv_cnnp_dataframe_t* const dataframe = iter->dataframe;
665
61
  const int column_size = iter->column_size;
666
61
  int i;
667
  // Push existing data back to reusable state (note, these may not be reused immediately because they may be on a different stream context).
668
6.76k
  for (i = 0; i < column_size; 
i++6.70k
)
669
6.70k
    if (iter->cached_data[i].flag)
670
190
      _ccv_cnnp_dataframe_enqueue_data(dataframe, iter->cached_data[i].data, i, iter->cached_data[i].ctx);
671
  // Push prefetches back to reusable state.
672
61
  _ccv_cnnp_null_prefetches(iter);
673
61
  if (iter->prefetches)
674
30
    ccv_array_free(iter->prefetches);
675
61
  if (iter->derived_data)
676
45
  {
677
45
    assert(dataframe->derived_column_data);
678
257
    
for (i = 0; 45
i < dataframe->derived_column_data->rnum;
i++212
)
679
212
      if (iter->derived_data[i])
680
194
        ccfree(iter->derived_data[i]);
681
45
    ccfree(iter->derived_data);
682
45
  }
683
61
  ccfree(iter->fetched_data);
684
61
  if (iter->column_ctx)
685
4
  {
686
4
    khash_t(iter_ctx)* const column_ctx = iter->column_ctx;
687
4
    khiter_t k;
688
20
    for (k = 
kh_begin4
(column_ctx); k != kh_end(column_ctx);
++k16
)
689
16
    {
690
16
      if (!kh_exist(column_ctx, k))
691
10
        continue;
692
6
      ccv_cnnp_dataframe_column_ctx_t* const ctx = kh_val(column_ctx, k);
693
82
      for (i = 0; i < column_size; 
i++76
)
694
76
      {
695
76
        if (ctx[i].stream_context)
696
39
          ccv_nnc_stream_context_free(ctx[i].stream_context);
697
76
      }
698
6
    }
699
4
    kh_destroy(iter_ctx, column_ctx);
700
4
  }
701
61
  ccfree(iter);
702
61
}
703
704
void ccv_cnnp_dataframe_free(ccv_cnnp_dataframe_t* const dataframe)
705
56
{
706
56
  int i;
707
56
  khash_t(ctx)* const data_ctx = dataframe->data_ctx;
708
56
  khiter_t k;
709
56
  const int column_size = dataframe->column_size + (dataframe->derived_column_data ? 
dataframe->derived_column_data->rnum44
:
012
);
710
280
  for (k = 
kh_begin56
(data_ctx); k != kh_end(data_ctx);
++k224
)
711
224
  {
712
224
    if (!kh_exist(data_ctx, k))
713
166
      continue;
714
58
    ccv_nnc_stream_context_t* const stream_context = (ccv_nnc_stream_context_t*)(intptr_t)kh_key(data_ctx, k);
715
58
    ccv_array_t* const columns = kh_val(data_ctx, k).columns;
716
58
    if (stream_context)
717
12
    {
718
12
      const int hook_id = kh_val(data_ctx, k).hook_id;
719
12
      ccv_nnc_stream_context_remove_destructor_hook(stream_context, hook_id);
720
12
    }
721
58
    assert(columns->rnum <= column_size);
722
58
    _ccv_cnnp_dataframe_data_ctx_columns_free(dataframe, columns);
723
58
  }
724
56
  kh_destroy(ctx, data_ctx);
725
56
  if (dataframe->derived_column_data)
726
44
  {
727
255
    for (i = 0; i < dataframe->derived_column_data->rnum; 
i++211
)
728
211
    {
729
211
      ccv_cnnp_derived_column_data_t* const derived_column_data = (ccv_cnnp_derived_column_data_t*)ccv_array_get(dataframe->derived_column_data, i);
730
211
      if (derived_column_data->context_deinit)
731
142
        derived_column_data->context_deinit(derived_column_data->context);
732
211
      ccfree(derived_column_data->column_idxs);
733
211
      if (derived_column_data->name)
734
1
        ccfree(derived_column_data->name);
735
211
    }
736
44
    ccv_array_free(dataframe->derived_column_data);
737
44
  }
738
6.54k
  for (i = 0; i < dataframe->column_size; 
i++6.48k
)
739
6.48k
  {
740
6.48k
    if (dataframe->column_data[i].context_deinit)
741
22
      dataframe->column_data[i].context_deinit(dataframe->column_data[i].context);
742
6.48k
    if (dataframe->column_data[i].name)
743
3.21k
      ccfree(dataframe->column_data[i].name);
744
6.48k
  }
745
56
  if (dataframe->shuffled_idx)
746
9
    ccfree(dataframe->shuffled_idx);
747
56
#ifdef HAVE_GSL
748
56
  if (dataframe->rng)
749
9
    gsl_rng_free(dataframe->rng);
750
56
#endif
751
56
  ccfree(dataframe);
752
56
}