-
Notifications
You must be signed in to change notification settings - Fork 5.9k
[Cpp API Compatibility] add storage API #77176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
1bbda30
65f8562
6eb3a1d
dfed0ad
bc3cb0f
a6e9f5f
e6fdea8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,13 +20,16 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <c10/core/MemoryFormat.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <c10/core/Scalar.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <c10/core/ScalarType.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <c10/core/Storage.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <c10/core/SymInt.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <c10/core/TensorOptions.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <utils/int_array_ref_conversion.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include <utils/scalar_type_conversion.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "paddle/common/layout.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "paddle/phi/api/include/api.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "paddle/phi/api/include/tensor.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "paddle/phi/common/place.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #include "paddle/phi/core/dense_tensor.h" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace at { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using PaddleTensor = paddle::Tensor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -208,6 +211,35 @@ class PADDLE_API TensorBase { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool defined() const { return tensor_.defined(); } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int64_t storage_offset() const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Paddle DenseTensor stores offset in meta_.offset (in bytes) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // We need to convert to element offset | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto dense_tensor = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (dense_tensor) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size_t byte_offset = dense_tensor->meta().offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| size_t element_size = SizeOf(tensor_.dtype()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return element_size > 0 ? static_cast<int64_t>(byte_offset / element_size) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| c10::SymInt sym_storage_offset() const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return c10::SymInt(storage_offset()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool has_storage() const { return tensor_.defined(); } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const Storage storage() const { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Storage( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl())->Holder()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+235
to
+236
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Storage( | |
| std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl())->Holder()); | |
| if (!tensor_.defined()) { | |
| // Undefined tensor: return an empty Storage | |
| return Storage(); | |
| } | |
| auto impl = tensor_.impl(); | |
| if (!impl) { | |
| // No underlying implementation: return an empty Storage | |
| return Storage(); | |
| } | |
| auto dense_tensor = | |
| std::dynamic_pointer_cast<phi::DenseTensor>(impl); | |
| if (!dense_tensor) { | |
| // Not backed by a DenseTensor: return an empty Storage | |
| return Storage(); | |
| } | |
| auto holder = dense_tensor->Holder(); | |
| if (!holder) { | |
| // No allocation holder: return an empty Storage | |
| return Storage(); | |
| } | |
| return Storage(holder); |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The is_alias_of method doesn't check if the tensors are defined before accessing their storage. If either tensor is undefined, calling storage() will likely crash. Add validation to check if both tensors are defined before comparing their storage allocations.
| bool is_alias_of(const at::TensorBase& other) const { | |
| bool is_alias_of(const at::TensorBase& other) const { | |
| if (!this->defined() || !other.defined()) { | |
| // Undefined tensors cannot be aliases of each other. | |
| return false; | |
| } |
Copilot
AI
Jan 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing test coverage for TensorBase storage-related methods. The new methods storage_offset(), sym_storage_offset(), has_storage(), storage(), and is_alias_of() added to TensorBase lack dedicated test coverage that validates edge cases like undefined tensors, non-DenseTensor implementations, and error conditions. Consider adding specific tests for these methods.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| // Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 同下,添加下声明
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 已添加 |
||
| // #The file has been adapted from pytorch project | ||
| // #Licensed under BSD-style license - | ||
| // https://github.com/pytorch/pytorch/blob/main/LICENSE | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <cstddef> | ||
| #include <functional> | ||
| #include <memory> | ||
| #include <utility> | ||
|
|
||
| #include "paddle/phi/common/place.h" | ||
| #include "paddle/phi/core/allocator.h" | ||
|
|
||
| namespace c10 { | ||
|
|
||
| // Deleter function pointer type (compatible with LibTorch) | ||
| using DeleterFnPtr = void (*)(void*); | ||
|
|
||
| // DataPtr class compatible with LibTorch's c10::DataPtr | ||
| // Wraps a pointer with associated device and deleter | ||
| class DataPtr { | ||
| public: | ||
| DataPtr() : ptr_(nullptr), device_(phi::CPUPlace()) {} | ||
|
|
||
| explicit DataPtr(void* data, phi::Place device = phi::CPUPlace()) | ||
| : ptr_(data), device_(device) {} | ||
|
|
||
| DataPtr(void* data, | ||
| void* ctx, | ||
| DeleterFnPtr ctx_deleter, | ||
| phi::Place device = phi::CPUPlace()) | ||
| : ptr_(data), ctx_(ctx), deleter_(ctx_deleter), device_(device) {} | ||
|
|
||
| // Construct from phi::Allocation | ||
| explicit DataPtr(const std::shared_ptr<phi::Allocation>& alloc) | ||
| : ptr_(alloc ? alloc->ptr() : nullptr), | ||
| device_(alloc ? alloc->place() : phi::CPUPlace()), | ||
| allocation_(alloc) {} | ||
|
|
||
| DataPtr(const DataPtr&) = default; | ||
| DataPtr& operator=(const DataPtr&) = default; | ||
| DataPtr(DataPtr&&) = default; | ||
| DataPtr& operator=(DataPtr&&) = default; | ||
|
|
||
| void* get() const { return ptr_; } | ||
|
|
||
| void* operator->() const { return ptr_; } | ||
|
|
||
| explicit operator bool() const { return ptr_ != nullptr; } | ||
|
|
||
| phi::Place device() const { return device_; } | ||
|
|
||
| DeleterFnPtr get_deleter() const { return deleter_; } | ||
|
|
||
| void* get_context() const { return ctx_; } | ||
|
|
||
| void clear() { | ||
| ptr_ = nullptr; | ||
| ctx_ = nullptr; | ||
| deleter_ = nullptr; | ||
| allocation_.reset(); | ||
| } | ||
|
Comment on lines
+72
to
+77
|
||
|
|
||
| // Get the underlying allocation (if available) | ||
| std::shared_ptr<phi::Allocation> allocation() const { return allocation_; } | ||
|
|
||
| private: | ||
| void* ptr_ = nullptr; | ||
| void* ctx_ = nullptr; | ||
| DeleterFnPtr deleter_ = nullptr; | ||
| phi::Place device_; | ||
| std::shared_ptr<phi::Allocation> allocation_; | ||
| }; | ||
|
Comment on lines
+34
to
+88
|
||
|
|
||
| inline bool operator==(const DataPtr& dp, std::nullptr_t) noexcept { | ||
| return !dp; | ||
| } | ||
|
|
||
| inline bool operator==(std::nullptr_t, const DataPtr& dp) noexcept { | ||
| return !dp; | ||
| } | ||
|
|
||
| inline bool operator!=(const DataPtr& dp, std::nullptr_t) noexcept { | ||
| return static_cast<bool>(dp); | ||
| } | ||
|
|
||
| inline bool operator!=(std::nullptr_t, const DataPtr& dp) noexcept { | ||
| return static_cast<bool>(dp); | ||
| } | ||
|
|
||
| } // namespace c10 | ||
|
|
||
| namespace at { | ||
| using DataPtr = c10::DataPtr; | ||
| } // namespace at | ||
|
Comment on lines
+34
to
+110
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
storage_offset()method doesn't validate if the dynamic_pointer_cast to DenseTensor succeeds. If the tensor's impl is not a DenseTensor, the method will crash when trying to accessdense_tensor->meta(). Add a check and return 0 if the cast fails.