Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./zerocopy/tensor.h"
25 : :
26 : : #include <cstdint>
27 : : #include <limits>
28 : :
29 : : namespace vlink {
30 : :
31 : : namespace zerocopy {
32 : :
33 : : // Tensor
34 : 101 : Tensor::Tensor() noexcept {
35 : : #if defined(__arm__) || defined(__x86__) || defined(__i386__)
36 : : #ifndef __ANDROID__
37 : : #warning "[Tensor] No support for 32-bit architecture."
38 : : #endif
39 : : #else
40 : : static_assert(sizeof(Tensor) == 248, "Sizeof must be 248 bytes.");
41 : : #endif
42 : 101 : }
43 : :
44 : 103 : Tensor::~Tensor() noexcept {
45 [ + + + - : 103 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
46 : 48 : Bytes::bytes_free(data_, size_);
47 : : }
48 : 103 : }
49 : :
50 : 1 : Tensor::Tensor(const Tensor& target) noexcept { deep_copy(target); }
51 : :
52 : 1 : Tensor::Tensor(Tensor&& target) noexcept { move_copy(target); }
53 : :
54 : 1 : Tensor& Tensor::operator=(const Tensor& target) noexcept {
55 [ - + ]: 1 : if VUNLIKELY (this == &target) {
56 : : return *this; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
57 : : }
58 : :
59 : 1 : deep_copy(target);
60 : :
61 : 1 : return *this;
62 : : }
63 : :
64 : 1 : Tensor& Tensor::operator=(Tensor&& target) noexcept {
65 [ - + ]: 1 : if VUNLIKELY (this == &target) {
66 : : return *this; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
67 : : }
68 : :
69 : 1 : move_copy(target);
70 : :
71 : 1 : return *this;
72 : : }
73 : :
74 : 24 : bool Tensor::operator<<(const Bytes& bytes) noexcept {
75 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
76 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
77 : : // static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
78 : :
79 [ + + ]: 24 : if VUNLIKELY (bytes.empty()) {
80 : 1 : return false;
81 : : }
82 : :
83 [ + + ]: 23 : if VUNLIKELY (!check_valid(bytes)) {
84 : 2 : return false;
85 : : }
86 : :
87 : 21 : uint32_t wire_version = 0;
88 : 21 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
89 : :
90 [ - + ]: 21 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
91 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
92 : : }
93 : :
94 [ + + + - : 21 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
95 : 1 : Bytes::bytes_free(data_, size_);
96 : : }
97 : :
98 : : #if defined(__GNUC__) && !defined(__clang__)
99 : : #pragma GCC diagnostic push
100 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
101 : : #if __GNUC__ >= 11
102 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
103 : : #endif
104 : : #endif
105 : :
106 : 21 : auto* target_ptr = reinterpret_cast<uint8_t*>(this);
107 : :
108 : 21 : std::memcpy(target_ptr, bytes.data() + kMagicNumberBeginSize + kVersionSize, sizeof(Tensor));
109 : :
110 : : #if defined(__GNUC__) && !defined(__clang__)
111 : : #pragma GCC diagnostic pop
112 : : #endif
113 : :
114 : 21 : data_ = const_cast<uint8_t*>(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(Tensor));
115 : 21 : is_owner_ = false;
116 : :
117 [ + + ]: 21 : if VUNLIKELY (bytes.size() != get_serialized_size()) {
118 : 1 : clear();
119 : 1 : return false;
120 : : }
121 : :
122 [ + + ]: 20 : if VUNLIKELY (rank_ > kMaxRank) {
123 : 1 : rank_ = kMaxRank;
124 : : }
125 : :
126 : 20 : element_size_ = element_size_of(dtype_);
127 : :
128 : 20 : return true;
129 : : }
130 : :
131 : 25 : bool Tensor::operator>>(Bytes& bytes) const noexcept {
132 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
133 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
134 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
135 : :
136 [ + + + + : 25 : if (bytes.empty() || bytes.size() != get_serialized_size()) {
+ + ]
137 : 24 : bytes = Bytes::create(get_serialized_size());
138 : :
139 [ - + ]: 24 : if VUNLIKELY (bytes.empty()) {
140 : 0 : return false;
141 : : }
142 : : }
143 : :
144 : 25 : std::memcpy(bytes.data(), &kMagicNumberBegin, kMagicNumberBeginSize);
145 : :
146 : 25 : std::memcpy(bytes.data() + kMagicNumberBeginSize, &kWireVersion, kVersionSize);
147 : :
148 : : // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
149 : 25 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize, this, sizeof(Tensor));
150 : :
151 : 25 : const auto data_offset = reinterpret_cast<const uint8_t*>(&data_) - reinterpret_cast<const uint8_t*>(this);
152 : 25 : const size_t data_pointer_size = sizeof(data_);
153 : 25 : std::memset(bytes.data() + kMagicNumberBeginSize + kVersionSize + data_offset, 0, data_pointer_size);
154 : :
155 [ + + + - : 25 : if VLIKELY (data_ != nullptr && size_ != 0) {
+ + ]
156 : 24 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(Tensor), data_, size_);
157 : : }
158 : :
159 : 25 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(Tensor) + size_, &kMagicNumberEnd,
160 : : kMagicNumberEndSize);
161 : :
162 : 25 : return true;
163 : : }
164 : :
165 : 30 : bool Tensor::check_valid(const Bytes& bytes) noexcept {
166 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
167 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
168 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
169 : :
170 [ + + ]: 30 : if VUNLIKELY (bytes.size() < kMagicNumberBeginSize + kVersionSize + sizeof(Tensor) + kMagicNumberEndSize) {
171 : 2 : return false;
172 : : }
173 : :
174 : 28 : uint32_t check_magic = 0;
175 : :
176 : 28 : std::memcpy(&check_magic, bytes.begin(), kMagicNumberBeginSize);
177 : :
178 [ + + ]: 28 : if VUNLIKELY (check_magic != kMagicNumberBegin) {
179 : 1 : return false;
180 : : }
181 : :
182 : 27 : uint32_t wire_version = 0;
183 : 27 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
184 : :
185 [ + + ]: 27 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
186 : 2 : return false;
187 : : }
188 : :
189 : 25 : std::memcpy(&check_magic, bytes.end() - kMagicNumberEndSize, kMagicNumberEndSize);
190 : :
191 [ + + ]: 25 : if VUNLIKELY (check_magic != kMagicNumberEnd) {
192 : 1 : return false;
193 : : }
194 : :
195 : 24 : return true;
196 : : }
197 : :
198 : 52 : size_t Tensor::get_serialized_size() const noexcept {
199 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
200 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
201 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
202 : :
203 : 52 : return kMagicNumberBeginSize + kVersionSize + sizeof(Tensor) + size_ + kMagicNumberEndSize;
204 : : }
205 : :
206 [ + + + - ]: 19 : bool Tensor::is_valid() const noexcept { return data_ != nullptr && size_ != 0; }
207 : :
208 : 10 : bool Tensor::shallow_copy(const Tensor& target) noexcept {
209 [ + + ]: 10 : if VUNLIKELY (this == &target) {
210 : 2 : return false;
211 : : }
212 : :
213 [ + + + - : 8 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
214 : 1 : const auto current = reinterpret_cast<uintptr_t>(data_);
215 : 1 : const auto source = reinterpret_cast<uintptr_t>(target.data_);
216 : :
217 [ + - + - : 1 : if VUNLIKELY (source >= current && source - current < size_) {
+ - ]
218 : 1 : return false;
219 : : }
220 : :
221 : 0 : Bytes::bytes_free(data_, size_);
222 : : }
223 : :
224 : 7 : header = target.header;
225 : :
226 : 7 : update_time_ns_ = target.update_time_ns_;
227 : 7 : num_elements_ = target.num_elements_;
228 : 7 : std::memcpy(name_, target.name_, sizeof(name_));
229 : 7 : std::memcpy(model_id_, target.model_id_, sizeof(model_id_));
230 : 7 : std::memcpy(layout_, target.layout_, sizeof(layout_));
231 : 7 : std::memcpy(shape_, target.shape_, sizeof(shape_));
232 : 7 : std::memcpy(strides_, target.strides_, sizeof(strides_));
233 : 7 : channel_ = target.channel_;
234 : 7 : freq_ = target.freq_;
235 : 7 : batch_size_ = target.batch_size_;
236 : 7 : quant_scale_ = target.quant_scale_;
237 : 7 : quant_zero_point_ = target.quant_zero_point_;
238 : 7 : dtype_ = target.dtype_;
239 : 7 : rank_ = target.rank_;
240 : 7 : device_ = target.device_;
241 : 7 : element_size_ = target.element_size_;
242 : 7 : reserved_buf_ = target.reserved_buf_;
243 : 7 : reserved_buf2_ = target.reserved_buf2_;
244 : 7 : reserved_buf3_ = target.reserved_buf3_;
245 : 7 : is_owner_ = false;
246 : 7 : data_ = target.data_;
247 : 7 : size_ = target.size_;
248 : :
249 : 7 : return true;
250 : : }
251 : :
252 : 6 : bool Tensor::deep_copy(const Tensor& target) noexcept {
253 [ + + + - : 6 : if VLIKELY (data_ && is_owner_ && target.data_ && size_ != 0 && size_ == target.size_) {
+ + + - +
+ + - + +
+ - + + ]
254 : 3 : const auto current = reinterpret_cast<uintptr_t>(data_);
255 : 3 : const auto source = reinterpret_cast<uintptr_t>(target.data_);
256 : :
257 [ + + + - : 3 : if VUNLIKELY (source >= current && source - current < size_) {
+ + ]
258 : 2 : return false;
259 : : }
260 : :
261 : 1 : header = target.header;
262 : :
263 : 1 : update_time_ns_ = target.update_time_ns_;
264 : 1 : num_elements_ = target.num_elements_;
265 : 1 : std::memcpy(name_, target.name_, sizeof(name_));
266 : 1 : std::memcpy(model_id_, target.model_id_, sizeof(model_id_));
267 : 1 : std::memcpy(layout_, target.layout_, sizeof(layout_));
268 : 1 : std::memcpy(shape_, target.shape_, sizeof(shape_));
269 : 1 : std::memcpy(strides_, target.strides_, sizeof(strides_));
270 : 1 : channel_ = target.channel_;
271 : 1 : freq_ = target.freq_;
272 : 1 : batch_size_ = target.batch_size_;
273 : 1 : quant_scale_ = target.quant_scale_;
274 : 1 : quant_zero_point_ = target.quant_zero_point_;
275 : 1 : dtype_ = target.dtype_;
276 : 1 : rank_ = target.rank_;
277 : 1 : device_ = target.device_;
278 : 1 : element_size_ = target.element_size_;
279 : 1 : reserved_buf_ = target.reserved_buf_;
280 : 1 : reserved_buf2_ = target.reserved_buf2_;
281 : 1 : reserved_buf3_ = target.reserved_buf3_;
282 : :
283 : 1 : std::memcpy(data_, target.data_, size_);
284 : :
285 : 1 : return true;
286 : : }
287 : :
288 [ - + ]: 3 : if VUNLIKELY (!shallow_copy(target)) {
289 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
290 : : }
291 : :
292 [ + - + - ]: 3 : if (data_ && size_ != 0) {
293 : 3 : auto* target_data = data_;
294 : 3 : data_ = Bytes::bytes_malloc(size_);
295 : :
296 [ - + ]: 3 : if VUNLIKELY (!data_) {
297 : 0 : size_ = 0;
298 : 0 : return false;
299 : : }
300 : :
301 : 3 : std::memcpy(data_, target_data, size_);
302 : 3 : is_owner_ = true;
303 : : }
304 : :
305 : 3 : return true;
306 : : }
307 : :
308 : 4 : bool Tensor::move_copy(Tensor& target) noexcept {
309 [ + + ]: 4 : if VUNLIKELY (!shallow_copy(target)) {
310 : 1 : return false;
311 : : }
312 : :
313 : 3 : is_owner_ = target.is_owner_;
314 : :
315 : 3 : target.update_time_ns_ = 0;
316 : 3 : target.num_elements_ = 0;
317 : 3 : std::memset(target.name_, 0, sizeof(target.name_));
318 : 3 : std::memset(target.model_id_, 0, sizeof(target.model_id_));
319 : 3 : std::memset(target.layout_, 0, sizeof(target.layout_));
320 : 3 : std::memset(target.shape_, 0, sizeof(target.shape_));
321 : 3 : std::memset(target.strides_, 0, sizeof(target.strides_));
322 : 3 : target.channel_ = 0;
323 : 3 : target.freq_ = 0;
324 : 3 : target.batch_size_ = 0;
325 : 3 : target.quant_scale_ = 0;
326 : 3 : target.quant_zero_point_ = 0;
327 : 3 : target.dtype_ = kDataUnknown;
328 : 3 : target.rank_ = 0;
329 : 3 : target.device_ = kDeviceCpu;
330 : 3 : target.element_size_ = 0;
331 : 3 : target.reserved_buf_ = 0;
332 : 3 : target.reserved_buf2_ = 0;
333 : 3 : target.reserved_buf3_ = 0;
334 : 3 : target.is_owner_ = false;
335 : 3 : target.data_ = nullptr;
336 : 3 : target.size_ = 0;
337 : :
338 : : #if defined(__GNUC__) && !defined(__clang__)
339 : : #pragma GCC diagnostic push
340 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
341 : : #if __GNUC__ >= 11
342 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
343 : : #endif
344 : : #endif
345 : :
346 : 3 : std::memset(&target.header, 0, sizeof(header));
347 : :
348 : : #if defined(__GNUC__) && !defined(__clang__)
349 : : #pragma GCC diagnostic pop
350 : : #endif
351 : :
352 : 3 : return true;
353 : : }
354 : :
355 : 53 : bool Tensor::create(size_t _size) noexcept {
356 [ + + ]: 53 : if VUNLIKELY (_size == 0) {
357 : 1 : return false;
358 : : }
359 : :
360 [ + + + - : 52 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
361 : 2 : Bytes::bytes_free(data_, size_);
362 : : }
363 : :
364 : 52 : data_ = Bytes::bytes_malloc(_size);
365 : :
366 [ - + ]: 52 : if VUNLIKELY (!data_) {
367 : 0 : size_ = 0;
368 : 0 : is_owner_ = false;
369 : 0 : return false;
370 : : }
371 : :
372 : 52 : size_ = _size;
373 : 52 : is_owner_ = true;
374 : :
375 : 52 : return true;
376 : : }
377 : :
378 : 5 : void Tensor::clear() noexcept {
379 [ + + + - : 5 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
380 : 4 : Bytes::bytes_free(data_, size_);
381 : : }
382 : :
383 : 5 : update_time_ns_ = 0;
384 : 5 : num_elements_ = 0;
385 : 5 : std::memset(name_, 0, sizeof(name_));
386 : 5 : std::memset(model_id_, 0, sizeof(model_id_));
387 : 5 : std::memset(layout_, 0, sizeof(layout_));
388 : 5 : std::memset(shape_, 0, sizeof(shape_));
389 : 5 : std::memset(strides_, 0, sizeof(strides_));
390 : 5 : channel_ = 0;
391 : 5 : freq_ = 0;
392 : 5 : batch_size_ = 0;
393 : 5 : quant_scale_ = 0;
394 : 5 : quant_zero_point_ = 0;
395 : 5 : dtype_ = kDataUnknown;
396 : 5 : rank_ = 0;
397 : 5 : device_ = kDeviceCpu;
398 : 5 : element_size_ = 0;
399 : 5 : is_owner_ = false;
400 : 5 : data_ = nullptr;
401 : 5 : size_ = 0;
402 : :
403 : : #if defined(__GNUC__) && !defined(__clang__)
404 : : #pragma GCC diagnostic push
405 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
406 : : #if __GNUC__ >= 11
407 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
408 : : #endif
409 : : #endif
410 : :
411 : 5 : std::memset(&header, 0, sizeof(header));
412 : :
413 : : #if defined(__GNUC__) && !defined(__clang__)
414 : : #pragma GCC diagnostic pop
415 : : #endif
416 : 5 : }
417 : :
418 : 7 : bool Tensor::shallow_copy(uint8_t* data, size_t size) noexcept {
419 [ + + + + : 7 : if VUNLIKELY (!data || size == 0) {
+ + ]
420 : 2 : return false;
421 : : }
422 : :
423 [ + + ]: 5 : if VUNLIKELY (data_ == data) {
424 : 1 : return false;
425 : : }
426 : :
427 [ + + + - : 4 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
428 : 1 : const auto current = reinterpret_cast<uintptr_t>(data_);
429 : 1 : const auto source = reinterpret_cast<uintptr_t>(data);
430 : :
431 [ + - + - : 1 : if VUNLIKELY (source >= current && source - current < size_) {
+ - ]
432 : 1 : return false;
433 : : }
434 : :
435 : 0 : Bytes::bytes_free(data_, size_);
436 : : }
437 : :
438 : 3 : is_owner_ = false;
439 : :
440 : 3 : data_ = data;
441 : 3 : size_ = size;
442 : :
443 : 3 : return true;
444 : : }
445 : :
446 : 21 : bool Tensor::deep_copy(uint8_t* data, size_t size) noexcept {
447 [ + + + + : 21 : if VUNLIKELY (!data || size == 0) {
+ + ]
448 : 2 : return false;
449 : : }
450 : :
451 [ + + ]: 19 : if (is_owner_) {
452 [ - + ]: 4 : if VUNLIKELY (!data_) {
453 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
454 : : }
455 : :
456 : 4 : const auto current = reinterpret_cast<uintptr_t>(data_);
457 : 4 : const auto source = reinterpret_cast<uintptr_t>(data);
458 : :
459 [ + + + + : 4 : if VUNLIKELY (source >= current && source - current < size_) {
+ + ]
460 : 2 : return false;
461 : : }
462 : :
463 [ + + - + : 2 : if VUNLIKELY (size_ != size && !create(size)) {
- + ]
464 : 0 : return false;
465 : : }
466 [ - + ]: 15 : } else if VUNLIKELY (!create(size)) {
467 : 0 : return false;
468 : : }
469 : :
470 : 17 : std::memcpy(data_, data, size);
471 : :
472 : 17 : return true;
473 : : }
474 : :
475 : 15 : bool Tensor::fill_data(uint8_t* data, size_t size) noexcept { return deep_copy(data, size); }
476 : :
477 : 3 : uint64_t Tensor::update_time_ns() const noexcept { return update_time_ns_; }
478 : :
479 : 25 : uint64_t Tensor::num_elements() const noexcept { return num_elements_; }
480 : :
481 : 9 : std::string_view Tensor::name() const noexcept { return {name_, ::strnlen(name_, sizeof(name_))}; }
482 : :
483 : 7 : std::string_view Tensor::model_id() const noexcept { return {model_id_, ::strnlen(model_id_, sizeof(model_id_))}; }
484 : :
485 : 8 : std::string_view Tensor::layout() const noexcept { return {layout_, ::strnlen(layout_, sizeof(layout_))}; }
486 : :
487 : 0 : const uint32_t* Tensor::shape() const noexcept { return shape_; }
488 : :
489 : 23 : uint32_t Tensor::shape_at(uint8_t dim) const noexcept {
490 [ + + ]: 23 : if VUNLIKELY (dim >= kMaxRank) {
491 : 1 : return 0;
492 : : }
493 : :
494 : 22 : return shape_[dim];
495 : : }
496 : :
497 : 0 : const uint32_t* Tensor::strides() const noexcept { return strides_; }
498 : :
499 : 18 : uint32_t Tensor::stride_at(uint8_t dim) const noexcept {
500 [ + + ]: 18 : if VUNLIKELY (dim >= kMaxRank) {
501 : 1 : return 0;
502 : : }
503 : :
504 : 17 : return strides_[dim];
505 : : }
506 : :
507 : 3 : uint32_t Tensor::channel() const noexcept { return channel_; }
508 : :
509 : 3 : uint32_t Tensor::freq() const noexcept { return freq_; }
510 : :
511 : 8 : uint32_t Tensor::batch_size() const noexcept { return batch_size_; }
512 : :
513 : 3 : float Tensor::quant_scale() const noexcept { return quant_scale_; }
514 : :
515 : 3 : int32_t Tensor::quant_zero_point() const noexcept { return quant_zero_point_; }
516 : :
517 : 27 : Tensor::DataType Tensor::dtype() const noexcept { return dtype_; }
518 : :
519 : 23 : uint8_t Tensor::rank() const noexcept { return rank_; }
520 : :
521 : 8 : Tensor::Device Tensor::device() const noexcept { return device_; }
522 : :
523 : 59 : uint8_t Tensor::element_size() const noexcept { return element_size_; }
524 : :
525 : 55 : const uint8_t* Tensor::data() const noexcept { return data_; }
526 : :
527 : 47 : size_t Tensor::size() const noexcept { return size_; }
528 : :
529 : 23 : bool Tensor::is_owner() const noexcept { return is_owner_; }
530 : :
531 : 2 : void Tensor::set_update_time_ns(uint64_t update_time_ns) noexcept { update_time_ns_ = update_time_ns; }
532 : :
533 : 8 : void Tensor::set_name(std::string_view name) noexcept {
534 : 8 : std::memset(name_, 0, sizeof(name_));
535 : :
536 : 8 : size_t copy_size = name.size();
537 : :
538 [ + + ]: 8 : if (copy_size >= sizeof(name_)) {
539 : 1 : copy_size = sizeof(name_) - 1;
540 : : }
541 : :
542 [ + - ]: 8 : if VLIKELY (copy_size != 0) {
543 : 8 : std::memcpy(name_, name.data(), copy_size);
544 : : }
545 : 8 : }
546 : :
547 : 6 : void Tensor::set_model_id(std::string_view model_id) noexcept {
548 : 6 : std::memset(model_id_, 0, sizeof(model_id_));
549 : :
550 : 6 : size_t copy_size = model_id.size();
551 : :
552 [ + + ]: 6 : if (copy_size >= sizeof(model_id_)) {
553 : 1 : copy_size = sizeof(model_id_) - 1;
554 : : }
555 : :
556 [ + - ]: 6 : if VLIKELY (copy_size != 0) {
557 : 6 : std::memcpy(model_id_, model_id.data(), copy_size);
558 : : }
559 : 6 : }
560 : :
561 : 7 : void Tensor::set_layout(std::string_view layout) noexcept {
562 : 7 : std::memset(layout_, 0, sizeof(layout_));
563 : :
564 : 7 : size_t copy_size = layout.size();
565 : :
566 [ + + ]: 7 : if (copy_size >= sizeof(layout_)) {
567 : 1 : copy_size = sizeof(layout_) - 1;
568 : : }
569 : :
570 [ + - ]: 7 : if VLIKELY (copy_size != 0) {
571 : 7 : std::memcpy(layout_, layout.data(), copy_size);
572 : : }
573 : 7 : }
574 : :
575 : 36 : void Tensor::set_shape(const uint32_t* shape, uint8_t rank) noexcept {
576 : 36 : std::memset(shape_, 0, sizeof(shape_));
577 : 36 : std::memset(strides_, 0, sizeof(strides_));
578 : :
579 [ + + + + : 36 : if VUNLIKELY (rank == 0 || !shape) {
+ + ]
580 : 2 : rank_ = 0;
581 : 2 : num_elements_ = 0;
582 : 2 : batch_size_ = 0;
583 : 2 : return;
584 : : }
585 : :
586 [ + + ]: 34 : if (rank > kMaxRank) {
587 : 1 : rank = kMaxRank;
588 : : }
589 : :
590 : 34 : uint64_t total = 1;
591 : 34 : bool has_zero = false;
592 : 34 : bool total_overflow = false;
593 : :
594 [ + + ]: 104 : for (uint8_t i = 0; i < rank; ++i) {
595 : 70 : shape_[i] = shape[i];
596 : :
597 [ + + ]: 70 : if (shape[i] == 0) {
598 : 1 : has_zero = true;
599 : 1 : total = 0;
600 [ + - + - ]: 69 : } else if (!has_zero && !total_overflow) {
601 [ + + ]: 69 : if VUNLIKELY (total > std::numeric_limits<uint64_t>::max() / shape[i]) {
602 : 2 : total_overflow = true;
603 : : } else {
604 : 67 : total *= shape[i];
605 : : }
606 : : }
607 : : }
608 : :
609 [ + + + + : 34 : if VUNLIKELY (total_overflow && !has_zero) {
+ + ]
610 : 1 : std::memset(shape_, 0, sizeof(shape_));
611 : 1 : std::memset(strides_, 0, sizeof(strides_));
612 : 1 : rank_ = 0;
613 : 1 : num_elements_ = 0;
614 : 1 : batch_size_ = 0;
615 : 1 : return;
616 : : }
617 : :
618 : 33 : uint64_t running = 1;
619 : :
620 [ + + ]: 98 : for (uint8_t i = rank; i > 0; --i) {
621 [ + + ]: 66 : if VUNLIKELY (running > std::numeric_limits<uint32_t>::max()) {
622 : 1 : std::memset(shape_, 0, sizeof(shape_));
623 : 1 : std::memset(strides_, 0, sizeof(strides_));
624 : 1 : rank_ = 0;
625 : 1 : num_elements_ = 0;
626 : 1 : batch_size_ = 0;
627 : 1 : return;
628 : : }
629 : :
630 : 65 : strides_[i - 1] = static_cast<uint32_t>(running);
631 : :
632 [ + + ]: 65 : if (shape_[i - 1] == 0) {
633 : 1 : running = 0;
634 [ + + ]: 64 : } else if (i > 1) {
635 : 32 : running *= shape_[i - 1];
636 : : }
637 : : }
638 : :
639 : 32 : rank_ = rank;
640 : 32 : num_elements_ = total;
641 : 32 : batch_size_ = shape_[0];
642 : : }
643 : :
644 : 5 : void Tensor::set_shape_at(uint8_t dim, uint32_t value) noexcept {
645 [ + + ]: 5 : if VUNLIKELY (dim >= kMaxRank) {
646 : 1 : return;
647 : : }
648 : :
649 : 4 : shape_[dim] = value;
650 : : }
651 : :
652 : 5 : void Tensor::set_stride_at(uint8_t dim, uint32_t value) noexcept {
653 [ + + ]: 5 : if VUNLIKELY (dim >= kMaxRank) {
654 : 1 : return;
655 : : }
656 : :
657 : 4 : strides_[dim] = value;
658 : : }
659 : :
660 : 2 : void Tensor::set_channel(uint32_t channel) noexcept { channel_ = channel; }
661 : :
662 : 2 : void Tensor::set_freq(uint32_t freq) noexcept { freq_ = freq; }
663 : :
664 : 1 : void Tensor::set_batch_size(uint32_t batch_size) noexcept { batch_size_ = batch_size; }
665 : :
666 : 3 : void Tensor::set_quant_scale(float quant_scale) noexcept { quant_scale_ = quant_scale; }
667 : :
668 : 3 : void Tensor::set_quant_zero_point(int32_t quant_zero_point) noexcept { quant_zero_point_ = quant_zero_point; }
669 : :
670 : 30 : void Tensor::set_dtype(DataType dtype) noexcept {
671 : 30 : dtype_ = dtype;
672 : 30 : element_size_ = element_size_of(dtype);
673 : 30 : }
674 : :
675 : 7 : void Tensor::set_device(Device device) noexcept { device_ = device; }
676 : :
677 : 64 : uint8_t Tensor::element_size_of(DataType dtype) noexcept {
678 : 64 : uint8_t target_size = 0;
679 : :
680 [ + + + + : 64 : if (dtype == kBool || dtype == kInt8 || dtype == kUint8) {
+ + ]
681 : 12 : target_size = 1;
682 [ + + + + : 52 : } else if (dtype == kInt16 || dtype == kUint16 || dtype == kFloat16 || dtype == kBfloat16) {
+ + + + ]
683 : 13 : target_size = 2;
684 [ + + + + : 39 : } else if (dtype == kInt32 || dtype == kUint32 || dtype == kFloat32) {
+ + ]
685 : 22 : target_size = 4;
686 [ + + + + : 17 : } else if (dtype == kInt64 || dtype == kUint64 || dtype == kFloat64) {
+ + ]
687 : 14 : target_size = 8;
688 : : }
689 : :
690 : 64 : return target_size;
691 : : }
692 : :
693 : : } // namespace zerocopy
694 : :
695 : : } // namespace vlink
|