已合并
aicpu persistence落盘问题修复 #458
wangzixuan创建于 22 天前
aicpu persistence落盘问题修复 #458
已合并
共 8 个文件变更+144-5
| @@ -502,7 +502,9 @@ uint32_t AicpuPersistence::GenerateAndSaveData(const std::string& deviceFilePath | |||
| 502 | // 表驱动方式:使用 std::function 适配不同签名的函数 | 502 | // 表驱动方式:使用 std::function 适配不同签名的函数 |
| 503 | using func = std::function<uint32_t()>; | 503 | using func = std::function<uint32_t()>; |
| 504 | 504 | ||
| 505 | - static const std::vector<std::pair<const std::vector<AicpuData> AicpuPersistence::*, func>> dataProcessMap = { | 505 | + // 注意:不能声明为 static。static 会导致首次调用时捕获的 this/deviceFilePath |
| 506 | + // 被所有 device 实例共享,后续卡的落盘路径全部错写成第一张卡的目录。 | ||
| 507 | + const std::vector<std::pair<const std::vector<AicpuData> AicpuPersistence::*, func>> dataProcessMap = { | ||
| 506 | {&AicpuPersistence::nodeData_, [this, deviceFilePath]() { return GenerateAndSaveNode(deviceFilePath); }}, | 508 | {&AicpuPersistence::nodeData_, [this, deviceFilePath]() { return GenerateAndSaveNode(deviceFilePath); }}, |
| 507 | {&AicpuPersistence::dpData_, [this, deviceFilePath]() { return GenerateAndSaveDp(deviceFilePath); }}, | 509 | {&AicpuPersistence::dpData_, [this, deviceFilePath]() { return GenerateAndSaveDp(deviceFilePath); }}, |
| 508 | {&AicpuPersistence::modelData_, [this, deviceFilePath]() { return GenerateAndSaveModel(deviceFilePath); }}, | 510 | {&AicpuPersistence::modelData_, [this, deviceFilePath]() { return GenerateAndSaveModel(deviceFilePath); }}, |
| @@ -628,6 +630,7 @@ void AicpuPersistence::ComputeAicpuBatchId() | |||
| 628 | uint32_t AicpuPersistence::ProcessEntry(DataInventory& dataInventory, const Context& context) | 630 | uint32_t AicpuPersistence::ProcessEntry(DataInventory& dataInventory, const Context& context) |
| 629 | { | 631 | { |
| 630 | const DeviceContext& deviceContext = static_cast<const DeviceContext&>(context); | 632 | const DeviceContext& deviceContext = static_cast<const DeviceContext&>(context); |
| 633 | + INFO("Start to process aicpu data for device, path %.", deviceContext.GetDeviceFilePath()); | ||
| 631 | auto aicpuData = dataInventory.GetPtr<std::vector<AicpuData>>(); | 634 | auto aicpuData = dataInventory.GetPtr<std::vector<AicpuData>>(); |
| 632 | auto deviceStreamInfo = dataInventory.GetPtr<DeviceStreamInfo>(); | 635 | auto deviceStreamInfo = dataInventory.GetPtr<DeviceStreamInfo>(); |
| 633 | auto hostStreamInfo = dataInventory.GetPtr<HostStreamInfo>(); | 636 | auto hostStreamInfo = dataInventory.GetPtr<HostStreamInfo>(); |
| @@ -19,8 +19,10 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | + | ||
| 22 | 23 | ||
| 23 | 24 | ||
| 25 | + | ||
| 24 | 26 | ||
| 25 | 27 | ||
| 26 | 28 | ||
| @@ -175,9 +177,9 @@ bool Reserve(std::vector<T> &vec, size_t s) | |||
| 175 | { | 177 | { |
| 176 | vec.reserve(s); | 178 | vec.reserve(s); |
| 177 | } | 179 | } |
| 178 | - catch (...) | 180 | + catch (const std::exception &e) |
| 179 | { | 181 | { |
| 180 | - ERROR("Reserve vector failed"); | 182 | + ERROR("Reserve vector failed, data type=%, size=%, reason=%", typeid(T).name(), s, e.what()); |
| 181 | return false; | 183 | return false; |
| 182 | } | 184 | } |
| 183 | return true; | 185 | return true; |
| @@ -190,9 +192,9 @@ bool Resize(std::vector<T> &vec, size_t s) | |||
| 190 | { | 192 | { |
| 191 | vec.resize(s); | 193 | vec.resize(s); |
| 192 | } | 194 | } |
| 193 | - catch (...) | 195 | + catch (const std::exception &e) |
| 194 | { | 196 | { |
| 195 | - ERROR("Resize vector failed"); | 197 | + ERROR("Resize vector failed, data type=%, size=%, reason=%", typeid(T).name(), s, e.what()); |
| 196 | return false; | 198 | return false; |
| 197 | } | 199 | } |
| 198 | return true; | 200 | return true; |
| @@ -697,6 +697,94 @@ TEST_F(AicpuPersistenceSaveUtest, ShouldOnlyWriteAiCpuDbFileWhenSaveBothNodeAndD | |||
| 697 | EXPECT_TRUE(dbRunner.CheckTableExists("AiCpuDP")); | 697 | EXPECT_TRUE(dbRunner.CheckTableExists("AiCpuDP")); |
| 698 | } | 698 | } |
| 699 | 699 | ||
| 700 | +// ========================================================================= | ||
| 701 | +// GenerateAndSaveData — 多 device 实例各自落盘到自己的目录 | ||
| 702 | +// 回归测试:dataProcessMap 不能声明为 static。static 会让后续 device 实例 | ||
| 703 | +// 复用首次调用捕获的 this/deviceFilePath,导致所有卡的 aicpu 数据 | ||
| 704 | +// 全部写进第一张卡的 ai_cpu.db(旧 bug:各卡数据累加和 = 单卡 db 条数)。 | ||
| 705 | +// ========================================================================= | ||
| 706 | + | ||
| 707 | +class AicpuPersistenceMultiDeviceSaveUtest : public Test { | ||
| 708 | +protected: | ||
| 709 | + void SetUp() override | ||
| 710 | + { | ||
| 711 | + devicePath0_ = "./aicpu_multi_device_0"; | ||
| 712 | + devicePath1_ = "./aicpu_multi_device_1"; | ||
| 713 | + EXPECT_TRUE(File::CreateDir(devicePath0_)); | ||
| 714 | + EXPECT_TRUE(File::CreateDir(File::PathJoin({devicePath0_, "sqlite"}))); | ||
| 715 | + EXPECT_TRUE(File::CreateDir(devicePath1_)); | ||
| 716 | + EXPECT_TRUE(File::CreateDir(File::PathJoin({devicePath1_, "sqlite"}))); | ||
| 717 | + persistence0_ = std::make_shared<AicpuPersistence>(); | ||
| 718 | + persistence1_ = std::make_shared<AicpuPersistence>(); | ||
| 719 | + // freq=1000, sysCnt=1000, hostMonotonic=1000,时间换算结果确定无溢出 | ||
| 720 | + persistence0_->params_ = SyscntConversionParams(1000.0, 1000, 1000); | ||
| 721 | + persistence1_->params_ = SyscntConversionParams(1000.0, 1000, 1000); | ||
| 722 | + } | ||
| 723 | + | ||
| 724 | + void TearDown() override | ||
| 725 | + { | ||
| 726 | + EXPECT_TRUE(File::RemoveDir(devicePath0_, 0)); | ||
| 727 | + EXPECT_TRUE(File::RemoveDir(devicePath1_, 0)); | ||
| 728 | + } | ||
| 729 | + | ||
| 730 | + AicpuData CreateNodeData(uint32_t taskId, uint64_t runStartTick, uint64_t runEndTick) | ||
| 731 | + { | ||
| 732 | + AicpuData data; | ||
| 733 | + data.type = AicpuType::AICPU_NODE; | ||
| 734 | + data.taskId.streamId = 1; | ||
| 735 | + data.taskId.taskId = taskId; | ||
| 736 | + data.node.runStartTick = runStartTick; | ||
| 737 | + data.node.runEndTick = runEndTick; | ||
| 738 | + data.node.computeStartTime = 1000; | ||
| 739 | + data.node.memcpyStartTime = 1200; | ||
| 740 | + data.node.memcpyEndTime = 1500; | ||
| 741 | + data.node.dispatchTime = 300; | ||
| 742 | + data.node.submitTick = 900; | ||
| 743 | + data.node.tickAfterRun = runEndTick + 100; | ||
| 744 | + return data; | ||
| 745 | + } | ||
| 746 | + | ||
| 747 | +protected: | ||
| 748 | + std::string devicePath0_; | ||
| 749 | + std::string devicePath1_; | ||
| 750 | + std::shared_ptr<AicpuPersistence> persistence0_; | ||
| 751 | + std::shared_ptr<AicpuPersistence> persistence1_; | ||
| 752 | +}; | ||
| 753 | + | ||
| 754 | +TEST_F(AicpuPersistenceMultiDeviceSaveUtest, ShouldSaveEachDeviceDataToItsOwnDbPath) | ||
| 755 | +{ | ||
| 756 | + // 两张卡各自构造一份 node 数据,taskId 用于区分来源 | ||
| 757 | + persistence0_->nodeData_.emplace_back(CreateNodeData(10, 1000, 2000)); | ||
| 758 | + persistence1_->nodeData_.emplace_back(CreateNodeData(20, 3000, 4000)); | ||
| 759 | + | ||
| 760 | + ASSERT_EQ(ANALYSIS_OK, persistence0_->GenerateAndSaveData(devicePath0_)); | ||
| 761 | + ASSERT_EQ(ANALYSIS_OK, persistence1_->GenerateAndSaveData(devicePath1_)); | ||
| 762 | + | ||
| 763 | + using NodeRow = std::tuple<uint32_t, uint16_t, double, double, std::string, uint64_t, uint64_t, double, uint64_t, | ||
| 764 | + double>; | ||
| 765 | + | ||
| 766 | + // device0 的 ai_cpu.db 只含 device0 的数据(1 条,task_id=10) | ||
| 767 | + std::string dbPath0 = File::PathJoin({devicePath0_, "sqlite", "ai_cpu.db"}); | ||
| 768 | + EXPECT_TRUE(File::Exist(dbPath0)); | ||
| 769 | + DBRunner dbRunner0(dbPath0); | ||
| 770 | + EXPECT_TRUE(dbRunner0.CheckTableExists("AiCpuData")); | ||
| 771 | + std::vector<NodeRow> rows0; | ||
| 772 | + EXPECT_TRUE(dbRunner0.QueryData("SELECT * FROM AiCpuData", rows0)); | ||
| 773 | + ASSERT_EQ(rows0.size(), 1); | ||
| 774 | + EXPECT_EQ(std::get<1>(rows0[0]), 10); | ||
| 775 | + | ||
| 776 | + // device1 的 ai_cpu.db 只含 device1 的数据(1 条,task_id=20)。 | ||
| 777 | + // 回归点:旧 static bug 下 device1 的数据被写入 device0 的目录,这里不存在。 | ||
| 778 | + std::string dbPath1 = File::PathJoin({devicePath1_, "sqlite", "ai_cpu.db"}); | ||
| 779 | + EXPECT_TRUE(File::Exist(dbPath1)); | ||
| 780 | + DBRunner dbRunner1(dbPath1); | ||
| 781 | + EXPECT_TRUE(dbRunner1.CheckTableExists("AiCpuData")); | ||
| 782 | + std::vector<NodeRow> rows1; | ||
| 783 | + EXPECT_TRUE(dbRunner1.QueryData("SELECT * FROM AiCpuData", rows1)); | ||
| 784 | + ASSERT_EQ(rows1.size(), 1); | ||
| 785 | + EXPECT_EQ(std::get<1>(rows1[0]), 20); | ||
| 786 | +} | ||
| 787 | + | ||
| 700 | 788 | ||
| 701 | } // namespace | 789 | } // namespace |
| 702 | } // namespace Domain | 790 | } // namespace Domain |
| @@ -15,6 +15,8 @@ | |||
| 15 | * -------------------------------------------------------------------------*/ | 15 | * -------------------------------------------------------------------------*/ |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | + | ||
| 19 | + | ||
| 18 | 20 | ||
| 19 | 21 | ||
| 20 | 22 | ||
| @@ -257,4 +259,48 @@ TEST_F(UtilsUTest, TestDivideByPowersOfTenWithPrecisionShouldReturnTrueValue) | |||
| 257 | 259 | ||
| 258 | value = 78; // 入参78 | 260 | value = 78; // 入参78 |
| 259 | EXPECT_EQ("0.07", DivideByPowersOfTenWithPrecision(value, 2, 3)); // 长度小于3位,移动3位,精度2位 | 261 | EXPECT_EQ("0.07", DivideByPowersOfTenWithPrecision(value, 2, 3)); // 长度小于3位,移动3位,精度2位 |
| 262 | +} | ||
| 263 | + | ||
| 264 | +// ========================================================================= | ||
| 265 | +// Reserve / Resize — 异常路径看护 | ||
| 266 | +// 生产中出现超大 size 时,reserve/resize 抛异常必须被捕获并返回 false, | ||
| 267 | +// 而不是让异常向上传播导致进程崩溃 | ||
| 268 | +// ========================================================================= | ||
| 269 | + | ||
| 270 | +TEST_F(UtilsUTest, TestReserveShouldReturnTrueWhenSizeIsNormal) | ||
| 271 | +{ | ||
| 272 | + std::vector<int> vec; | ||
| 273 | + EXPECT_TRUE(Reserve(vec, 10)); | ||
| 274 | + EXPECT_GE(vec.capacity(), static_cast<size_t>(10)); | ||
| 275 | +} | ||
| 276 | + | ||
| 277 | +TEST_F(UtilsUTest, TestReserveShouldReturnFalseWhenSizeExceedsMax) | ||
| 278 | +{ | ||
| 279 | + std::vector<int> vec; | ||
| 280 | + // 超过 max_size 会抛 std::length_error,应被捕获并返回 false | ||
| 281 | + EXPECT_FALSE(Reserve(vec, std::numeric_limits<size_t>::max())); | ||
| 282 | + EXPECT_TRUE(vec.empty()); | ||
| 283 | + // 异常路径不应破坏已存在的数据 | ||
| 284 | + vec = {1, 2, 3}; | ||
| 285 | + EXPECT_FALSE(Reserve(vec, std::numeric_limits<size_t>::max())); | ||
| 286 | + EXPECT_EQ(vec.size(), static_cast<size_t>(3)); | ||
| 287 | +} | ||
| 288 | + | ||
| 289 | +TEST_F(UtilsUTest, TestResizeShouldReturnTrueWhenSizeIsNormal) | ||
| 290 | +{ | ||
| 291 | + std::vector<int> vec; | ||
| 292 | + EXPECT_TRUE(Resize(vec, 10)); | ||
| 293 | + EXPECT_EQ(vec.size(), static_cast<size_t>(10)); | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +TEST_F(UtilsUTest, TestResizeShouldReturnFalseWhenSizeExceedsMax) | ||
| 297 | +{ | ||
| 298 | + std::vector<int> vec; | ||
| 299 | + // 超过 max_size 会抛 std::length_error,应被捕获并返回 false | ||
| 300 | + EXPECT_FALSE(Resize(vec, std::numeric_limits<size_t>::max())); | ||
| 301 | + EXPECT_TRUE(vec.empty()); | ||
| 302 | + // 异常路径不应破坏已存在的数据 | ||
| 303 | + vec = {1, 2, 3}; | ||
| 304 | + EXPECT_FALSE(Resize(vec, std::numeric_limits<size_t>::max())); | ||
| 305 | + EXPECT_EQ(vec.size(), static_cast<size_t>(3)); | ||
| 260 | } | 306 | } |
Rtest/st/l0_test_ascend_msprof_matmul_basic_api.sh→test/st/l1_test_ascend_msprof_matmul_basic_api.sh+0-0
文件重命名但无更改。
Rtest/st/l0_test_ascend_msprof_matmul_leakyrelu_basic_api.sh→test/st/l1_test_ascend_msprof_matmul_leakyrelu_basic_api.sh+0-0
文件重命名但无更改。
Rtest/st/src/l0_test_ascend_msprof_matmul_basic_api.py→test/st/src/l1_test_ascend_msprof_matmul_basic_api.py+0-0
文件重命名但无更改。
Rtest/st/src/l0_test_ascend_msprof_matmul_leakyrelu_basic_api.py→test/st/src/l1_test_ascend_msprof_matmul_leakyrelu_basic_api.py+0-0
文件重命名但无更改。