KleidiAI Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 90.6% 58 / 0 / 64
Functions: 89.5% 17 / 0 / 19
Branches: 28.4% 21 / 0 / 74

test/nextgen/harness/tensor.hpp
Line Branch Exec Source
1 //
2 // SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 //
6
7 #pragma once
8
9 #include <algorithm>
10 #include <cstddef>
11 #include <optional>
12 #include <ostream>
13 #include <string_view>
14 #include <utility>
15 #include <vector>
16
17 #include "test/common/assert.hpp"
18 #include "test/common/buffer.hpp"
19 #include "test/common/span.hpp"
20 #include "test/nextgen/common/poly.hpp"
21 #include "test/nextgen/format/format.hpp"
22
23 namespace kai::test {
24
25 /// Multidimensional data slot.
26 class Tensor {
27 public:
28 /// Gets the size of the multidimensional array.
29 400 [[nodiscard]] Span<const size_t> shape() const {
30 400 return m_shape;
31 }
32
33 /// Sets the shape.
34 ///
35 /// A slot cannot change its shape. If the shape is already non-zero,
36 /// the new shape must be the same as the existing shape
37 /// to make sure all components in the test environment have the same
38 /// expectation for this slot.
39 5400 Tensor& set_shape(Span<const size_t> shape) {
40
2/2
✓ Branch 0 taken 1200 times.
✓ Branch 1 taken 4200 times.
5400 if (m_shape.empty()) {
41
1/4
✓ Branch 0 taken 4200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4200 KAI_TEST_ASSERT_MSG(m_data.size() == 0, "The slot must be empty when its shape is setup.");
42
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
4200 m_shape = std::vector(shape.begin(), shape.end());
43 4200 } else {
44
1/4
✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1200 KAI_TEST_ASSERT_MSG(
45 std::equal(m_shape.begin(), m_shape.end(), shape.begin(), shape.end()),
46 "The new shape must be the same as the existing shape.");
47 }
48
49 5400 return *this;
50 }
51
52 /// Gets the data format.
53 2600 [[nodiscard]] const Poly<Format>& format() const {
54 2600 return m_format.value();
55 }
56
57 /// Sets the data format.
58 ///
59 /// A slot cannot change its data format. If the data format is already known,
60 /// the new format must be the same as the existing one
61 /// to make sure all components in the test environment have the same
62 /// expectation for this slot.
63 4745 Tensor& set_format(const Poly<Format>& format) {
64
2/2
✓ Branch 0 taken 3600 times.
✓ Branch 1 taken 1145 times.
4745 if (!m_format.has_value()) {
65
1/4
✓ Branch 0 taken 3600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3600 KAI_TEST_ASSERT_MSG(m_data.size() == 0, "The slot must be empty when its format is setup.");
66 3600 m_format = format;
67 3600 } else {
68
1/4
✓ Branch 0 taken 1145 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1145 KAI_TEST_ASSERT_MSG(
69 *m_format.value() == *format, "The new format must be the same as the existing format.");
70 }
71
72 4745 return *this;
73 }
74
75 /// Gets the data.
76 10525 [[nodiscard]] Span<const std::byte> data() const {
77 10525 return m_data;
78 }
79
80 /// Gets the data.
81 3600 [[nodiscard]] Span<std::byte> data() {
82 3600 return m_data;
83 }
84
85 /// Gets the data.
86 3400 [[nodiscard]] const std::byte* data_ptr() const {
87 3400 return m_data.data();
88 }
89
90 /// Gets the data.
91 1800 [[nodiscard]] std::byte* data_ptr() {
92 1800 return m_data.data();
93 }
94
95 /// Gets the value in custom format.
96 template <typename T>
97 3200 [[nodiscard]] const T& value() const {
98
2/8
✓ Branch 0 taken 1800 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1400 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3200 KAI_TEST_ASSERT_MSG(!m_format.has_value(), "This method only works on custom data.");
99
2/8
✓ Branch 0 taken 1800 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1400 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3200 KAI_TEST_ASSERT_MSG(m_data.size() == sizeof(T), "The data size is incorrect.");
100
101 3200 return *reinterpret_cast<const T*>(data_ptr());
102 }
103
104 /// Gets the value in custom format.
105 template <typename T>
106 1800 [[nodiscard]] T& value() {
107
1/4
✓ Branch 0 taken 1800 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1800 KAI_TEST_ASSERT_MSG(!m_format.has_value(), "This method only works on custom data.");
108
1/4
✓ Branch 0 taken 1800 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1800 KAI_TEST_ASSERT_MSG(m_data.size() == sizeof(T), "The data size is incorrect.");
109
110 1800 return *reinterpret_cast<T*>(data_ptr());
111 }
112
113 /// Sets the value in custom format.
114 template <typename T>
115 200 void set_value(T&& value) {
116
1/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
200 KAI_TEST_ASSERT_MSG(!m_format.has_value(), "This method only works on custom data.");
117
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (m_shape.empty()) {
118
1/4
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
200 KAI_TEST_ASSERT_MSG(
119 m_data.size() == 0, "If the shape is not specified, the data cannot be already allocated.");
120
121 200 set_shape({sizeof(T)});
122 200 allocate();
123 200 } else {
124 KAI_TEST_ASSERT_MSG(m_shape.size() == 1 && m_shape.at(0) == sizeof(T), "The shape is incorrect.");
125 KAI_TEST_ASSERT_MSG(m_data.size() == sizeof(T), "The data size is incorrect.");
126 }
127
128 200 this->value<T>() = std::forward<T>(value);
129 200 }
130
131 /// Allocates and resets the data buffer.
132 2200 void allocate() {
133 2200 const size_t size = compute_size();
134 2200 m_data = Buffer(size, 0);
135 2200 }
136
137 /// Sets the data buffer.
138 ///
139 /// The new data buffer must have the right size.
140 3200 void set_data(Buffer&& buffer) {
141 3200 [[maybe_unused]] const size_t size = compute_size();
142
1/4
✓ Branch 0 taken 3200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3200 KAI_TEST_ASSERT_MSG(buffer.size() == size, "New data buffer must have the right size.");
143 3200 m_data = std::move(buffer);
144 3200 }
145
146 private:
147 5400 [[nodiscard]] size_t compute_size() const {
148
2/2
✓ Branch 0 taken 4800 times.
✓ Branch 1 taken 600 times.
5400 if (m_format.has_value()) {
149 4800 return m_format.value()->compute_size(m_shape);
150 }
151
152 // If the data format is not available, this slot is used to store custom data
153 // rather than multidimensional array. The first element of the shape
154 // is the size of the data being stored.
155
1/4
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
600 KAI_TEST_ASSERT_MSG(
156 m_shape.size() == 1, "Custom data slot must use the shape to store the size of entire data.");
157 600 return m_shape.at(0);
158 5400 }
159
160 std::vector<size_t> m_shape;
161 std::optional<Poly<Format>> m_format;
162 Buffer m_data;
163 };
164
165 } // namespace kai::test
166