## Coverage Report

#### Created: 2026-04-18 18:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/liu/actions-runner/_work/ccv/ccv/lib/nnc/_ccv_nnc_symbolic_graph.h

    Line
    Count
    Source
    1
    /**********************************************************
    2
     * C-based/Cached/Core Computer Vision Library
    3
     * Liu Liu, 2010-02-01
    4
     **********************************************************/
    5
    6
    /**********************************************************
    7
     * CCV - Neural Network Collection
    8
     **********************************************************/
    9
    10
    #ifndef GUARD_ccv_nnc_symbolic_graph_internal_h
    11
    #define GUARD_ccv_nnc_symbolic_graph_internal_h
    12
    13
    #include "ccv_nnc.h"
    14
    #include "ccv_nnc_internal.h"
    15
    16
    typedef struct {
    17
      // Start for while loop handling
    18
      int assign_ref; // Reference to the tensor that the value will be copied from (for parameter passing). Starts at 1.
    19
      int r_assign_ref; // It is a reverse of the assign_ref. Starts at 1.
    20
      int bypass_ref; // Some exec may not generate output for this tensor. In that case, use the content from tensor bypass (typical case for case..of). Starts at 1.
    21
      int r_bypass_ref; // It is a reverse of the bypass_ref. Starts at 1.
    22
      int p_ref; // Reference to the tensor number in its parent graph. Starts at 1.
    23
      // End of while loop handling.
    24
      int alias_ref; // Reference to the tensor. Starts at 1.
    25
      int pair_ref; // Reference to its pair. Starts at 1.
    26
      int flags;
    27
      int ofs[CCV_NNC_MAX_DIM_ALLOC];
    28
      int stride[CCV_NNC_MAX_DIM_ALLOC];
    29
      ccv_array_t* s_ref; // Reference to the tensor number in its sub graphs, Starts at 1.
    30
      char* name;
    31
      ccv_nnc_tensor_param_t info;
    32
    } ccv_nnc_tensor_symbol_info_t;
    33
    34
    enum {
    35
      CCV_NNC_GRAPH_EXEC_CASE_OF_NO_BYPASS = 0x01, // If this flag is set, this case..of won't have any bypass.
    36
    };
    37
    38
    typedef struct {
    39
      int input_size;
    40
      int output_size;
    41
      int graph_ref_size;
    42
      int flags; // Mark this node as dead. Lower 16 bits is for internal use, such as mark as dead. Higher 16-bit can be set.
    43
      int pair_ref; // Reference to its pair. Starts at 1.
    44
      int* inputs;
    45
      int* outputs;
    46
      ccv_array_t* outgoings; // Outgoing nodes
    47
      char* name;
    48
      ccv_nnc_cmd_t cmd;
    49
      ccv_nnc_hint_t hint;
    50
      // Below are only relevant to sub-graph nodes (case_of, while).
    51
      int _inline_graph_ref[2]; // Reference to the sub-graph. Starts at 1.
    52
      int* _heap_graph_ref;
    53
      union {
    54
        struct {
    55
          ccv_nnc_graph_case_of_f expr;
    56
          const void* data;
    57
          int flags;
    58
          struct {
    59
            int offset;
    60
            int size;
    61
          } argument; // range for which data as inputs from input section.
    62
        } case_of;
    63
        struct {
    64
          ccv_nnc_graph_while_f expr;
    65
          const void* data;
    66
          int* inputs;
    67
          int input_size;
    68
        } p_while;
    69
      };
    70
    } ccv_nnc_graph_exec_symbol_info_t;
    71
    72
    struct ccv_nnc_symbolic_graph_s {
    73
      ccv_array_t* tensor_symbol_info; // A lit of info for tensor symbols.
    74
      ccv_array_t* exec_symbol_info; // A list of info for exec symbols.
    75
      // I think that I can be more explicit about which are sources and which are destinations.
    76
      ccv_array_t* sources;
    77
      ccv_array_t* destinations;
    78
      // Some extra information piggy-back on symbolic graph struct.
    79
      // Start for while loop handling
    80
      ccv_array_t* sub_graphs; // A list of its sub-graphs (for while loop).
    81
      struct ccv_nnc_symbolic_graph_s* pair; // The pair graph (only useful for backward prop graph).
    82
      struct ccv_nnc_symbolic_graph_s* p; // The parent graph (if current one is a sub-graph).
    83
      int p_idx; // Reference to the index in its parent graph's sub-graph array, Starts at 1.
    84
      int exec_idx; // Reference to the index in its parent graph's exec (the graph exec), Starts at 1.
    85
      // Why some of these I choose to be flat int* array, some of these I choose to be ccv_array_t?
    86
      // for flat int* array, these are not going to be modified until next time call ccv_nnc_symbolic_graph_backward
    87
      // for ccv_array_t, we can continue to modify what's inside.
    88
      int breakpoint_size;
    89
      ccv_nnc_graph_exec_symbol_t* breakpoints;
    90
      // End of while loop handling.
    91
      struct {
    92
        int tensor;
    93
        int exec;
    94
      } reuse; // The reuse slot for tensor or graph exec symbols.
    95
      // Start for backward (automatic differentiation) handling
    96
      struct {
    97
        int tensor_symbol_size;
    98
        int* tensor_symbol_idx;
    99
        int exec_symbol_size;
    100
        int* exec_symbol_idx;
    101
      } backward;
    102
      // End of backward (automatic differentiation) handling.
    103
      // For parallel, get duplicated tensors.
    104
      struct {
    105
        int count;
    106
        int tensor_symbol_size;
    107
        int* tensor_symbol_idx;
    108
        int exec_symbol_size;
    109
        int* exec_symbol_idx;
    110
      } data_parallel;
    111
      // Hooks
    112
      struct {
    113
        struct {
    114
          ccv_nnc_tensor_symbol_new_hook_f func;
    115
          void* context;
    116
        } tensor_symbol_new;
    117
        struct {
    118
          ccv_nnc_tensor_symbol_alias_new_hook_f func;
    119
          void* context;
    120
        } tensor_symbol_alias_new;
    121
        struct {
    122
          ccv_nnc_graph_exec_symbol_new_hook_f func;
    123
          void* context;
    124
        } graph_exec_symbol_new;
    125
      } hooks;
    126
    };
    127
    128
    typedef void(*ccv_nnc_arena_dispose_f)(void* ptr, void* userdata);
    129
    typedef struct {
    130
      void* ptr;
    131
      void* userdata;
    132
      ccv_nnc_arena_dispose_f dispose;
    133
    } ccv_nnc_arena_disposer_t;
    134
    135
    struct ccv_nnc_tensor_arena_s {
    136
      intptr_t graph_ref; // A value contains the pointer name of the graph.
    137
      int sub_arena_size;
    138
      struct ccv_nnc_tensor_arena_s** sub_arenas; // Corresponding to sub graphs.
    139
      // This is a table of tensor references to real allocated tensors.
    140
      int vt_tensor_size;
    141
      ccv_nnc_tensor_t** vt_tensors;
    142
      int* vt_alias_refs; // reference to which it is alias to.
    143
      int* vt_alias_r_refs_p; // pointer to record which tensor this is aliased to.
    144
      int* vt_alias_r_refs; // array to record which tensor this is aliased to. This is first created when bind a symbol.
    145
      size_t* vt_sizes; // The size of each tensor.
    146
      ccv_numeric_data_t* pb_vt_tensors; // pre-bindings for this vt_tensors, this is optional.
    147
      struct {
    148
        const ccv_nnc_symbolic_graph_compile_allocator_vtab_t* isa;
    149
        struct {
    150
          void* free;
    151
        } context;
    152
      } allocator;
    153
      // This is the allocated non-continuous buffers.
    154
      int buffer_size;
    155
      struct {
    156
        int type; // The type from tensor blocks.
    157
        int pin_mem; // Whether this memory is pinned.
    158
        uint64_t size;
    159
        uint8_t* ptr;
    160
      }* buffers;
    161
      // Real allocated tensor header metadata (this is a mixed pool of ccv_tensor_t, ccv_tensor_view_t,
    162
      // ccv_tensor_multiview_t, thus, it is aligned to a 16-byte boundary).
    163
      ccv_array_t* tensor_metadata;
    164
      ccv_array_t* m_tensor_idx; // The index into multi-view tensors in tensor_metadata.
    165
      ccv_array_t* disposers; // Generic dispose structure that shares life-cycle with the arena.
    166
    };
    167
    168
    struct ccv_nnc_graph_exec_arena_s {
    169
      intptr_t graph_ref; // A value contains the pointer name of the graph.
    170
      int sub_arena_size;
    171
      struct ccv_nnc_graph_exec_arena_s** sub_arenas; // Corresponding to sub graphs.
    172
      ccv_nnc_graph_exec_t source;
    173
      ccv_nnc_graph_exec_t destination;
    174
      int graph_exec_size;
    175
      ccv_nnc_graph_exec_t graph_execs[1];
    176
    };
    177
    178
    1
    #define CCV_NNC_ENCODE_WHILE_COUNT_SYMBOL(d) ((int)((~(uint32_t)d) << 4 | 0xe))
    179
    40
    #define CCV_NNC_DECODE_WHILE_COUNT_SYMBOL(symbol) ((~(uint32_t)(symbol)) >> 4)
    180
    181
    inline static void ccv_array_replace_unique_int(ccv_array_t* ints, const int idx, const int outgoing)
    182
    8.60k
    {
    183
    8.60k
      int i;
    184
    8.60k
      int flag = 0;
    185
    17.2k
      for (i = 0; i < ints->rnum;)
    186
    8.61k
      {
    187
    8.61k
        if (*(int*)ccv_array_get(ints, i) == idx)
    188
    4.29k
        {
    189
    4.29k
          if (flag)
    190
    4
          {
    191
    4
            if (i < ints->rnum - 1)
    192
    4
              *(int*)ccv_array_get(ints, i) = *(int*)ccv_array_get(ints, ints->rnum - 1);
    193
    4
            --ints->rnum;
    194
    4
            continue;
    195
    4
          }
    196
    4.28k
          *(int*)ccv_array_get(ints, i) = outgoing;
    197
    4.28k
          flag = 1;
    198
    4.32k
        } else if (*(int*)ccv_array_get(ints, i) == outgoing) {
    199
          // Remove this from the list.
    200
    4.24k
          if (flag)
    201
    0
          {
    202
    0
            if (i < ints->rnum - 1)
    203
    0
              *(int*)ccv_array_get(ints, i) = *(int*)ccv_array_get(ints, ints->rnum - 1);
    204
    0
            --ints->rnum;
    205
    0
            continue;
    206
    0
          }
    207
    4.24k
          flag = 1;
    208
    4.24k
        }
    209
    8.61k
        ++i;
    210
    8.61k
      }
    211
    8.60k
      if (!flag)
    212
    76
        ccv_array_push(ints, &outgoing);
    213
    8.60k
    }
    Unexecuted instantiation: ccv_nnc_tensor_io.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_io.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_compile.c:ccv_array_replace_unique_int

    ccv_nnc_symbolic_graph_backward.c:ccv_array_replace_unique_int

    Line
    Count
    Source
    182
    8.59k
    {
    183
    8.59k
      int i;
    184
    8.59k
      int flag = 0;
    185
    17.1k
      for (i = 0; i < ints->rnum;)
    186
    8.57k
      {
    187
    8.57k
        if (*(int*)ccv_array_get(ints, i) == idx)
    188
    4.28k
        {
    189
    4.28k
          if (flag)
    190
    0
          {
    191
    0
            if (i < ints->rnum - 1)
    192
    0
              *(int*)ccv_array_get(ints, i) = *(int*)ccv_array_get(ints, ints->rnum - 1);
    193
    0
            --ints->rnum;
    194
    0
            continue;
    195
    0
          }
    196
    4.28k
          *(int*)ccv_array_get(ints, i) = outgoing;
    197
    4.28k
          flag = 1;
    198
    4.29k
        } else if (*(int*)ccv_array_get(ints, i) == outgoing) {
    199
          // Remove this from the list.
    200
    4.23k
          if (flag)
    201
    0
          {
    202
    0
            if (i < ints->rnum - 1)
    203
    0
              *(int*)ccv_array_get(ints, i) = *(int*)ccv_array_get(ints, ints->rnum - 1);
    204
    0
            --ints->rnum;
    205
    0
            continue;
    206
    0
          }
    207
    4.23k
          flag = 1;
    208
    4.23k
        }
    209
    8.57k
        ++i;
    210
    8.57k
      }
    211
    8.59k
      if (!flag)
    212
    72
        ccv_array_push(ints, &outgoing);
    213
    8.59k
    }
    Unexecuted instantiation: ccv_nnc_symbolic_graph_while.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_case_of.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_minimize.c:ccv_array_replace_unique_int

    ccv_nnc_symbolic_graph_parallel.c:ccv_array_replace_unique_int

    Line
    Count
    Source
    182
    16
    {
    183
    16
      int i;
    184
    16
      int flag = 0;
    185
    60
      for (i = 0; i < ints->rnum;)
    186
    44
      {
    187
    44
        if (*(int*)ccv_array_get(ints, i) == idx)
    188
    8
        {
    189
    8
          if (flag)
    190
    4
          {
    191
    4
            if (i < ints->rnum - 1)
    192
    4
              *(int*)ccv_array_get(ints, i) = *(int*)ccv_array_get(ints, ints->rnum - 1);
    193
    4
            --ints->rnum;
    194
    4
            continue;
    195
    4
          }
    196
    4
          *(int*)ccv_array_get(ints, i) = outgoing;
    197
    4
          flag = 1;
    198
    36
        } else if (*(int*)ccv_array_get(ints, i) == outgoing) {
    199
          // Remove this from the list.
    200
    8
          if (flag)
    201
    0
          {
    202
    0
            if (i < ints->rnum - 1)
    203
    0
              *(int*)ccv_array_get(ints, i) = *(int*)ccv_array_get(ints, ints->rnum - 1);
    204
    0
            --ints->rnum;
    205
    0
            continue;
    206
    0
          }
    207
    8
          flag = 1;
    208
    8
        }
    209
    40
        ++i;
    210
    40
      }
    211
    16
      if (!flag)
    212
    4
        ccv_array_push(ints, &outgoing);
    213
    16
    }
    Unexecuted instantiation: ccv_nnc_symbolic_graph_simplify.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_memory_compression.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_memory_reduction.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_array_replace_unique_int
    Unexecuted instantiation: ccv_nnc_symbolic_graph_chain_decomposition.c:ccv_array_replace_unique_int
    214
    215
    void ccv_nnc_symbolic_graph_symbol_infer(const ccv_nnc_symbolic_graph_t* const symbolic_graph, const ccv_nnc_graph_visit_t* const visit, const ccv_nnc_graph_exec_symbol_t* const sources, const int source_size, const ccv_nnc_graph_exec_symbol_t* const destinations, const int destination_size, const ccv_nnc_tensor_symbol_info_t* const p_tensor_symbol_info, const int p_tensor_symbol_info_size, ccv_nnc_tensor_symbol_info_t* const tensor_symbol_info, ccv_nnc_graph_exec_symbol_info_t* const exec_symbol_info);
    216
    217
    int ccv_nnc_over_tensor_symbol_aliases(const ccv_nnc_tensor_symbol_info_t* const tensor_a, const ccv_nnc_tensor_symbol_info_t* const tensor_b);
    218
    int ccv_nnc_tensor_symbol_map_raw(ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t symbol);
    219
    220
    typedef struct {
    221
      int flags;
    222
      int* chain_ids;
    223
      int* chain_pos;
    224
      ccv_sparse_matrix_t* deps;
    225
    } ccv_nnc_exec_dep_t;
    226
    227
    ccv_nnc_exec_dep_t ccv_nnc_exec_dep_new(const ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_graph_visit_t* const visit);
    228
    void ccv_nnc_exec_dep_free(const ccv_nnc_exec_dep_t exec_dep);
    229
    230
    inline static int ccv_nnc_exec_dep_hop(const ccv_nnc_exec_dep_t exec_dep, const int d, ccv_sparse_matrix_vector_t* const vector, const int dd)
    231
    0
    {
    232
      // Check if dd is d's ancestor.
    233
    0
      const int dd_chain_id = exec_dep.chain_ids[dd];
    234
    0
      const int dd_chain_pos = exec_dep.chain_pos[dd];
    235
    0
      if (exec_dep.chain_ids[d] == dd_chain_id)
    236
    0
        return exec_dep.chain_pos[d] - dd_chain_pos;
    237
    0
      const ccv_numeric_data_t cell = vector ? ccv_get_sparse_matrix_cell_from_vector(exec_dep.deps, vector, dd_chain_id) : ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id);
    238
      // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor.
    239
    0
      if (cell.i32 && cell.i32[0] > 0 && cell.i32[0] >= dd_chain_pos)
    240
    0
        return cell.i32[0] - dd_chain_pos + cell.i32[1];
    241
    0
      return -1;
    242
    0
    }
    Unexecuted instantiation: ccv_nnc_tensor_io.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_io.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_compile.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_backward.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_while.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_case_of.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_minimize.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_parallel.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_simplify.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_memory_compression.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_memory_reduction.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_cnnp_model_gradient_checkpointing.c:ccv_nnc_exec_dep_hop
    Unexecuted instantiation: ccv_nnc_symbolic_graph_chain_decomposition.c:ccv_nnc_exec_dep_hop
    243
    244
    inline static int ccv_nnc_exec_dep_check(const ccv_nnc_exec_dep_t exec_dep, const int d, ccv_sparse_matrix_vector_t* const vector, const int dd)
    245
    81
    {
    246
      // Check if dd is d's ancestor.
    247
    81
      const int dd_chain_id = exec_dep.chain_ids[dd];
    248
    81
      const int dd_chain_pos = exec_dep.chain_pos[dd];
    249
    81
      if (exec_dep.chain_ids[d] == dd_chain_id)
    250
    38
        return exec_dep.chain_pos[d] > dd_chain_pos;
    251
    43
      if (vector == (ccv_sparse_matrix_vector_t*)1) // Special sentinel value to say that we don't have vector found.
    252
    22
        return 0;
    253
    21
      const ccv_numeric_data_t cell = vector ? ccv_get_sparse_matrix_cell_from_vector(exec_dep.deps, vector, dd_chain_id) : ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id)0;
    254
      // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor.
    255
    21
      if (cell.i32 && cell.i32[0] > 010)
    256
    10
        return cell.i32[0] >= dd_chain_pos;
    257
    11
      return 0;
    258
    21
    }
    Unexecuted instantiation: ccv_nnc_tensor_io.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_io.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_compile.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_backward.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_while.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_case_of.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_minimize.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_parallel.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_simplify.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_memory_compression.c:ccv_nnc_exec_dep_check
    Unexecuted instantiation: ccv_nnc_symbolic_graph_memory_reduction.c:ccv_nnc_exec_dep_check

    ccv_cnnp_model_gradient_checkpointing.c:ccv_nnc_exec_dep_check

    Line
    Count
    Source
    245
    81
    {
    246
      // Check if dd is d's ancestor.
    247
    81
      const int dd_chain_id = exec_dep.chain_ids[dd];
    248
    81
      const int dd_chain_pos = exec_dep.chain_pos[dd];
    249
    81
      if (exec_dep.chain_ids[d] == dd_chain_id)
    250
    38
        return exec_dep.chain_pos[d] > dd_chain_pos;
    251
    43
      if (vector == (ccv_sparse_matrix_vector_t*)1) // Special sentinel value to say that we don't have vector found.
    252
    22
        return 0;
    253
    21
      const ccv_numeric_data_t cell = vector ? ccv_get_sparse_matrix_cell_from_vector(exec_dep.deps, vector, dd_chain_id) : ccv_get_sparse_matrix_cell(exec_dep.deps, d, dd_chain_id)0;
    254
      // Check if the chain pos is greater than or equal to dd_chain_pos. If it is, it is an ancestor.
    255
    21
      if (cell.i32 && cell.i32[0] > 010)
    256
    10
        return cell.i32[0] >= dd_chain_pos;
    257
    11
      return 0;
    258
    21
    }
    Unexecuted instantiation: ccv_nnc_symbolic_graph_chain_decomposition.c:ccv_nnc_exec_dep_check
    259
    260
    #endif
    261