diff --git a/paddle/pten/core/tensor_meta.h b/paddle/pten/core/tensor_meta.h index b94552fd8016c8ce95a8013f6c04da442221c52a..85afc3f2f01ea803a4cbd71221f741d862367033 100644 --- a/paddle/pten/core/tensor_meta.h +++ b/paddle/pten/core/tensor_meta.h @@ -54,7 +54,7 @@ struct DenseTensorMeta { /// marked with `const` are expected to remain unchanged. const bool is_scalar{false}; DDim dims; - const DataType type{DataType::FLOAT32}; + const DataType type{DataType::UNDEFINED}; const DataLayout layout{DataLayout::NCHW}; LoD lod; }; diff --git a/paddle/pten/tests/CMakeLists.txt b/paddle/pten/tests/CMakeLists.txt index 21ce2f74df9451d11ab9479252beccc54623f958..27e76c87c6c0b7d94a3a7f5cb977d76ef81f5bb8 100644 --- a/paddle/pten/tests/CMakeLists.txt +++ b/paddle/pten/tests/CMakeLists.txt @@ -1,3 +1,6 @@ +add_subdirectory(core) +add_subdirectory(utils) + cc_test(pten_backend_test SRCS backend_test.cc DEPS gtest) cc_test(pten_data_layout_test SRCS data_layout_test.cc DEPS gtest) cc_test(pten_data_type_test SRCS data_type_test.cc DEPS gtest) diff --git a/paddle/pten/tests/core/CMakeLists.txt b/paddle/pten/tests/core/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..34888200b2f1918ee76428c274fa8c0b9216a9ac --- /dev/null +++ b/paddle/pten/tests/core/CMakeLists.txt @@ -0,0 +1,3 @@ +cc_test(test_allocator SRCS test_allocator.cc DEPS tensor_base) +cc_test(test_storage SRCS test_storage.cc DEPS tensor_base) +cc_test(test_dense_tensor SRCS test_dense_tensor.cc DEPS dense_tensor) diff --git a/paddle/pten/tests/core/allocator.h b/paddle/pten/tests/core/allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..053e8ba7b382b6527d2148c45ab928e92f1a3f8e --- /dev/null +++ b/paddle/pten/tests/core/allocator.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2021 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. */ + +#pragma once + +#include + +#include "paddle/pten/core/allocator.h" + +namespace pten { +namespace tests { + +class HostAllocatorSample : public pten::RawAllocator { + public: + using Place = paddle::platform::Place; + void* Allocate(size_t bytes_size) override { + return ::operator new(bytes_size); + } + void Deallocate(void* ptr, size_t bytes_size) override { + return ::operator delete(ptr); + } + const Place& place() const override { return place_; } + + private: + Place place_{paddle::platform::CPUPlace()}; +}; + +class FancyAllocator : public pten::Allocator { + public: + static void Delete(void* data) { ::operator delete(data); } + + Allocation Allocate(size_t bytes_size) override { + void* data = ::operator new(bytes_size); + return Allocation(data, data, &Delete, paddle::platform::CPUPlace()); + } +}; + +template +struct CustomAllocator { + using value_type = T; + using Allocator = pten::RawAllocator; + + explicit CustomAllocator(const std::shared_ptr& a) noexcept + : alloc_(a) {} + + CustomAllocator(const CustomAllocator&) noexcept = default; + T* allocate(std::size_t n) { + return static_cast(alloc_->Allocate(n * sizeof(T))); + } + void deallocate(T* p, std::size_t n) { + return alloc_->Deallocate(p, sizeof(T) * n); + } + + template + friend bool operator==(const CustomAllocator&, + const CustomAllocator&) noexcept; + template + friend bool operator!=(const CustomAllocator&, + const CustomAllocator&) noexcept; + + private: + std::shared_ptr alloc_; +}; + +template +inline bool operator==(const CustomAllocator& lhs, + const CustomAllocator& rhs) noexcept { + return &lhs.alloc_ == &rhs.alloc_; +} + +template +inline bool operator!=(const CustomAllocator& lhs, + const CustomAllocator& rhs) noexcept { + return &lhs.alloc_ != &rhs.alloc_; +} + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/core/random.h b/paddle/pten/tests/core/random.h new file mode 100644 index 0000000000000000000000000000000000000000..4e2e55162d3a4d4fb0cd2586dbeb54ba512d44ad --- /dev/null +++ b/paddle/pten/tests/core/random.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2021 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. */ + +#pragma once + +#include +#include + +namespace pten { +namespace tests { + +template ::value>::type> +class RandomGenerator { + using distribution_type = + typename std::conditional::value, + std::uniform_int_distribution, + std::uniform_real_distribution>::type; + + std::default_random_engine engine; + distribution_type distribution; + + public: + auto operator()() -> decltype(distribution(engine)) { + return distribution(engine); + } +}; + +template +auto make_generator(Container const&) -> decltype(RandomGenerator()) { + return RandomGenerator(); +} + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/core/test_allocator.cc b/paddle/pten/tests/core/test_allocator.cc new file mode 100644 index 0000000000000000000000000000000000000000..c509d8bd20a01243eda2bb7be13166ca8d540d5b --- /dev/null +++ b/paddle/pten/tests/core/test_allocator.cc @@ -0,0 +1,91 @@ +/* Copyright (c) 2021 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. */ + +#include +#include + +#include "gtest/gtest.h" +#include "paddle/fluid/framework/generator.h" +#include "paddle/pten/tests/core/allocator.h" +#include "paddle/pten/tests/core/random.h" +#include "paddle/pten/tests/core/timer.h" + +namespace pten { +namespace tests { + +template +bool host_allocator_test(size_t vector_size) { + std::vector src(vector_size); + std::generate(src.begin(), src.end(), make_generator(src)); + std::vector> dst( + src.begin(), + src.end(), + CustomAllocator(std::make_shared())); + return std::equal(src.begin(), src.end(), dst.begin()); +} + +TEST(raw_allocator, host) { + CHECK(host_allocator_test(1000)); + CHECK(host_allocator_test(1000)); + CHECK(host_allocator_test(1000)); +} + +class StorageRawAlloc { + public: + StorageRawAlloc(const std::shared_ptr& a, size_t size) + : alloc_(a) { + data_ = alloc_->Allocate(size); + } + ~StorageRawAlloc() { alloc_->Deallocate(data_, size); } + + private: + void* data_; + size_t size; + std::shared_ptr alloc_; +}; + +class StorageFancyAlloc { + public: + StorageFancyAlloc(const std::shared_ptr& a, size_t size) + : alloc_(a), allocation_(a->Allocate(size)) {} + + private: + std::shared_ptr alloc_; + Allocation allocation_; +}; + +TEST(benchmark, allocator) { + std::shared_ptr raw_allocator(new HostAllocatorSample); + std::shared_ptr fancy_allocator(new FancyAllocator); + const size_t cycles = 100; + Timer timer; + double t1{}, t2{}; + for (size_t i = 0; i < cycles; ++i) { + timer.tic(); + for (size_t i = 0; i < cycles; ++i) { + StorageRawAlloc(raw_allocator, i * 100); + } + t1 += timer.toc(); + timer.tic(); + for (size_t i = 0; i < cycles; ++i) { + StorageFancyAlloc(fancy_allocator, i * 100); + } + t2 += timer.toc(); + } + std::cout << "The cost of raw alloc is " << t1 << "ms.\n"; + std::cout << "The cost of fancy alloc with place is " << t2 << "ms.\n"; +} + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/core/test_dense_tensor.cc b/paddle/pten/tests/core/test_dense_tensor.cc new file mode 100644 index 0000000000000000000000000000000000000000..12476373f8d98c7e349a5d82959a570f3df58e2c --- /dev/null +++ b/paddle/pten/tests/core/test_dense_tensor.cc @@ -0,0 +1,127 @@ +/* Copyright (c) 2021 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. */ + +#include "gtest/gtest.h" + +#include "paddle/pten/core/dense_tensor.h" +#include "paddle/pten/tests/core/allocator.h" + +namespace pten { +namespace tests { + +TEST(dense_tensor, meta) { + const DDim dims({1, 2}); + const DataType dtype{DataType::INT8}; + const DataLayout layout{DataLayout::NHWC}; + // TODO(Shixiaowei02): need to check the lod is valid. + const std::vector> lod{}; + + DenseTensorMeta meta_0; + CHECK(!meta_0.valid()); + + DenseTensorMeta meta_1(dtype, dims); + CHECK(meta_1.type == dtype); + CHECK(meta_1.dims == dims); + CHECK(meta_1.valid()); + + DenseTensorMeta meta_2(dtype, dims, layout); + CHECK(meta_2.type == dtype); + CHECK(meta_2.dims == dims); + CHECK(meta_2.layout == layout); + CHECK(meta_2.valid()); + + DenseTensorMeta meta_3(dtype, dims, layout, lod); + CHECK(meta_3.type == dtype); + CHECK(meta_3.dims == dims); + CHECK(meta_3.layout == layout); + CHECK(meta_3.lod == lod); + CHECK(meta_3.valid()); + + DenseTensorMeta meta_4(meta_3); + CHECK(meta_4.type == dtype); + CHECK(meta_4.dims == dims); + CHECK(meta_4.layout == layout); + CHECK(meta_4.lod == lod); + CHECK(meta_4.valid()); + + DenseTensorMeta meta_5(std::move(meta_4)); + CHECK(meta_5.type == dtype); + CHECK(meta_5.dims == dims); + CHECK(meta_5.layout == layout); + CHECK(meta_5.lod == lod); + CHECK(meta_5.valid()); +} + +TEST(dense_tensor, def_ctor) { + DenseTensor tensor_0; + CHECK(!tensor_0.valid()); +} + +TEST(dense_tensor, ctor) { + const DDim dims({1, 2}); + const DataType dtype{DataType::INT8}; + const DataLayout layout{DataLayout::NHWC}; + const std::vector> lod{}; + DenseTensorMeta meta(dtype, dims, layout, lod); + + auto alloc = std::make_shared(); + + auto check_dense_tensor = [](const DenseTensor& t, + const DenseTensorMeta& m) -> bool { + bool r{true}; + r = r && (t.numel() == product(m.dims)); + r = r && (t.dims() == m.dims); + r = r && (t.data_type() == m.type); + r = r && (t.layout() == m.layout); + r = r && (t.place() == paddle::platform::CPUPlace()); + r = r && t.initialized(); + r = r && t.IsSharedWith(t); + return r; + }; + + DenseTensor tensor_0(alloc, meta); + check_dense_tensor(tensor_0, meta); + + DenseTensor tensor_1(alloc, DenseTensorMeta(meta)); + check_dense_tensor(tensor_0, meta); + + DenseTensor tensor_2(make_intrusive(alloc), meta); + CHECK(tensor_2.data() == nullptr); + CHECK_NOTNULL(tensor_2.mutable_data()); + check_dense_tensor(tensor_2, meta); +} + +TEST(dense_tensor, resize) { + const DDim dims({1, 2}); + const DataType dtype{DataType::INT8}; + const DataLayout layout{DataLayout::NHWC}; + const std::vector> lod{}; + DenseTensorMeta meta(dtype, dims, layout, lod); + + auto alloc = std::make_shared(); + DenseTensor tensor_0(alloc, meta); + + CHECK_EQ(tensor_0.memory_size(), 2u); + tensor_0.check_memory_size(); + tensor_0.Resize({1, 2, 3}); + CHECK_EQ(tensor_0.memory_size(), 2u); + tensor_0.mutable_data(); + CHECK_EQ(tensor_0.memory_size(), 6u); + + auto storage = tensor_0.release(); + CHECK_EQ(storage->size(), 6u); +} + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/core/test_storage.cc b/paddle/pten/tests/core/test_storage.cc new file mode 100644 index 0000000000000000000000000000000000000000..69d1eae668c5859526193631d6f19c945ddb6271 --- /dev/null +++ b/paddle/pten/tests/core/test_storage.cc @@ -0,0 +1,40 @@ +/* Copyright (c) 2021 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. */ + +#include + +#include "gtest/gtest.h" + +#include "paddle/pten/core/storage.h" +#include "paddle/pten/tests/core/allocator.h" + +namespace pten { +namespace tests { + +TEST(host_storage, internal) { + // TODO(Shixiaowei02): Here we need to consider the case + // where the size is zero. + const size_t size{100}; + const auto a = std::make_shared(); + TensorStorage storage(a, size); + CHECK_EQ(storage.size(), size); + CHECK(paddle::platform::is_cpu_place(storage.place())); + CHECK(storage.OwnsMemory()); + CHECK(storage.allocator() == a); + storage.Realloc(size + 100); + CHECK_EQ(storage.size(), size + 100); +} + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/core/timer.h b/paddle/pten/tests/core/timer.h new file mode 100644 index 0000000000000000000000000000000000000000..1ed03192f124358d5540b90a1daec5a51c97c2fc --- /dev/null +++ b/paddle/pten/tests/core/timer.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2021 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. */ + +#pragma once + +#include // NOLINT + +namespace pten { +namespace tests { + +class Timer { + public: + std::chrono::high_resolution_clock::time_point start; + std::chrono::high_resolution_clock::time_point startu; + + void tic() { start = std::chrono::high_resolution_clock::now(); } + double toc() { + startu = std::chrono::high_resolution_clock::now(); + std::chrono::duration time_span = + std::chrono::duration_cast>(startu - + start); + double used_time_ms = static_cast(time_span.count()) * 1000.0; + return used_time_ms; + } +}; + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/utils/CMakeLists.txt b/paddle/pten/tests/utils/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9974819322517b92c9c9b44e2fe3d00b91480d4 --- /dev/null +++ b/paddle/pten/tests/utils/CMakeLists.txt @@ -0,0 +1,2 @@ +cc_test(test_intrusive_ptr SRCS test_intrusive_ptr.cc) +cc_test(test_type_info SRCS test_type_info.cc) diff --git a/paddle/pten/tests/utils/test_intrusive_ptr.cc b/paddle/pten/tests/utils/test_intrusive_ptr.cc new file mode 100644 index 0000000000000000000000000000000000000000..799f594d10f91132af5fe89caea71cbdf17a265c --- /dev/null +++ b/paddle/pten/tests/utils/test_intrusive_ptr.cc @@ -0,0 +1,97 @@ +/* Copyright (c) 2021 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. */ + +#include +#include + +#include "gtest/gtest.h" + +#include "paddle/pten/core/utils/intrusive_ptr.h" +#include "paddle/pten/core/utils/intrusive_ref_counter.h" + +namespace pten { +namespace tests { + +struct SharedObject : public intrusive_ref_counter { + int i{0}; +}; + +TEST(intrusive_ref_counter, async) { + SharedObject obj; + const size_t num{100}; + std::vector> results; + auto add_ref_and_release = [](const SharedObject* p) { + intrusive_ptr_add_ref(p); + intrusive_ptr_release(p); + }; + for (size_t i = 0; i < num; ++i) { + results.emplace_back(std::async(add_ref_and_release, &obj)); + } + for (auto& result : results) { + result.get(); + } + CHECK_EQ(obj.use_count(), 1u); +} + +TEST(intrusive_ptr, default_ctor) { + intrusive_ptr p; + CHECK(p == nullptr); +} + +TEST(intrusive_ptr, private_ctor) { + auto p = make_intrusive(); + const auto* ptr0 = p.get(); + auto p1 = std::move(p); + intrusive_ptr> p2(std::move(p1)); + const auto* ptr1 = p2.get(); + CHECK_EQ(ptr0, ptr1); +} + +TEST(intrusive_ptr, reset_with_obj) { + SharedObject obj; + obj.i = 1; + intrusive_ptr p; + p.reset(&obj, true); + CHECK_EQ(p->i, obj.i); +} + +TEST(intrusive_ptr, reset_with_ptr) { + auto* ptr = new SharedObject; + ptr->i = 1; + intrusive_ptr p; + p.reset(ptr, false); + CHECK_EQ((*p).i, ptr->i); + p.reset(); + CHECK(p == nullptr); +} + +TEST(intrusive_ptr, op_comp) { + auto p = make_intrusive(); + auto copy = copy_intrusive(p); + auto null = intrusive_ptr(); + auto p1 = make_intrusive(); + CHECK(p == copy); + CHECK(p != p1); + CHECK(p == copy.get()); + CHECK(p != p1.get()); + CHECK(p.get() == copy); + CHECK(p.get() != p1); + CHECK(null == nullptr); + CHECK(nullptr == null); + CHECK(p != nullptr); + CHECK(nullptr != p); +} + +} // namespace tests +} // namespace pten diff --git a/paddle/pten/tests/utils/test_type_info.cc b/paddle/pten/tests/utils/test_type_info.cc new file mode 100644 index 0000000000000000000000000000000000000000..a83f83e90db88ba1079b723c7f3e3dd2a10401a1 --- /dev/null +++ b/paddle/pten/tests/utils/test_type_info.cc @@ -0,0 +1,71 @@ +/* Copyright (c) 2021 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. */ + +#include "gtest/gtest.h" + +#include "paddle/pten/core/utils/type_registry.h" + +namespace pten { +namespace tests { + +template +class Base { + public: + TypeInfo> type_info() const { return type_info_; } + + private: + template + friend class pten::TypeInfoTraits; + TypeInfo> type_info_{TypeInfo>::kUnknownType}; +}; + +template +class DerivedA : public Base, public TypeInfoTraits, DerivedA> { + public: + static const char* name() { return "DerivedA"; } +}; + +template +class DerivedB : public Base, public TypeInfoTraits, DerivedB> { + public: + static const char* name() { return "DerivedB"; } +}; + +template +void check_type_info() { + std::unique_ptr> base(new Base); + std::unique_ptr> derived_a(new DerivedA); + std::unique_ptr> derived_b(new DerivedB); + + EXPECT_EQ(DerivedA::classof(derived_a.get()), true); + EXPECT_EQ(DerivedB::classof(derived_b.get()), true); + EXPECT_EQ(DerivedB::classof(derived_a.get()), false); + EXPECT_EQ(DerivedA::classof(derived_b.get()), false); + + EXPECT_EQ(base->type_info().id(), 0); + EXPECT_EQ(derived_a->type_info().id(), 1); + EXPECT_EQ(derived_b->type_info().id(), 2); + + EXPECT_EQ(base->type_info().name(), "Unknown"); + EXPECT_EQ(derived_a->type_info().name(), "DerivedA"); + EXPECT_EQ(derived_b->type_info().name(), "DerivedB"); +} + +TEST(type_info, base) { + check_type_info(); + check_type_info(); +} + +} // namespace tests +} // namespace pten