## Coverage Report

#### Created: 2026-05-04 15:30

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

    /home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/tape.tests.c

    Line
    Count
    Source
    1
    #include "case.h"
    2
    #include "ccv_case.h"
    3
    #include "ccv_nnc_case.h"
    4
    #include <ccv.h>
    5
    #include <nnc/ccv_nnc.h>
    6
    #include <nnc/ccv_nnc_easy.h>
    7
    #include <nnc/_ccv_nnc_graph.h>
    8
    #include <3rdparty/dsfmt/dSFMT.h>
    9
    10
    TEST_SETUP()
    11
    {
    12
      ccv_nnc_init();
    13
    }
    14
    15
    TEST_CASE("new tape from a graph")
    16
    1
    {
    17
    1
      ccv_nnc_symbolic_graph_t* symbolic_graph = ccv_nnc_symbolic_graph_new();
    18
    1
      ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x");
    19
    1
      ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y");
    20
    1
      ccv_nnc_tensor_symbol_t z0 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z0");
    21
    1
      ccv_nnc_symbolic_graph_t* while_symbolic_graph = ccv_nnc_symbolic_graph_new();
    22
    1
      ccv_nnc_graph_exec_symbol_t while_symbol = ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_symbolic_graph, "for 1..5");
    23
    1
      ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z1");
    24
    1
      ccv_nnc_graph_exec_symbol_t noop = ccv_nnc_graph_exec_symbol_new(while_symbolic_graph, CMD_NOOP(), 0, 0, 0, 0, "noop");
    25
    1
      ccv_nnc_graph_exec_symbol_t prod0 = ccv_nnc_graph_exec_symbol_new(while_symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z0, x), TENSOR_SYMBOL_LIST(z1), "prod0");
    26
    1
      ccv_nnc_graph_exec_symbol_concat(while_symbolic_graph, noop, prod0);
    27
    1
      ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z2");
    28
    1
      ccv_nnc_tensor_symbol_t z3 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z3");
    29
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z1, y), TENSOR_SYMBOL_LIST(z2), "prod1");
    30
    1
      ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z2, z0), TENSOR_SYMBOL_LIST(z3), "sum");
    31
    1
      ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
    32
    1
      ccv_nnc_symbolic_graph_set_while_expr(while_symbolic_graph, NOOP_GRAPH_WHILE_EXPR, 0, 0, 0, GRAPH_EXEC_SYMBOL_LIST(noop));
    33
    1
      ccv_nnc_symbolic_graph_set_carry_overs(while_symbolic_graph, TENSOR_SYMBOL_MAP(KV(z1, z0)));
    34
    1
      ccv_nnc_symbolic_graph_set_sources(while_symbolic_graph, GRAPH_EXEC_SYMBOL_LIST(noop));
    35
    1
      ccv_nnc_symbolic_graph_set_destinations(while_symbolic_graph, GRAPH_EXEC_SYMBOL_LIST(prod0));
    36
    1
      ccv_nnc_graph_t* graph = 0;
    37
    1
      ccv_nnc_tensor_arena_t* tensor_arena = 0;
    38
    1
      ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
    39
    1
      ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, ccv_nnc_symbolic_graph_sources(symbolic_graph), ccv_nnc_symbolic_graph_source_size(symbolic_graph), ccv_nnc_symbolic_graph_destinations(symbolic_graph), ccv_nnc_symbolic_graph_destination_size(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
    40
    1
      SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
    41
    1
      GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
    42
    1
      ccv_nnc_symbolic_graph_free(symbolic_graph);
    43
    1
      ccv_nnc_graph_exec_t while_exec = ccv_nnc_graph_exec_from_symbol(graph_exec_arena, while_symbol);
    44
    1
      ccv_nnc_graph_t* while_graph = ccv_nnc_graph_from_while_exec(graph, while_exec);
    45
    1
      ccv_nnc_graph_t* sub_while_graph = ccv_nnc_graph_new();
    46
    1
      ccv_nnc_graph_exec_t sub_while_exec = ccv_nnc_graph_while(while_graph, CCV_NNC_GRAPH_FORWARD, sub_while_graph);
    47
    1
      ccv_nnc_graph_exec_t noop_exec = ccv_nnc_graph_exec_from_symbol(graph_exec_arena, noop);
    48
    1
      ccv_nnc_graph_exec_concat(while_graph, noop_exec, sub_while_exec);
    49
    1
      ccv_nnc_tensor_tape_t* tape = ccv_nnc_tensor_tape_new();
    50
    1
      ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1), 0);
    51
    1
      ccv_numeric_data_t data = tensor->data; // Preserve the data field.
    52
    1
      tensor->type |= CCV_TAPE_ALLOC;
    53
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(), 0, TENSOR_LIST(tensor));
    54
    1
      REQUIRE(tensor->data.u8 != data.u8, "Tensor should assigned a different memory region with (0, 0).");
    55
    1
      tensor->data.f32[0] = 0.32;
    56
    1
      while_graph->while_count = 2;
    57
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(), 0, TENSOR_LIST(tensor));
    58
    1
      REQUIRE(tensor->data.u8 != data.u8, "Tensor should assigned a different memory region with (0, 2).");
    59
    1
      tensor->data.f32[0] = 0.11;
    60
    1
      graph->while_count = 1;
    61
    1
      while_graph->while_count = 1;
    62
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(), 0, TENSOR_LIST(tensor));
    63
    1
      REQUIRE(tensor->data.u8 != data.u8, "Tensor should assigned a different memory region with (1, 1).");
    64
    1
      tensor->data.f32[0] = 0.58;
    65
    1
      while_graph->while_count = 2;
    66
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(), 0, TENSOR_LIST(tensor));
    67
    1
      REQUIRE(tensor->data.u8 != data.u8, "Tensor should assigned a different memory region with (1, 2).");
    68
    1
      tensor->data.f32[0] = 0.18;
    69
    1
      graph->while_count = 2;
    70
    1
      while_graph->while_count = 3;
    71
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(), 0, TENSOR_LIST(tensor));
    72
    1
      REQUIRE(tensor->data.u8 != data.u8, "Tensor should assigned a different memory region with (2, 3).");
    73
    1
      tensor->data.f32[0] = 1.29;
    74
    1
      while_graph->while_count = 2;
    75
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(), 0, TENSOR_LIST(tensor));
    76
    1
      REQUIRE(tensor->data.u8 != data.u8, "Tensor should assigned a different memory region with (2, 2).");
    77
    1
      tensor->data.f32[0] = 0.02;
    78
    1
      graph->while_count = 0;
    79
    1
      while_graph->while_count = 2;
    80
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(tensor), 0, TENSOR_LIST());
    81
    1
      REQUIRE_EQ_WITH_TOLERANCE(tensor->data.f32[0], 0.11, 1e-5, "Tensor should retain 0.11 with (0, 2).");
    82
    1
      graph->while_count = 1;
    83
    1
      while_graph->while_count = 1;
    84
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(tensor), 0, TENSOR_LIST());
    85
    1
      REQUIRE_EQ_WITH_TOLERANCE(tensor->data.f32[0], 0.58, 1e-5, "Tensor should retain 0.58 with (1, 1).");
    86
    1
      graph->while_count = 0;
    87
    1
      while_graph->while_count = 0;
    88
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(tensor), 0, TENSOR_LIST());
    89
    1
      REQUIRE_EQ_WITH_TOLERANCE(tensor->data.f32[0], 0.32, 1e-5, "Tensor should retain 0.32 with (0, 0).");
    90
    1
      graph->while_count = 2;
    91
    1
      while_graph->while_count = 3;
    92
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(tensor), 0, TENSOR_LIST());
    93
    1
      REQUIRE_EQ_WITH_TOLERANCE(tensor->data.f32[0], 1.29, 1e-5, "Tensor should retain 1.29 with (2, 3).");
    94
    1
      graph->while_count = 2;
    95
    1
      while_graph->while_count = 2;
    96
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(tensor), 0, TENSOR_LIST());
    97
    1
      REQUIRE_EQ_WITH_TOLERANCE(tensor->data.f32[0], 0.02, 1e-5, "Tensor should retain 0.02 with (2, 2).");
    98
    1
      graph->while_count = 1;
    99
    1
      while_graph->while_count = 2;
    100
    1
      ccv_nnc_tensor_tape_io(tape, while_graph, 0, TENSOR_LIST(tensor), 0, TENSOR_LIST());
    101
    1
      REQUIRE_EQ_WITH_TOLERANCE(tensor->data.f32[0], 0.18, 1e-5, "Tensor should retain 0.02 with (1, 2).");
    102
    1
      tensor->data = data;
    103
      // Verify while count
    104
    1
      while_graph->while_count = 0;
    105
    1
      ccv_nnc_tensor_tape_set_numbering(tape, graph, while_exec, 0);
    106
    1
      while_graph->while_count = 1;
    107
    1
      ccv_nnc_tensor_tape_set_numbering(tape, graph, while_exec, 1);
    108
    1
      sub_while_graph->while_count = 1;
    109
    1
      ccv_nnc_tensor_tape_set_numbering(tape, while_graph, sub_while_exec, 1);
    110
    1
      sub_while_graph->while_count = 2;
    111
    1
      ccv_nnc_tensor_tape_set_numbering(tape, while_graph, sub_while_exec, 2);
    112
    1
      while_graph->while_count = 2;
    113
    1
      ccv_nnc_tensor_tape_set_numbering(tape, graph, while_exec, 2);
    114
    1
      sub_while_graph->while_count = 2;
    115
    1
      ccv_nnc_tensor_tape_set_numbering(tape, while_graph, sub_while_exec, 2);
    116
    1
      sub_while_graph->while_count = 3;
    117
    1
      ccv_nnc_tensor_tape_set_numbering(tape, while_graph, sub_while_exec, 3);
    118
    1
      REQUIRE_EQ(ccv_nnc_tensor_tape_numbering(tape, graph, while_exec), 2, "First while graph should have count to 2");
    119
    1
      REQUIRE_EQ(ccv_nnc_tensor_tape_numbering(tape, while_graph, sub_while_exec), 3, "Second while graph should have count to 3");
    120
    1
      while_graph->while_count = 1;
    121
    1
      REQUIRE_EQ(ccv_nnc_tensor_tape_numbering(tape, while_graph, sub_while_exec), 2, "Second while graph should have count to 2");
    122
    1
      while_graph->while_count = 3;
    123
    1
      ccv_nnc_tensor_tape_set_numbering(tape, while_graph, sub_while_exec, 4);
    124
    1
      REQUIRE_EQ(ccv_nnc_tensor_tape_numbering(tape, while_graph, sub_while_exec), 4, "Second while graph should have count to 4");
    125
    1
      ccv_nnc_tensor_tape_set_numbering(tape, graph, while_exec, 3);
    126
    1
      REQUIRE_EQ(ccv_nnc_tensor_tape_numbering(tape, graph, while_exec), 3, "First while graph should have count to 3");
    127
    1
      while_graph->while_count = 2;
    128
    1
      REQUIRE_EQ(ccv_nnc_tensor_tape_numbering(tape, while_graph, sub_while_exec), 3, "Second while graph should have count to 3");
    129
    1
      ccv_nnc_tensor_free(tensor);
    130
    1
      ccv_nnc_tensor_tape_free(tape);
    131
    1
      ccv_nnc_tensor_arena_free(tensor_arena);
    132
    1
      ccv_nnc_graph_exec_arena_free(graph_exec_arena);
    133
    1
      ccv_nnc_graph_free(graph);
    134
    1
    }
    135
    136
    #include "case_main.h"