diff --git a/.claude/skills/add-compat-api/SKILL.md b/.claude/skills/add-compat-api/SKILL.md index 1bc79e5..b784e5e 100644 --- a/.claude/skills/add-compat-api/SKILL.md +++ b/.claude/skills/add-compat-api/SKILL.md @@ -202,12 +202,12 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`references/Step7.md`](references/Step7.md)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B add/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b add/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] <对齐迭代记录标题>`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`) 5. **同步 PCAT 测试改动** - 1. **从 fork 主分支 checkout 新分支**(`cd "$PCAT_ROOT" && git fetch upstream && git checkout -B test/- upstream/master`) + 1. **从本地跟踪 origin 的 master 创建新分支**(`cd "$PCAT_ROOT" && git checkout master && git pull --ff-only origin master && git checkout -b test/-`) 2. **commit 改动**(commit message 首行使用 `test(): align with Paddle compat 行为`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PFCCLab/PaddleCppAPITest --base master`,PR body 中加 `Related: PaddlePaddle/Paddle#`) diff --git a/.claude/skills/add-compat-api/references/Step7.md b/.claude/skills/add-compat-api/references/Step7.md index 892239d..ec2f5d4 100644 --- a/.claude/skills/add-compat-api/references/Step7.md +++ b/.claude/skills/add-compat-api/references/Step7.md @@ -13,24 +13,27 @@ 任一未通过 → **不要**进入本流程。 -## 1) 从 fork 主分支 checkout 新分支 +## 1) 从本地跟踪 origin 的基分支创建新分支 ### Paddle 侧 ```bash cd "$PADDLE_ROOT" -git fetch upstream +git checkout develop +git pull --ff-only origin develop # add 流程 -git checkout -B "add/-$(date +%Y%m%d)" upstream/develop +git checkout -b "add/-$(date +%Y%m%d)" # fix 流程 -git checkout -B "fix/-$(date +%Y%m%d)" upstream/develop +git checkout -b "fix/-$(date +%Y%m%d)" ``` 分支命名规则: - add:`add/-`(例:`add/abs-20260519`) - fix:`fix/-`(例:`fix/78652-20260519`) -> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`。若 remote 缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 +> 实际执行时只选 add 或 fix 对应的一条 `git checkout -b`。若分支已存在,`git checkout -b` 会失败;换新分支名或让用户手动处理,**不要**改用 `-B` 覆盖已有分支。 +> +> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`,且本地 `develop` 跟踪 `origin/develop`。若 remote 或本地基分支缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 ## 2) commit 改动 @@ -100,8 +103,9 @@ EOF ```bash cd "$PCAT_ROOT" -git fetch upstream -git checkout -B "test/-$(date +%Y%m%d)" upstream/master +git checkout master +git pull --ff-only origin master +git checkout -b "test/-$(date +%Y%m%d)" git add test/<改动文件> git commit -m "test(): align with Paddle compat 行为" git push origin diff --git a/.claude/skills/fix-compat-api/SKILL.md b/.claude/skills/fix-compat-api/SKILL.md index 9245cf8..d366845 100644 --- a/.claude/skills/fix-compat-api/SKILL.md +++ b/.claude/skills/fix-compat-api/SKILL.md @@ -218,7 +218,7 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`../add-compat-api/references/Step7.md`](../add-compat-api/references/Step7.md)(与 `add-compat-api` 共享同一份 references)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B fix/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b fix/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] `) 3. **征求用户同意后 push 到 fork**(`git push origin `——这是发出去的动作,**push 前必须明确询问用户**) 4. **征求用户同意后 `gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`——同样需要用户确认;若本轮修复源自外部 PR/Actions/comment 链接,PR 描述里应**引用原链接**便于追溯) diff --git a/.github/skills/add-compat-api/SKILL.md b/.github/skills/add-compat-api/SKILL.md index 1bc79e5..b784e5e 100644 --- a/.github/skills/add-compat-api/SKILL.md +++ b/.github/skills/add-compat-api/SKILL.md @@ -202,12 +202,12 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`references/Step7.md`](references/Step7.md)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B add/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b add/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] <对齐迭代记录标题>`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`) 5. **同步 PCAT 测试改动** - 1. **从 fork 主分支 checkout 新分支**(`cd "$PCAT_ROOT" && git fetch upstream && git checkout -B test/- upstream/master`) + 1. **从本地跟踪 origin 的 master 创建新分支**(`cd "$PCAT_ROOT" && git checkout master && git pull --ff-only origin master && git checkout -b test/-`) 2. **commit 改动**(commit message 首行使用 `test(): align with Paddle compat 行为`) 3. **push 到 fork**(`git push origin `) 4. **`gh pr create` 到 upstream**(`--repo PFCCLab/PaddleCppAPITest --base master`,PR body 中加 `Related: PaddlePaddle/Paddle#`) diff --git a/.github/skills/add-compat-api/references/Step7.md b/.github/skills/add-compat-api/references/Step7.md index 892239d..ec2f5d4 100644 --- a/.github/skills/add-compat-api/references/Step7.md +++ b/.github/skills/add-compat-api/references/Step7.md @@ -13,24 +13,27 @@ 任一未通过 → **不要**进入本流程。 -## 1) 从 fork 主分支 checkout 新分支 +## 1) 从本地跟踪 origin 的基分支创建新分支 ### Paddle 侧 ```bash cd "$PADDLE_ROOT" -git fetch upstream +git checkout develop +git pull --ff-only origin develop # add 流程 -git checkout -B "add/-$(date +%Y%m%d)" upstream/develop +git checkout -b "add/-$(date +%Y%m%d)" # fix 流程 -git checkout -B "fix/-$(date +%Y%m%d)" upstream/develop +git checkout -b "fix/-$(date +%Y%m%d)" ``` 分支命名规则: - add:`add/-`(例:`add/abs-20260519`) - fix:`fix/-`(例:`fix/78652-20260519`) -> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`。若 remote 缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 +> 实际执行时只选 add 或 fix 对应的一条 `git checkout -b`。若分支已存在,`git checkout -b` 会失败;换新分支名或让用户手动处理,**不要**改用 `-B` 覆盖已有分支。 +> +> 前提:Paddle 仓库已配置 `origin = /Paddle` 与 `upstream = PaddlePaddle/Paddle`,且本地 `develop` 跟踪 `origin/develop`。若 remote 或本地基分支缺失,**提示用户配置后再继续**,不要主动改用户仓库的 remote。 ## 2) commit 改动 @@ -100,8 +103,9 @@ EOF ```bash cd "$PCAT_ROOT" -git fetch upstream -git checkout -B "test/-$(date +%Y%m%d)" upstream/master +git checkout master +git pull --ff-only origin master +git checkout -b "test/-$(date +%Y%m%d)" git add test/<改动文件> git commit -m "test(): align with Paddle compat 行为" git push origin diff --git a/.github/skills/fix-compat-api/SKILL.md b/.github/skills/fix-compat-api/SKILL.md index 9245cf8..d366845 100644 --- a/.github/skills/fix-compat-api/SKILL.md +++ b/.github/skills/fix-compat-api/SKILL.md @@ -218,7 +218,7 @@ bash test/result_cmp.sh ./build/ 闭环验证通过且文档已回填后,按以下流程提交。完整命令模板见 [`../add-compat-api/references/Step7.md`](../add-compat-api/references/Step7.md)(与 `add-compat-api` 共享同一份 references)。 -1. **从 fork 主分支 checkout 新分支**(`git fetch upstream && git checkout -B fix/- upstream/develop`) +1. **从本地跟踪 origin 的 develop 创建新分支**(`git checkout develop && git pull --ff-only origin develop && git checkout -b fix/-`) 2. **commit 改动**(commit message 首行使用 `[Cpp API Compatibility] `) 3. **征求用户同意后 push 到 fork**(`git push origin `——这是发出去的动作,**push 前必须明确询问用户**) 4. **征求用户同意后 `gh pr create` 到 upstream**(`--repo PaddlePaddle/Paddle --base develop`——同样需要用户确认;若本轮修复源自外部 PR/Actions/comment 链接,PR 描述里应**引用原链接**便于追溯) diff --git a/test/ATen/core/TensorUtilTest.cpp b/test/ATen/core/TensorUtilTest.cpp index f0c17c7..947b4bc 100644 --- a/test/ATen/core/TensorUtilTest.cpp +++ b/test/ATen/core/TensorUtilTest.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "src/file_manager.h" @@ -17,6 +18,11 @@ namespace test { using paddle_api_test::FileManerger; using paddle_api_test::ThreadSafeParam; +static_assert(noexcept(std::declval().is_same( + std::declval()))); +static_assert(noexcept(std::declval().use_count())); +static_assert(noexcept(std::declval().weak_use_count())); + class TensorUtilTest : public ::testing::Test { protected: void SetUp() override { diff --git a/test/ATen/ops/AsStridedTest.cpp b/test/ATen/ops/AsStridedTest.cpp index 4410024..90d650e 100644 --- a/test/ATen/ops/AsStridedTest.cpp +++ b/test/ATen/ops/AsStridedTest.cpp @@ -19,19 +19,8 @@ class AsStridedTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(AsStridedTest, AsStrided) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "AsStrided "; at::Tensor tensor = at::ones({2, 3, 4}, at::kFloat); @@ -44,7 +33,7 @@ TEST_F(AsStridedTest, AsStrided) { } TEST_F(AsStridedTest, AsStridedInplace) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "AsStridedInplace "; at::Tensor tensor = at::ones({2, 3, 4}, at::kFloat); @@ -57,7 +46,7 @@ TEST_F(AsStridedTest, AsStridedInplace) { } TEST_F(AsStridedTest, AsStridedScatter) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "AsStridedScatter "; at::Tensor tensor = at::ones({2, 3, 4}, at::kFloat); @@ -69,5 +58,40 @@ TEST_F(AsStridedTest, AsStridedScatter) { file.saveFile(); } +TEST_F(AsStridedTest, AsStridedScatterPreservesInputShape) { + FileManerger file(g_custom_param.get()); + file.openAppend(); + file << "AsStridedScatterPreservesInputShape "; + at::Tensor tensor = at::arange(12, at::kFloat); + at::Tensor src = at::full({2, 3}, 99.0f, at::kFloat); + at::Tensor result = tensor.as_strided_scatter(src, {2, 3}, {3, 1}); + file << std::to_string(result.dim()) << " "; + file << std::to_string(result.sizes()[0]) << " "; + float* data = result.data_ptr(); + for (int i = 0; i < 6; ++i) { + file << std::to_string(data[i]) << " "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(AsStridedTest, AsStridedScatterWithOffset) { + FileManerger file(g_custom_param.get()); + file.openAppend(); + file << "AsStridedScatterWithOffset "; + at::Tensor tensor = at::arange(12, at::kFloat); + at::Tensor src = at::full({2, 2}, 88.0f, at::kFloat); + at::Tensor result = tensor.as_strided_scatter(src, {2, 2}, {2, 1}, 2); + file << std::to_string(result.dim()) << " "; + file << std::to_string(result.sizes()[0]) << " "; + float* data = result.data_ptr(); + file << std::to_string(data[0]) << " "; + file << std::to_string(data[2]) << " "; + file << std::to_string(data[3]) << " "; + file << std::to_string(data[5]) << " "; + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at diff --git a/test/ATen/ops/BitwiseTest.cpp b/test/ATen/ops/BitwiseTest.cpp index 90d2a55..77f2a85 100644 --- a/test/ATen/ops/BitwiseTest.cpp +++ b/test/ATen/ops/BitwiseTest.cpp @@ -19,19 +19,8 @@ class BitwiseTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(BitwiseTest, BitwiseRightShift) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "BitwiseRightShift "; at::Tensor input = at::ones({2, 3}, at::kInt).fill_(8); diff --git a/test/ATen/ops/ClampTest.cpp b/test/ATen/ops/ClampTest.cpp index 26ed74d..28d54a3 100644 --- a/test/ATen/ops/ClampTest.cpp +++ b/test/ATen/ops/ClampTest.cpp @@ -19,19 +19,8 @@ class ClampTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(ClampTest, ClampScalarMinMax) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "ClampScalarMinMax "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -44,7 +33,7 @@ TEST_F(ClampTest, ClampScalarMinMax) { } TEST_F(ClampTest, ClampTensorMinMax) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampTensorMinMax "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -57,7 +46,7 @@ TEST_F(ClampTest, ClampTensorMinMax) { } TEST_F(ClampTest, ClampInplaceScalar) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampInplaceScalar "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -69,7 +58,7 @@ TEST_F(ClampTest, ClampInplaceScalar) { } TEST_F(ClampTest, ClampInplaceTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampInplaceTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -82,7 +71,7 @@ TEST_F(ClampTest, ClampInplaceTensor) { } TEST_F(ClampTest, ClampMaxScalar) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxScalar "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -94,7 +83,7 @@ TEST_F(ClampTest, ClampMaxScalar) { } TEST_F(ClampTest, ClampMaxTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -106,7 +95,7 @@ TEST_F(ClampTest, ClampMaxTensor) { } TEST_F(ClampTest, ClampMaxInplace) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxInplace "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -118,7 +107,7 @@ TEST_F(ClampTest, ClampMaxInplace) { } TEST_F(ClampTest, ClampMaxInplaceTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMaxInplaceTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat).fill_(5.0f); @@ -130,7 +119,7 @@ TEST_F(ClampTest, ClampMaxInplaceTensor) { } TEST_F(ClampTest, ClampMinScalar) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinScalar "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -142,7 +131,7 @@ TEST_F(ClampTest, ClampMinScalar) { } TEST_F(ClampTest, ClampMinTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -154,7 +143,7 @@ TEST_F(ClampTest, ClampMinTensor) { } TEST_F(ClampTest, ClampMinInplace) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinInplace "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -166,7 +155,7 @@ TEST_F(ClampTest, ClampMinInplace) { } TEST_F(ClampTest, ClampMinInplaceTensor) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "ClampMinInplaceTensor "; at::Tensor input = at::ones({2, 3}, at::kFloat); diff --git a/test/ATen/ops/IndexPutTest.cpp b/test/ATen/ops/IndexPutTest.cpp index 3b1b258..ba36b1d 100644 --- a/test/ATen/ops/IndexPutTest.cpp +++ b/test/ATen/ops/IndexPutTest.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -190,5 +191,62 @@ TEST(TensorBodyTest, IndexPutAccumulateTrue) { file.saveFile(); } +TEST(TensorBodyTest, IndexPutTensorIndexNoneValue) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor base = at::zeros({2, 3}, options); + at::Tensor values = at::full({1, 2, 3}, 6.0f, options); + + base.index_put_({at::indexing::None}, values); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexPutTensorIndexNoneValue "; + write_index_result_to_file(&file, base); + file << "\n"; + file.saveFile(); +} + +TEST(TensorBodyTest, IndexPutTensorIndexTensorNoneAndSlice) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor base = at::zeros({3, 4}, options); + at::Tensor idx = tensor_from_vector_i64({2, 0}); + at::Tensor values = at::full({2, 1, 4}, 8.0f, options); + + base.index_put_({idx, at::indexing::None, at::indexing::Slice()}, values); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexPutTensorIndexTensorNoneAndSlice "; + file << std::to_string(base.dim()) << " "; + file << std::to_string(base.numel()) << " "; + file << std::to_string(base.sizes()[0]) << " "; + file << std::to_string(base.sizes()[1]) << " "; + at::Tensor cont = base.contiguous(); + float* data = cont.data_ptr(); + file << std::to_string(data[0]) << " "; + file << std::to_string(data[4]) << " "; + file << std::to_string(data[8]) << " "; + file << std::to_string(cont.sum().item()) << " "; + file << "\n"; + file.saveFile(); +} + +TEST(TensorBodyTest, IndexPutTensorIndexNoneScalar) { + auto options = at::TensorOptions().dtype(at::kFloat).device(at::kCPU); + at::Tensor base = at::zeros({2, 3}, options); + + base.index_put_({at::indexing::None}, at::Scalar(4.0)); + + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "IndexPutTensorIndexNoneScalar "; + write_index_result_to_file(&file, base); + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at diff --git a/test/ATen/ops/RepeatInterleaveTest.cpp b/test/ATen/ops/RepeatInterleaveTest.cpp new file mode 100644 index 0000000..162ca33 --- /dev/null +++ b/test/ATen/ops/RepeatInterleaveTest.cpp @@ -0,0 +1,516 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "src/file_manager.h" + +extern paddle_api_test::ThreadSafeParam g_custom_param; + +namespace at { +namespace test { + +using paddle_api_test::FileManerger; +using paddle_api_test::ThreadSafeParam; + +static void write_repeat_interleave_result_to_file(FileManerger* file, + const at::Tensor& result) { + *file << std::to_string(result.dim()) << " "; + *file << std::to_string(result.numel()) << " "; + for (int64_t i = 0; i < result.dim(); ++i) { + *file << std::to_string(result.sizes()[i]) << " "; + } +} + +// Helper to create a 1D Long tensor from initializer list +static at::Tensor make_long_tensor(const std::vector& values) { + at::Tensor t = at::zeros({static_cast(values.size())}, at::kLong); + int64_t* data = t.data_ptr(); + for (size_t i = 0; i < values.size(); ++i) { + data[i] = values[i]; + } + return t; +} + +// Helper to create a 1D Float tensor from initializer list +static at::Tensor make_float_tensor(const std::vector& values) { + at::Tensor t = at::zeros({static_cast(values.size())}, at::kFloat); + float* data = t.data_ptr(); + for (size_t i = 0; i < values.size(); ++i) { + data[i] = values[i]; + } + return t; +} + +// Helper to create a scalar Long tensor +static at::Tensor make_scalar_long_tensor(int64_t value) { + at::Tensor t = at::zeros({}, at::kLong); + t.data_ptr()[0] = value; + return t; +} + +class RepeatInterleaveTest : public ::testing::Test { + protected: + void SetUp() override { + tensor = at::ones({2, 3, 4}, at::kFloat); + float* data = tensor.data_ptr(); + for (int64_t i = 0; i < tensor.numel(); ++i) { + data[i] = static_cast(i); + } + } + + at::Tensor tensor; +}; + +// ========== Scalar repeats tests ========== + +// Scalar repeats with explicit dim +TEST_F(RepeatInterleaveTest, ScalarRepeatsWithDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.createFile(); + file << "ScalarRepeatsWithDim "; + at::Tensor result = tensor.repeat_interleave(2, 1); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Scalar repeats without dim (flatten first, then repeat) +TEST_F(RepeatInterleaveTest, ScalarRepeatsWithoutDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarRepeatsWithoutDim "; + at::Tensor result = tensor.repeat_interleave(2); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Scalar repeats with dim=0 +TEST_F(RepeatInterleaveTest, ScalarRepeatsDim0) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarRepeatsDim0 "; + at::Tensor result = tensor.repeat_interleave(3, 0); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Scalar repeats with negative dim +TEST_F(RepeatInterleaveTest, ScalarRepeatsNegativeDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarRepeatsNegativeDim "; + at::Tensor result = tensor.repeat_interleave(2, -1); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// ========== Tensor repeats tests ========== + +// Tensor repeats with explicit dim +TEST_F(RepeatInterleaveTest, TensorRepeatsWithDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "TensorRepeatsWithDim "; + at::Tensor repeats = make_long_tensor({2, 1, 3}); + at::Tensor result = tensor.repeat_interleave(repeats, 1); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Tensor repeats without dim +TEST_F(RepeatInterleaveTest, TensorRepeatsWithoutDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "TensorRepeatsWithoutDim "; + // Input {2, 3} flattens to {6}, repeats must match flattened size + at::Tensor repeats = make_long_tensor({2, 1, 3, 1, 2, 1}); + at::Tensor small_tensor = at::ones({2, 3}, at::kFloat); + at::Tensor result = small_tensor.repeat_interleave(repeats); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Scalar tensor (0-dim) as repeats +TEST_F(RepeatInterleaveTest, ScalarTensorRepeats) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarTensorRepeats "; + at::Tensor repeats = make_scalar_long_tensor(2); + at::Tensor result = tensor.repeat_interleave(repeats, 1); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// ========== Standalone function test ========== + +// at::repeat_interleave(repeats) standalone function +TEST_F(RepeatInterleaveTest, StandaloneRepeatInterleave) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "StandaloneRepeatInterleave "; + at::Tensor repeats = make_long_tensor({2, 1, 3}); + at::Tensor result = at::repeat_interleave(repeats); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// ========== Shape coverage ========== + +// 1D tensor +TEST_F(RepeatInterleaveTest, OneDTensor) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "OneDTensor "; + at::Tensor t1d = at::arange(5, at::kFloat); + at::Tensor result = t1d.repeat_interleave(2); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Large shape +TEST_F(RepeatInterleaveTest, LargeShape) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "LargeShape "; + at::Tensor large = at::ones({100, 50}, at::kFloat); + at::Tensor result = large.repeat_interleave(3, 0); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Empty tensor +TEST_F(RepeatInterleaveTest, EmptyTensor) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "EmptyTensor "; + at::Tensor empty = at::ones({0, 3}, at::kFloat); + at::Tensor result = empty.repeat_interleave(2, 0); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// All-one dimensions +TEST_F(RepeatInterleaveTest, AllOneShape) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "AllOneShape "; + at::Tensor t = at::ones({1, 1, 1}, at::kFloat); + at::Tensor result = t.repeat_interleave(2, 0); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// ========== Dtype coverage ========== + +// float64 +TEST_F(RepeatInterleaveTest, Float64Dtype) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "Float64Dtype "; + at::Tensor t = at::ones({2, 3}, at::kDouble); + at::Tensor result = t.repeat_interleave(2, 0); + file << std::to_string(static_cast(result.scalar_type())) << " "; + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// int32 +TEST_F(RepeatInterleaveTest, Int32Dtype) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "Int32Dtype "; + at::Tensor t = at::ones({2, 3}, at::kInt); + at::Tensor result = t.repeat_interleave(2, 0); + file << std::to_string(static_cast(result.scalar_type())) << " "; + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// int64 +TEST_F(RepeatInterleaveTest, Int64Dtype) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "Int64Dtype "; + at::Tensor t = at::ones({2, 3}, at::kLong); + at::Tensor result = t.repeat_interleave(2, 0); + file << std::to_string(static_cast(result.scalar_type())) << " "; + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// ========== Boundary cases ========== + +// Zero repeats +TEST_F(RepeatInterleaveTest, ZeroRepeats) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ZeroRepeats "; + at::Tensor t = at::ones({2, 3}, at::kFloat); + at::Tensor result = t.repeat_interleave(0, 0); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Zero repeats without dim +TEST_F(RepeatInterleaveTest, ZeroRepeatsNoDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ZeroRepeatsNoDim "; + at::Tensor t = at::ones({2, 3}, at::kFloat); + at::Tensor result = t.repeat_interleave(0); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +// Empty standalone repeats +TEST_F(RepeatInterleaveTest, EmptyStandaloneRepeats) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "EmptyStandaloneRepeats "; + at::Tensor repeats = make_long_tensor({}); + at::Tensor result = at::repeat_interleave(repeats); + write_repeat_interleave_result_to_file(&file, result); + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, EmptyStandaloneRepeatsInvalidOutputSize) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "EmptyStandaloneRepeatsInvalidOutputSize "; + try { + at::Tensor repeats = make_long_tensor({}); + at::Tensor result = at::repeat_interleave(repeats, 1); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +// ========== Data integrity ========== + +// Verify data after scalar repeat_interleave +TEST_F(RepeatInterleaveTest, ScalarDataIntegrity) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarDataIntegrity "; + at::Tensor t = make_float_tensor({1.0f, 2.0f, 3.0f}); + at::Tensor result = t.repeat_interleave(2); + float* data = result.data_ptr(); + bool correct = (data[0] == 1.0f && data[1] == 1.0f && data[2] == 2.0f && + data[3] == 2.0f && data[4] == 3.0f && data[5] == 3.0f); + file << std::to_string(correct) << " "; + file << "\n"; + file.saveFile(); +} + +// Verify data after tensor repeat_interleave +TEST_F(RepeatInterleaveTest, TensorDataIntegrity) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "TensorDataIntegrity "; + at::Tensor t = make_float_tensor({1.0f, 2.0f, 3.0f}); + at::Tensor repeats = make_long_tensor({2, 1, 3}); + at::Tensor result = t.repeat_interleave(repeats); + float* data = result.data_ptr(); + bool correct = (data[0] == 1.0f && data[1] == 1.0f && data[2] == 2.0f && + data[3] == 3.0f && data[4] == 3.0f && data[5] == 3.0f); + file << std::to_string(correct) << " "; + file << "\n"; + file.saveFile(); +} + +// ========== Exception cases ========== + +// Negative scalar repeats +TEST_F(RepeatInterleaveTest, NegativeRepeats) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "NegativeRepeats "; + try { + at::Tensor result = tensor.repeat_interleave(-1, 0); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +// Invalid 2D repeats tensor +TEST_F(RepeatInterleaveTest, InvalidRepeatsDim) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "InvalidRepeatsDim "; + try { + at::Tensor repeats = at::ones({2, 3}, at::kLong); + at::Tensor result = tensor.repeat_interleave(repeats, 0); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +// Repeats size mismatch +TEST_F(RepeatInterleaveTest, RepeatsSizeMismatch) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "RepeatsSizeMismatch "; + try { + at::Tensor repeats = make_long_tensor({2, 3}); // size 2, but dim 1 has 3 + at::Tensor result = tensor.repeat_interleave(repeats, 1); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, TensorRepeatsNegativeOutputSize) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "TensorRepeatsNegativeOutputSize "; + try { + at::Tensor repeats = make_long_tensor({1, 2, 1}); + at::Tensor result = tensor.repeat_interleave(repeats, 1, -1); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, ScalarRepeatsNegativeOutputSize) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarRepeatsNegativeOutputSize "; + try { + at::Tensor result = tensor.repeat_interleave(2, 1, -1); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, ScalarZeroRepeatsInvalidOutputSize) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "ScalarZeroRepeatsInvalidOutputSize "; + try { + at::Tensor result = tensor.repeat_interleave(0, 1, 1); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, StandaloneRepeatsZeroOutputSizeMismatch) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "StandaloneRepeatsZeroOutputSizeMismatch "; + try { + at::Tensor repeats = make_long_tensor({1, 2, 1}); + at::Tensor result = at::repeat_interleave(repeats, 0); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, TensorRepeatsZeroOutputSizeMismatch) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "TensorRepeatsZeroOutputSizeMismatch "; + try { + at::Tensor repeats = make_long_tensor({1, 2, 1}); + at::Tensor result = tensor.repeat_interleave(repeats, 1, 0); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(RepeatInterleaveTest, TensorRepeatsZeroOutputSizeValid) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "TensorRepeatsZeroOutputSizeValid "; + try { + at::Tensor t = at::ones({3}, at::kFloat); + at::Tensor repeats = make_long_tensor({0, 0, 0}); + at::Tensor result = t.repeat_interleave(repeats, 0, 0); + write_repeat_interleave_result_to_file(&file, result); + } catch (const std::exception&) { + file << "exception "; + } + file << "\n"; + file.saveFile(); +} + +} // namespace test +} // namespace at diff --git a/test/ATen/ops/TensorPtrTest.cpp b/test/ATen/ops/TensorPtrTest.cpp index 8f46f8b..813bb4a 100644 --- a/test/ATen/ops/TensorPtrTest.cpp +++ b/test/ATen/ops/TensorPtrTest.cpp @@ -12,9 +12,18 @@ TEST(TensorBodyTest, PtrTest) { const float* const_ptr = t.const_data_ptr(); EXPECT_NE(const_ptr, nullptr); + const float* const_type_ptr = t.const_data_ptr(); + EXPECT_NE(const_type_ptr, nullptr); + const void* void_const_ptr = t.const_data_ptr(); EXPECT_NE(void_const_ptr, nullptr); + float* data_ptr = t.data_ptr(); + EXPECT_NE(data_ptr, nullptr); + + void* void_data_ptr = t.data_ptr(); + EXPECT_NE(void_data_ptr, nullptr); + float* mut_ptr = t.mutable_data_ptr(); EXPECT_NE(mut_ptr, nullptr); @@ -27,6 +36,16 @@ TEST(TensorBodyTest, PtrTest) { file.createFile(); file << "PtrTest "; file << "const_ptr[0]: " + std::to_string(const_ptr[0]) + "\n"; + file << "const_type_ptr[0]: " + std::to_string(const_type_ptr[0]) + "\n"; + file << "void_const_ptr_equal: " + << std::to_string(void_const_ptr == static_cast(const_ptr)) + << "\n"; + file << "data_ptr_equal: " + << std::to_string(static_cast(data_ptr) == void_data_ptr) << "\n"; + file << "const_type_ptr_equal: " + << std::to_string(static_cast(const_type_ptr) == + static_cast(const_ptr)) + << "\n"; mut_ptr[0] = 5.0f; file << "mut_ptr[0]: " + std::to_string(mut_ptr[0]) + "\n"; diff --git a/test/ATen/ops/TransposeTest.cpp b/test/ATen/ops/TransposeTest.cpp index 8731aa8..2d24da7 100644 --- a/test/ATen/ops/TransposeTest.cpp +++ b/test/ATen/ops/TransposeTest.cpp @@ -284,5 +284,55 @@ TEST_F(TransposeTest, TransposeSpecialValues) { file.saveFile(); } +TEST_F(TransposeTest, LargePositiveDimThrows) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "LargePositiveDimThrows "; + + try { + (void)at::transpose(tensor, 1LL << 32, 1); + file << "ok "; + } catch (const std::exception&) { + file << "exception "; + } + + at::Tensor in_place = at::zeros({2, 3, 4}, at::kFloat); + try { + (void)in_place.transpose_(1LL << 32, 1); + file << "inplace_ok "; + } catch (const std::exception&) { + file << "inplace_exception "; + } + for (int64_t i = 0; i < in_place.dim(); ++i) { + file << std::to_string(in_place.sizes()[i]) << " "; + } + file << "\n"; + file.saveFile(); +} + +TEST_F(TransposeTest, LargeNegativeDimThrows) { + auto file_name = g_custom_param.get(); + FileManerger file(file_name); + file.openAppend(); + file << "LargeNegativeDimThrows "; + + try { + (void)tensor.transpose(0, -(1LL << 32)); + file << "member_ok "; + } catch (const std::exception&) { + file << "member_exception "; + } + + try { + (void)at::transpose(tensor, 0, -(1LL << 32)); + file << "free_ok "; + } catch (const std::exception&) { + file << "free_exception "; + } + file << "\n"; + file.saveFile(); +} + } // namespace test } // namespace at diff --git a/test/ATen/ops/VarTest.cpp b/test/ATen/ops/VarTest.cpp index feac64c..82b80b0 100644 --- a/test/ATen/ops/VarTest.cpp +++ b/test/ATen/ops/VarTest.cpp @@ -19,19 +19,8 @@ class VarTest : public ::testing::Test { void SetUp() override {} }; -// 返回当前用例的结果文件名 -std::string GetTestCaseResultFileName() { - std::string base = g_custom_param.get(); - std::string test_name = - ::testing::UnitTest::GetInstance()->current_test_info()->name(); - if (base.size() >= 4 && base.substr(base.size() - 4) == ".txt") { - base.resize(base.size() - 4); - } - return base + "_" + test_name + ".txt"; -} - TEST_F(VarTest, VarDim) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.createFile(); file << "VarDim "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -44,7 +33,7 @@ TEST_F(VarTest, VarDim) { } TEST_F(VarTest, VarAll) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "VarAll "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -57,7 +46,7 @@ TEST_F(VarTest, VarAll) { } TEST_F(VarTest, VarDims) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "VarDims "; at::Tensor input = at::ones({2, 3}, at::kFloat); @@ -71,7 +60,7 @@ TEST_F(VarTest, VarDims) { } TEST_F(VarTest, VarCorrection) { - FileManerger file(GetTestCaseResultFileName()); + FileManerger file(g_custom_param.get()); file.openAppend(); file << "VarCorrection "; at::Tensor input = at::ones({2, 3}, at::kFloat); diff --git a/test/result_cmp.sh b/test/result_cmp.sh index e5fa3c0..4311325 100755 --- a/test/result_cmp.sh +++ b/test/result_cmp.sh @@ -8,6 +8,22 @@ PADDLE_PATH=${BUILD_PATH}/paddle/ TORCH_PATH=${BUILD_PATH}/torch/ RESULT_FILE_PATH="/tmp/paddle_cpp_api_test/" +cleanup_coverage_data() { + local build_path="$1" + local gcda_count + + if [[ ! -d "$build_path" ]]; then + return + fi + + gcda_count=$(find "$build_path" -type f -name "*.gcda" | wc -l) + gcda_count=${gcda_count//[[:space:]]/} + if [[ "$gcda_count" -gt 0 ]]; then + echo "Cleaning ${gcda_count} stale .gcda coverage files under ${build_path}..." + find "$build_path" -type f -name "*.gcda" -delete + fi +} + # 保存原始终端输出,并在退出时稳定打印日志路径 LOG_FILE="${RESULT_FILE_PATH}result_cmp_$(date +%Y%m%d_%H%M%S).log" mkdir -p "${RESULT_FILE_PATH}" @@ -16,6 +32,8 @@ trap 'status=$?; printf "\nDone. Full output saved to: %s\n" "$LOG_FILE" | tee - exec > >(tee -a "$LOG_FILE") 2>&1 echo "Log file: $LOG_FILE" +cleanup_coverage_data "$BUILD_PATH" + collect_and_run_executables() { local exec_path="$1" local prefix="$2" @@ -59,8 +77,12 @@ for key in "${!TORCH_EXECUTABLES[@]}"; do done while IFS= read -r key; do - paddle_exec="${PADDLE_EXECUTABLES[$key]}" - torch_exec="${TORCH_EXECUTABLES[$key]}" + if [[ -z "$key" ]]; then + continue + fi + + paddle_exec="${PADDLE_EXECUTABLES[$key]:-}" + torch_exec="${TORCH_EXECUTABLES[$key]:-}" if [[ -z "$paddle_exec" || -z "$torch_exec" ]]; then has_mismatch=1