已合并
【PR】: [fix] 修复Dump txt相关问题 #1907
xchu42创建于 19 天前
【PR】: [fix] 修复Dump txt相关问题 #1907
已合并
共 3 个文件变更+103-34
| @@ -1563,44 +1563,57 @@ std::string DumpGraphStructureView(const ascir::Graph &graph, const DumpContext | |||
| 1563 | 1563 | ||
| 1564 | namespace { | 1564 | namespace { |
| 1565 | void CollectQueueInfo(const af::AscNodePtr &node, size_t topo_id, std::map<int32_t, dumper::QueueInfo> &queues) { | 1565 | void CollectQueueInfo(const af::AscNodePtr &node, size_t topo_id, std::map<int32_t, dumper::QueueInfo> &queues) { |
| 1566 | - if (node->outputs().empty()) { | 1566 | + const size_t output_count = node->outputs().size(); |
| 1567 | - return; | 1567 | + if (output_count == 0U) { |
| 1568 | - } | ||
| 1569 | - auto &output_attr = node->outputs()[0]->attr; | ||
| 1570 | - auto &mem = output_attr.mem; | ||
| 1571 | - if (mem.alloc_type != af::AllocType::kAllocTypeQueue) { | ||
| 1572 | return; | 1568 | return; |
| 1573 | } | 1569 | } |
| 1570 | + for (size_t i = 0U; i < output_count; ++i) { | ||
| 1571 | + auto &output_attr = node->outputs()[i]->attr; | ||
| 1572 | + auto &mem = output_attr.mem; | ||
| 1573 | + if (mem.alloc_type != af::AllocType::kAllocTypeQueue) { | ||
| 1574 | + continue; | ||
| 1575 | + } | ||
| 1574 | 1576 | ||
| 1575 | - int32_t que_id = output_attr.que.id; | 1577 | + int32_t que_id = output_attr.que.id; |
| 1576 | - if (queues.find(que_id) == queues.end()) { | 1578 | + const int32_t buf_num = static_cast<int32_t>(output_attr.que.buf_num); |
| 1577 | - dumper::QueueInfo info; | 1579 | + if (queues.find(que_id) == queues.end()) { |
| 1578 | - info.que_id = que_id; | 1580 | + dumper::QueueInfo info; |
| 1579 | - info.depth = output_attr.que.depth; | 1581 | + info.que_id = que_id; |
| 1580 | - info.buf_num = static_cast<int32_t>(output_attr.que.buf_num); | 1582 | + info.depth = output_attr.que.depth; |
| 1581 | - info.position = "TPosition::" + PositionToString(mem.position); | 1583 | + info.buf_num = buf_num; |
| 1582 | - queues[que_id] = info; | 1584 | + info.position = "TPosition::" + PositionToString(mem.position); |
| 1585 | + queues[que_id] = info; | ||
| 1586 | + } else { | ||
| 1587 | + // 复用场景下同一 que 的多个 tensor 可能携带不同 buf_num, | ||
| 1588 | + // 与 codegen LocalTQueAlloc 的 que 级聚合语义保持一致:取 max | ||
| 1589 | + queues[que_id].buf_num = std::max(queues[que_id].buf_num, buf_num); | ||
| 1590 | + } | ||
| 1591 | + const std::string suffix = (output_count > 1U) ? ("[" + std::to_string(i) + "]") : ""; | ||
| 1592 | + queues[que_id].nodes.push_back({topo_id, node->GetName(), static_cast<int32_t>(mem.reuse_id), "", suffix}); | ||
| 1583 | } | 1593 | } |
| 1584 | - queues[que_id].nodes.push_back({topo_id, node->GetName(), static_cast<int32_t>(mem.reuse_id), ""}); | ||
| 1585 | } | 1594 | } |
| 1586 | 1595 | ||
| 1587 | void CollectBufferInfo(const af::AscNodePtr &node, size_t topo_id, std::map<int32_t, dumper::BufferInfo> &buffers) { | 1596 | void CollectBufferInfo(const af::AscNodePtr &node, size_t topo_id, std::map<int32_t, dumper::BufferInfo> &buffers) { |
| 1588 | - if (node->outputs().empty()) { | 1597 | + const size_t output_count = node->outputs().size(); |
| 1589 | - return; | 1598 | + if (output_count == 0U) { |
| 1590 | - } | ||
| 1591 | - auto &output_attr = node->outputs()[0]->attr; | ||
| 1592 | - auto &mem = output_attr.mem; | ||
| 1593 | - if (mem.alloc_type != af::AllocType::kAllocTypeBuffer) { | ||
| 1594 | return; | 1599 | return; |
| 1595 | } | 1600 | } |
| 1601 | + for (size_t i = 0U; i < output_count; ++i) { | ||
| 1602 | + auto &output_attr = node->outputs()[i]->attr; | ||
| 1603 | + auto &mem = output_attr.mem; | ||
| 1604 | + if (mem.alloc_type != af::AllocType::kAllocTypeBuffer) { | ||
| 1605 | + continue; | ||
| 1606 | + } | ||
| 1596 | 1607 | ||
| 1597 | - int32_t buf_id = output_attr.buf.id; | 1608 | + int32_t buf_id = output_attr.buf.id; |
| 1598 | - if (buffers.find(buf_id) == buffers.end()) { | 1609 | + if (buffers.find(buf_id) == buffers.end()) { |
| 1599 | - dumper::BufferInfo info; | 1610 | + dumper::BufferInfo info; |
| 1600 | - info.buf_id = buf_id; | 1611 | + info.buf_id = buf_id; |
| 1601 | - buffers[buf_id] = info; | 1612 | + buffers[buf_id] = info; |
| 1613 | + } | ||
| 1614 | + const std::string suffix = (output_count > 1U) ? ("[" + std::to_string(i) + "]") : ""; | ||
| 1615 | + buffers[buf_id].nodes.push_back({topo_id, node->GetName(), "", false, 0, suffix}); | ||
| 1602 | } | 1616 | } |
| 1603 | - buffers[buf_id].nodes.push_back({topo_id, node->GetName(), "", false, 0}); | ||
| 1604 | } | 1617 | } |
| 1605 | 1618 | ||
| 1606 | std::string GetTmpBufSizeStr(const af::TmpBufDesc &buf_desc) { | 1619 | std::string GetTmpBufSizeStr(const af::TmpBufDesc &buf_desc) { |
| @@ -1628,7 +1641,7 @@ void CollectTmpBufferInfo(const af::AscNodePtr &node, size_t topo_id, std::map<i | |||
| 1628 | buffers[buf_id] = info; | 1641 | buffers[buf_id] = info; |
| 1629 | } | 1642 | } |
| 1630 | std::string size_str = GetTmpBufSizeStr(tmp_buf.buf_desc); | 1643 | std::string size_str = GetTmpBufSizeStr(tmp_buf.buf_desc); |
| 1631 | - buffers[buf_id].nodes.push_back({topo_id, node->GetName(), size_str, true, static_cast<int32_t>(i)}); | 1644 | + buffers[buf_id].nodes.push_back({topo_id, node->GetName(), size_str, true, static_cast<int32_t>(i), ""}); |
| 1632 | } | 1645 | } |
| 1633 | } | 1646 | } |
| 1634 | 1647 | ||
| @@ -1674,7 +1687,7 @@ void DumpQueues(std::stringstream &ss, const std::map<int32_t, dumper::QueueInfo | |||
| 1674 | for (auto &reuse_entry : reuse_groups) { | 1687 | for (auto &reuse_entry : reuse_groups) { |
| 1675 | auto &nodes = reuse_entry.second; | 1688 | auto &nodes = reuse_entry.second; |
| 1676 | for (size_t i = 0; i < nodes.size(); ++i) { | 1689 | for (size_t i = 0; i < nodes.size(); ++i) { |
| 1677 | - ss << " [" << nodes[i].topo_id << "] " << nodes[i].node_name << ".y" << std::endl; | 1690 | + ss << " [" << nodes[i].topo_id << "] " << nodes[i].node_name << ".y" << nodes[i].tensor_suffix << std::endl; |
| 1678 | } | 1691 | } |
| 1679 | } | 1692 | } |
| 1680 | ss << std::endl; | 1693 | ss << std::endl; |
| @@ -1714,7 +1727,7 @@ void DumpBuffers(std::stringstream &ss, const std::map<int32_t, dumper::BufferIn | |||
| 1714 | ss << " # size:" << node_info.size_str; | 1727 | ss << " # size:" << node_info.size_str; |
| 1715 | } | 1728 | } |
| 1716 | } else { | 1729 | } else { |
| 1717 | - ss << ".y"; | 1730 | + ss << ".y" << node_info.tensor_suffix; |
| 1718 | } | 1731 | } |
| 1719 | ss << std::endl; | 1732 | ss << std::endl; |
| 1720 | } | 1733 | } |
| @@ -198,7 +198,8 @@ struct QueueNodeInfo { | |||
| 198 | size_t topo_id = 0; | 198 | size_t topo_id = 0; |
| 199 | std::string node_name; | 199 | std::string node_name; |
| 200 | int32_t reuse_id = -1; | 200 | int32_t reuse_id = -1; |
| 201 | - std::string size_str; // tensor 的 vector<> 格式大小 | 201 | + std::string size_str; // tensor 的 vector<> 格式大小 |
| 202 | + std::string tensor_suffix; // 多输出节点为 "[i]",单输出为 "" | ||
| 202 | }; | 203 | }; |
| 203 | 204 | ||
| 204 | /** | 205 | /** |
| @@ -218,9 +219,10 @@ struct QueueInfo { | |||
| 218 | struct BufferNodeInfo { | 219 | struct BufferNodeInfo { |
| 219 | size_t topo_id = 0; | 220 | size_t topo_id = 0; |
| 220 | std::string node_name; | 221 | std::string node_name; |
| 221 | - std::string size_str; // tensor 的 vector<> 格式大小 | 222 | + std::string size_str; // tensor 的 vector<> 格式大小 |
| 222 | - bool is_tmpbuf = false; // 是否为节点的 tmpbuf | 223 | + bool is_tmpbuf = false; // 是否为节点的 tmpbuf |
| 223 | - int32_t tmpbuf_idx = 0; // tmpbuf 的索引(仅当 is_tmpbuf=true 时有效) | 224 | + int32_t tmpbuf_idx = 0; // tmpbuf 的索引(仅当 is_tmpbuf=true 时有效) |
| 225 | + std::string tensor_suffix; // 多输出节点为 "[i]",单输出为 "" | ||
| 224 | }; | 226 | }; |
| 225 | 227 | ||
| 226 | /** | 228 | /** |
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | + | ||
| 18 | 19 | ||
| 19 | 20 | ||
| 20 | 21 | ||
| @@ -1068,4 +1069,57 @@ tiling_def, host_impl, device_impl = fuser.codegen(schedule_results) | |||
| 1068 | EXPECT_EQ(expected_graph_code, ReadFileContent("./asc_wrong_graph_python.py")); | 1069 | EXPECT_EQ(expected_graph_code, ReadFileContent("./asc_wrong_graph_python.py")); |
| 1069 | } | 1070 | } |
| 1070 | 1071 | ||
| 1072 | +// 验证 DumpMemoryLayoutView 对多输出节点的收集: | ||
| 1073 | +// 多输出节点的每个 output 的 que/buf 信息都应收集,且命名为 y[i] | ||
| 1074 | +TEST_F(AscendGraphCodeDumperUT, test_memory_layout_view_multi_output) { | ||
| 1075 | + AscGraph graph("multi_output_layout"); | ||
| 1076 | + Expression s0 = graph.CreateSizeVar("s0"); | ||
| 1077 | + Expression s1 = graph.CreateSizeVar("s1"); | ||
| 1078 | + Axis &z0 = graph.CreateAxis("z0", s0); | ||
| 1079 | + Axis &z1 = graph.CreateAxis("z1", s1); | ||
| 1080 | + | ||
| 1081 | + ascir_op::Data data("data", graph); | ||
| 1082 | + data.attr.sched.axis = {z0.id, z1.id}; | ||
| 1083 | + data.y.dtype = DT_FLOAT16; | ||
| 1084 | + | ||
| 1085 | + ascir_op::Load load("load"); | ||
| 1086 | + load.x = data.y; | ||
| 1087 | + load.attr.sched.axis = {z0.id, z1.id}; | ||
| 1088 | + *load.y.axis = {z0.id, z1.id}; | ||
| 1089 | + load.y.dtype = DT_FLOAT16; | ||
| 1090 | + *load.y.repeats = {s0, s1}; | ||
| 1091 | + *load.y.strides = {s1, One}; | ||
| 1092 | + | ||
| 1093 | + ascir_op::Split split("split"); | ||
| 1094 | + split.InstanceOutputy(3U); | ||
| 1095 | + split.x = load.y; | ||
| 1096 | + split.attr.sched.axis = {z0.id, z1.id}; | ||
| 1097 | + split.attr.api.compute_type = ComputeType::kComputeSplit; | ||
| 1098 | + for (size_t i = 0UL; i < 3UL; ++i) { | ||
| 1099 | + split.y[i].dtype = DT_FLOAT16; | ||
| 1100 | + *split.y[i].axis = {z0.id, z1.id}; | ||
| 1101 | + *split.y[i].repeats = {s0, s1}; | ||
| 1102 | + *split.y[i].strides = {s1, One}; | ||
| 1103 | + // output[0] 用 queue,output[1]/[2] 用 buffer,覆盖两种收集路径 | ||
| 1104 | + split.y[i].mem->alloc_type = (i == 0UL) ? AllocType::kAllocTypeQueue : AllocType::kAllocTypeBuffer; | ||
| 1105 | + if (i == 0UL) { | ||
| 1106 | + split.y[i].que->id = 7; | ||
| 1107 | + split.y[i].que->depth = 2; | ||
| 1108 | + split.y[i].que->buf_num = 2; | ||
| 1109 | + } else { | ||
| 1110 | + split.y[i].buf->id = static_cast<int64_t>(i); | ||
| 1111 | + } | ||
| 1112 | + } | ||
| 1113 | + | ||
| 1114 | + const std::string layout = ::ascir::dumper::DumpMemoryLayoutView(graph, true); | ||
| 1115 | + // Queue 7 来自 split 的 output[0] | ||
| 1116 | + EXPECT_NE(layout.find("Queue 7"), std::string::npos); | ||
| 1117 | + EXPECT_NE(layout.find("split.y[0]"), std::string::npos) << layout; | ||
| 1118 | + // Buffer 1/2 来自 split 的 output[1]/[2],修复前会缺失 | ||
| 1119 | + EXPECT_NE(layout.find("Buffer 1"), std::string::npos) << layout; | ||
| 1120 | + EXPECT_NE(layout.find("Buffer 2"), std::string::npos) << layout; | ||
| 1121 | + EXPECT_NE(layout.find("split.y[1]"), std::string::npos) << layout; | ||
| 1122 | + EXPECT_NE(layout.find("split.y[2]"), std::string::npos) << layout; | ||
| 1123 | +} | ||
| 1124 | + | ||
| 1071 | } // namespace af | 1125 | } // namespace af |