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 : 111 : 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 : 111 : }
43 : :
44 : 116 : Tensor::~Tensor() noexcept {
45 [ + + + - : 116 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
46 : 52 : Bytes::bytes_free(data_, size_);
47 : : }
48 : 116 : }
49 : :
50 : 1 : Tensor::Tensor(const Tensor& target) noexcept { deep_copy(target); }
51 : :
52 : 4 : 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 : 28 : 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 [ + + ]: 28 : if VUNLIKELY (bytes.empty()) {
80 : 1 : return false;
81 : : }
82 : :
83 [ + + ]: 27 : if VUNLIKELY (!check_valid(bytes)) {
84 : 2 : return false;
85 : : }
86 : :
87 : 25 : uint32_t wire_version = 0;
88 : 25 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
89 : :
90 [ - + ]: 25 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
91 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
92 : : }
93 : :
94 [ + + + - : 25 : 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 : 25 : auto* target_ptr = reinterpret_cast<uint8_t*>(this);
107 : :
108 : 25 : 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 : 25 : data_ = const_cast<uint8_t*>(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(Tensor));
115 : 25 : is_owner_ = false;
116 : :
117 [ + + ]: 25 : if VUNLIKELY (bytes.size() != get_serialized_size()) {
118 : 1 : clear();
119 : 1 : return false;
120 : : }
121 : :
122 [ + + ]: 24 : if VUNLIKELY (rank_ > kMaxRank) {
123 : 1 : rank_ = kMaxRank;
124 : : }
125 : :
126 : 24 : element_size_ = element_size_of(dtype_);
127 : :
128 : 24 : return true;
129 : : }
130 : :
131 : 29 : 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 [ + + + + : 29 : if (bytes.empty() || bytes.size() != get_serialized_size()) {
+ + ]
137 : 28 : bytes = Bytes::create(get_serialized_size());
138 : :
139 [ - + ]: 28 : if VUNLIKELY (bytes.empty()) {
140 : 0 : return false;
141 : : }
142 : : }
143 : :
144 : 29 : std::memcpy(bytes.data(), &kMagicNumberBegin, kMagicNumberBeginSize);
145 : :
146 : 29 : std::memcpy(bytes.data() + kMagicNumberBeginSize, &kWireVersion, kVersionSize);
147 : :
148 : : // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
149 : 29 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize, this, sizeof(Tensor));
150 : :
151 : 29 : const auto data_offset = reinterpret_cast<const uint8_t*>(&data_) - reinterpret_cast<const uint8_t*>(this);
152 : 29 : const size_t data_pointer_size = sizeof(data_);
153 : 29 : std::memset(bytes.data() + kMagicNumberBeginSize + kVersionSize + data_offset, 0, data_pointer_size);
154 : :
155 [ + + + - : 29 : if VLIKELY (data_ != nullptr && size_ != 0) {
+ + ]
156 : 28 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(Tensor), data_, size_);
157 : : }
158 : :
159 : 29 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(Tensor) + size_, &kMagicNumberEnd,
160 : : kMagicNumberEndSize);
161 : :
162 : 29 : return true;
163 : : }
164 : :
165 : 34 : 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 [ + + ]: 34 : if VUNLIKELY (bytes.size() < kMagicNumberBeginSize + kVersionSize + sizeof(Tensor) + kMagicNumberEndSize) {
171 : 2 : return false;
172 : : }
173 : :
174 : 32 : uint32_t check_magic = 0;
175 : :
176 : 32 : std::memcpy(&check_magic, bytes.begin(), kMagicNumberBeginSize);
177 : :
178 [ + + ]: 32 : if VUNLIKELY (check_magic != kMagicNumberBegin) {
179 : 1 : return false;
180 : : }
181 : :
182 : 31 : uint32_t wire_version = 0;
183 : 31 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
184 : :
185 [ + + ]: 31 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
186 : 2 : return false;
187 : : }
188 : :
189 : 29 : std::memcpy(&check_magic, bytes.end() - kMagicNumberEndSize, kMagicNumberEndSize);
190 : :
191 [ + + ]: 29 : if VUNLIKELY (check_magic != kMagicNumberEnd) {
192 : 1 : return false;
193 : : }
194 : :
195 : 28 : return true;
196 : : }
197 : :
198 : 60 : 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 : 60 : return kMagicNumberBeginSize + kVersionSize + sizeof(Tensor) + size_ + kMagicNumberEndSize;
204 : : }
205 : :
206 [ + + + - ]: 19 : bool Tensor::is_valid() const noexcept { return data_ != nullptr && size_ != 0; }
207 : :
208 : 16 : bool Tensor::shallow_copy(const Tensor& target) noexcept {
209 [ + + ]: 16 : if VUNLIKELY (this == &target) {
210 : 2 : return false;
211 : : }
212 : :
213 [ + + + - : 14 : 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 : 13 : header = target.header;
225 : :
226 : 13 : update_time_ns_ = target.update_time_ns_;
227 : 13 : num_elements_ = target.num_elements_;
228 : 13 : std::memcpy(name_, target.name_, sizeof(name_));
229 : 13 : std::memcpy(model_id_, target.model_id_, sizeof(model_id_));
230 : 13 : std::memcpy(layout_, target.layout_, sizeof(layout_));
231 : 13 : std::memcpy(shape_, target.shape_, sizeof(shape_));
232 : 13 : std::memcpy(strides_, target.strides_, sizeof(strides_));
233 : 13 : channel_ = target.channel_;
234 : 13 : freq_ = target.freq_;
235 : 13 : batch_size_ = target.batch_size_;
236 : 13 : quant_scale_ = target.quant_scale_;
237 : 13 : quant_zero_point_ = target.quant_zero_point_;
238 : 13 : dtype_ = target.dtype_;
239 : 13 : rank_ = target.rank_;
240 : 13 : device_ = target.device_;
241 : 13 : element_size_ = target.element_size_;
242 : 13 : reserved_buf_ = target.reserved_buf_;
243 : 13 : reserved_buf2_ = target.reserved_buf2_;
244 : 13 : reserved_buf3_ = target.reserved_buf3_;
245 : 13 : is_owner_ = false;
246 : 13 : data_ = target.data_;
247 : 13 : size_ = target.size_;
248 : :
249 : 13 : return true;
250 : : }
251 : :
252 : 9 : bool Tensor::deep_copy(const Tensor& target) noexcept {
253 [ + + + - : 9 : 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 [ - + ]: 6 : if VUNLIKELY (!shallow_copy(target)) {
289 : : return false; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
290 : : }
291 : :
292 [ + - + - ]: 6 : if (data_ && size_ != 0) {
293 : 6 : auto* target_data = data_;
294 : 6 : data_ = Bytes::bytes_malloc(size_);
295 : :
296 [ - + ]: 6 : if VUNLIKELY (!data_) {
297 : 0 : size_ = 0;
298 : 0 : return false;
299 : : }
300 : :
301 : 6 : std::memcpy(data_, target_data, size_);
302 : 6 : is_owner_ = true;
303 : : }
304 : :
305 : 6 : return true;
306 : : }
307 : :
308 : 7 : bool Tensor::move_copy(Tensor& target) noexcept {
309 [ + + ]: 7 : if VUNLIKELY (!shallow_copy(target)) {
310 : 1 : return false;
311 : : }
312 : :
313 : 6 : is_owner_ = target.is_owner_;
314 : :
315 : 6 : target.update_time_ns_ = 0;
316 : 6 : target.num_elements_ = 0;
317 : 6 : std::memset(target.name_, 0, sizeof(target.name_));
318 : 6 : std::memset(target.model_id_, 0, sizeof(target.model_id_));
319 : 6 : std::memset(target.layout_, 0, sizeof(target.layout_));
320 : 6 : std::memset(target.shape_, 0, sizeof(target.shape_));
321 : 6 : std::memset(target.strides_, 0, sizeof(target.strides_));
322 : 6 : target.channel_ = 0;
323 : 6 : target.freq_ = 0;
324 : 6 : target.batch_size_ = 0;
325 : 6 : target.quant_scale_ = 0;
326 : 6 : target.quant_zero_point_ = 0;
327 : 6 : target.dtype_ = kDataUnknown;
328 : 6 : target.rank_ = 0;
329 : 6 : target.device_ = kDeviceCpu;
330 : 6 : target.element_size_ = 0;
331 : 6 : target.reserved_buf_ = 0;
332 : 6 : target.reserved_buf2_ = 0;
333 : 6 : target.reserved_buf3_ = 0;
334 : 6 : target.is_owner_ = false;
335 : 6 : target.data_ = nullptr;
336 : 6 : 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 : 6 : std::memset(&target.header, 0, sizeof(header));
347 : :
348 : : #if defined(__GNUC__) && !defined(__clang__)
349 : : #pragma GCC diagnostic pop
350 : : #endif
351 : :
352 : 6 : return true;
353 : : }
354 : :
355 : 54 : bool Tensor::create(size_t _size) noexcept {
356 [ + + ]: 54 : if VUNLIKELY (_size == 0) {
357 : 1 : return false;
358 : : }
359 : :
360 [ + + + - : 53 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
361 : 2 : Bytes::bytes_free(data_, size_);
362 : : }
363 : :
364 : 53 : data_ = Bytes::bytes_malloc(_size);
365 : :
366 [ - + ]: 53 : if VUNLIKELY (!data_) {
367 : 0 : size_ = 0;
368 : 0 : is_owner_ = false;
369 : 0 : return false;
370 : : }
371 : :
372 : 53 : size_ = _size;
373 : 53 : is_owner_ = true;
374 : :
375 : 53 : 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 : 27 : uint64_t Tensor::num_elements() const noexcept { return num_elements_; }
480 : :
481 : 14 : std::string_view Tensor::name() const noexcept { return {name_, ::strnlen(name_, sizeof(name_))}; }
482 : :
483 : 12 : std::string_view Tensor::model_id() const noexcept { return {model_id_, ::strnlen(model_id_, sizeof(model_id_))}; }
484 : :
485 : 13 : std::string_view Tensor::layout() const noexcept { return {layout_, ::strnlen(layout_, sizeof(layout_))}; }
486 : :
487 : 3 : const uint32_t* Tensor::shape() const noexcept { return shape_; }
488 : :
489 : 26 : uint32_t Tensor::shape_at(uint8_t dim) const noexcept {
490 [ + + ]: 26 : if VUNLIKELY (dim >= kMaxRank) {
491 : 1 : return 0;
492 : : }
493 : :
494 : 25 : return shape_[dim];
495 : : }
496 : :
497 : 0 : const uint32_t* Tensor::strides() const noexcept { return strides_; }
498 : :
499 : 21 : uint32_t Tensor::stride_at(uint8_t dim) const noexcept {
500 [ + + ]: 21 : if VUNLIKELY (dim >= kMaxRank) {
501 : 1 : return 0;
502 : : }
503 : :
504 : 20 : 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 : 25 : 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 : 56 : const uint8_t* Tensor::data() const noexcept { return data_; }
526 : :
527 : 48 : size_t Tensor::size() const noexcept { return size_; }
528 : :
529 : 30 : 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 : 11 : void Tensor::set_name(std::string_view name) noexcept {
534 : 11 : size_t copy_size = name.size();
535 : :
536 [ + + ]: 11 : if (copy_size >= sizeof(name_)) {
537 : 1 : copy_size = sizeof(name_) - 1;
538 : : }
539 : :
540 [ + - ]: 11 : if VLIKELY (copy_size != 0) {
541 : 11 : std::memmove(name_, name.data(), copy_size);
542 : : }
543 : :
544 : 11 : std::memset(name_ + copy_size, 0, sizeof(name_) - copy_size);
545 : 11 : }
546 : :
547 : 9 : void Tensor::set_model_id(std::string_view model_id) noexcept {
548 : 9 : size_t copy_size = model_id.size();
549 : :
550 [ + + ]: 9 : if (copy_size >= sizeof(model_id_)) {
551 : 1 : copy_size = sizeof(model_id_) - 1;
552 : : }
553 : :
554 [ + - ]: 9 : if VLIKELY (copy_size != 0) {
555 : 9 : std::memmove(model_id_, model_id.data(), copy_size);
556 : : }
557 : :
558 : 9 : std::memset(model_id_ + copy_size, 0, sizeof(model_id_) - copy_size);
559 : 9 : }
560 : :
561 : 10 : void Tensor::set_layout(std::string_view layout) noexcept {
562 : 10 : size_t copy_size = layout.size();
563 : :
564 [ + + ]: 10 : if (copy_size >= sizeof(layout_)) {
565 : 1 : copy_size = sizeof(layout_) - 1;
566 : : }
567 : :
568 [ + - ]: 10 : if VLIKELY (copy_size != 0) {
569 : 10 : std::memmove(layout_, layout.data(), copy_size);
570 : : }
571 : :
572 : 10 : std::memset(layout_ + copy_size, 0, sizeof(layout_) - copy_size);
573 : 10 : }
574 : :
575 : 39 : void Tensor::set_shape(const uint32_t* shape, uint8_t rank) noexcept {
576 [ + + + + : 39 : if VUNLIKELY (rank == 0 || !shape) {
+ + ]
577 : 2 : std::memset(shape_, 0, sizeof(shape_));
578 : 2 : std::memset(strides_, 0, sizeof(strides_));
579 : 2 : rank_ = 0;
580 : 2 : num_elements_ = 0;
581 : 2 : batch_size_ = 0;
582 : 2 : return;
583 : : }
584 : :
585 [ + + ]: 37 : if (rank > kMaxRank) {
586 : 1 : rank = kMaxRank;
587 : : }
588 : :
589 : 37 : std::memmove(shape_, shape, rank * sizeof(shape_[0]));
590 : 37 : std::memset(shape_ + rank, 0, (kMaxRank - rank) * sizeof(shape_[0]));
591 : 37 : std::memset(strides_, 0, sizeof(strides_));
592 : :
593 : 37 : uint64_t total = 1;
594 : 37 : bool has_zero = false;
595 : 37 : bool total_overflow = false;
596 : :
597 [ + + ]: 112 : for (uint8_t i = 0; i < rank; ++i) {
598 [ + + ]: 75 : if (shape_[i] == 0) {
599 : 1 : has_zero = true;
600 : 1 : total = 0;
601 [ + - + - ]: 74 : } else if (!has_zero && !total_overflow) {
602 [ + + ]: 74 : if VUNLIKELY (total > std::numeric_limits<uint64_t>::max() / shape_[i]) {
603 : 2 : total_overflow = true;
604 : : } else {
605 : 72 : total *= shape_[i];
606 : : }
607 : : }
608 : : }
609 : :
610 [ + + + + : 37 : if VUNLIKELY (total_overflow && !has_zero) {
+ + ]
611 : 1 : std::memset(shape_, 0, sizeof(shape_));
612 : 1 : std::memset(strides_, 0, sizeof(strides_));
613 : 1 : rank_ = 0;
614 : 1 : num_elements_ = 0;
615 : 1 : batch_size_ = 0;
616 : 1 : return;
617 : : }
618 : :
619 : 36 : uint64_t running = 1;
620 : :
621 [ + + ]: 106 : for (uint8_t i = rank; i > 0; --i) {
622 [ + + ]: 71 : if VUNLIKELY (running > std::numeric_limits<uint32_t>::max()) {
623 : 1 : std::memset(shape_, 0, sizeof(shape_));
624 : 1 : std::memset(strides_, 0, sizeof(strides_));
625 : 1 : rank_ = 0;
626 : 1 : num_elements_ = 0;
627 : 1 : batch_size_ = 0;
628 : 1 : return;
629 : : }
630 : :
631 : 70 : strides_[i - 1] = static_cast<uint32_t>(running);
632 : :
633 [ + + ]: 70 : if (shape_[i - 1] == 0) {
634 : 1 : running = 0;
635 [ + + ]: 69 : } else if (i > 1) {
636 : 34 : running *= shape_[i - 1];
637 : : }
638 : : }
639 : :
640 : 35 : rank_ = rank;
641 : 35 : num_elements_ = total;
642 : 35 : batch_size_ = shape_[0];
643 : : }
644 : :
645 : 5 : void Tensor::set_shape_at(uint8_t dim, uint32_t value) noexcept {
646 [ + + ]: 5 : if VUNLIKELY (dim >= kMaxRank) {
647 : 1 : return;
648 : : }
649 : :
650 : 4 : shape_[dim] = value;
651 : : }
652 : :
653 : 5 : void Tensor::set_stride_at(uint8_t dim, uint32_t value) noexcept {
654 [ + + ]: 5 : if VUNLIKELY (dim >= kMaxRank) {
655 : 1 : return;
656 : : }
657 : :
658 : 4 : strides_[dim] = value;
659 : : }
660 : :
661 : 2 : void Tensor::set_channel(uint32_t channel) noexcept { channel_ = channel; }
662 : :
663 : 2 : void Tensor::set_freq(uint32_t freq) noexcept { freq_ = freq; }
664 : :
665 : 1 : void Tensor::set_batch_size(uint32_t batch_size) noexcept { batch_size_ = batch_size; }
666 : :
667 : 3 : void Tensor::set_quant_scale(float quant_scale) noexcept { quant_scale_ = quant_scale; }
668 : :
669 : 3 : void Tensor::set_quant_zero_point(int32_t quant_zero_point) noexcept { quant_zero_point_ = quant_zero_point; }
670 : :
671 : 30 : void Tensor::set_dtype(DataType dtype) noexcept {
672 : 30 : dtype_ = dtype;
673 : 30 : element_size_ = element_size_of(dtype);
674 : 30 : }
675 : :
676 : 7 : void Tensor::set_device(Device device) noexcept { device_ = device; }
677 : :
678 : 68 : uint8_t Tensor::element_size_of(DataType dtype) noexcept {
679 : 68 : uint8_t target_size = 0;
680 : :
681 [ + + + + : 68 : if (dtype == kBool || dtype == kInt8 || dtype == kUint8) {
+ + ]
682 : 12 : target_size = 1;
683 [ + + + + : 56 : } else if (dtype == kInt16 || dtype == kUint16 || dtype == kFloat16 || dtype == kBfloat16) {
+ + + + ]
684 : 13 : target_size = 2;
685 [ + + + + : 43 : } else if (dtype == kInt32 || dtype == kUint32 || dtype == kFloat32) {
+ + ]
686 : 22 : target_size = 4;
687 [ + + + + : 21 : } else if (dtype == kInt64 || dtype == kUint64 || dtype == kFloat64) {
+ + ]
688 : 14 : target_size = 8;
689 : : }
690 : :
691 : 68 : return target_size;
692 : : }
693 : :
694 : : } // namespace zerocopy
695 : :
696 : : } // namespace vlink
|