| fix: 修复Session GC对default allocator所有权管理缺陷;Python Tensor.to_host 去 padding
Co-authored-by: du-hua1024<duhua2@huawei.com>
# message auto-generated for no-merge-commit merge:
!2297 merge master into develop
fix: 修复Session GC对default allocator所有权管理缺陷;Python Tensor.to_host 去 padding
Created-by: du-hua1024
Commit-by: du-hua1024
Merged-by: cann-robot
Description: # Pull Request
## 描述
1、修复 Python Session 析构(GC)时 default allocator 清理的所有权管理问题。
run_graph_with_stream_async() 在某个 stream 未注册 external allocator 时,会自动注册 Python default allocator。旧逻辑仅在当前 session 的 _default_allocator_streams 中记录 stream,析构时按 stream 直接 unregister,无法判断当前 stream 上的 allocator 是否仍然是该 session 当初自动注册的 default allocator,可能误删后续由其他 session 注册的 allocator。
### 需要覆盖的关键场景
1. **同一 session 覆盖**
session1 自动注册 default_A 后,又通过 register_external_allocator() 注册 custom allocator。析构时不能再按 default 清理该 stream。
2. **跨 session custom 覆盖**
session1 自动注册 default_A,随后 session2 注册 custom_B。session1 析构时不能 unregister custom_B。
3. **跨 session default 重新归属**
session1 注册 default_A → session2 注册 custom_B → session3 再次触发自动注册 default_C。此时 session1 析构时不能因为当前 stream 仍是 default allocator 就误删 session3 的 default_C。
4. **Python wrapper 外部改动兜底**
如果 C++ 侧或其他 wrapper 路径绕过 Python 状态表修改了 stream allocator,析构前还需要通过 C wrapper 查询当前 allocator 是否仍为 Python default allocator,避免仅依赖 Python 侧记录。
5. **并发窗口**
HasDefaultAllocator -> unregister 属于 check-then-act 操作。Python wrapper 内通过同一把锁串行化 default 注册、custom 注册、显式注销和析构清理,避免判断后被其他 Python session 插入注册操作。
### 设计方案
- 引入 _stream_to_default_allocator_owner:维护 stream -> weakref(session),记录当前 stream 的 Python default allocator 归属 session。
- register_external_allocator() 成功后清理当前 stream 的 default owner 记录,表示该 stream 已被 custom allocator 覆盖。
- _ensure_default_allocator() 成功注册 default allocator 后,记录当前 session 为该 stream 的 default owner。
- Session.__del__() 提取 _unregister_default_allocators(),析构时仅在以下条件同时满足时才 unregister:
- 当前 session 仍是该 stream 的 default owner;
- C++ 当前 allocator 仍是 Python default allocator。
- 新增 _default_allocator_lock,保护 Python wrapper 内 allocator 注册/注销和 owner 状态更新。
- 新增 GeApiWrapper_HasDefaultAllocator C wrapper API,通过 PyCallbackAllocator::is_default_allocator 区分 Python default allocator 和 Python custom allocator。
- register / unregister 相关路径仅在 C 侧返回成功(ret == 0)后同步更新 Python 侧状态。
2、Python Tensor.to_host 去 padding
### 背景
Python 异步执行接口使用 default allocator 创建输出 Tensor 时,runtime 侧 device buffer 可能按 allocator 规则进行对齐,Tensor::GetSize() 表示实际 storage size,可能大于 shape 对应的逻辑数据大小。例如 [2, 3] 的 FP32 输出逻辑上只有 6 个元素,但 storage size 对齐后可能被 Python 侧按 16 个元素解析,导致 Length of list 16 does not match shape 6。
之前由于 TensorValueUtils::ConvertTensorValue是按 shape大小取的值,所以问题没有暴露出来,当前TensorValueUtils::ConvertTensorValue修改为按 Tensor data size 算元素数,所以后面 Tensor._unflatten 就发现shape和data个数对不上了。
### 修改方案
- GeApiWrapper_Tensor_ToHost 不再把 device tensor 的 storage size 直接作为 host data size。
- 通过 tensor desc 的 shape、format 和 dtype 调用 TensorUtils::CalcTensorMemSize 计算 host 可见的逻辑数据大小,只拷贝有效数据。
- Tensor::GetSize() 仅作为 device storage 上限校验:当 storage size 小于逻辑大小时返回失败,避免越界拷贝。
- logical size 为 0 时清空 host data 并设置 placement 为 host;只有 logical size 大于 0 时才检查 device pointer 并执行 D2H 拷贝。
### 附带清理
本 PR 还保留了 examples/offline_compile_run/cpp 中两处魔数清理:
- kArgIndexAfterCommand
- kInferOutputFloatsPerLine
该清理不影响核心 bug 修复逻辑,属于同 PR 附带的代码规范改进。
## 变更类型
- [x] 🐛 Bug 修复
- [ ] ✨ 新功能
- [ ] 💄 代码风格更新(格式化,局部变量)
- [ ] ♻️ 重构(既不修复错误也不增加功能的代码变动)
- [ ] 📦 构建过程或辅助工具的变动
- [ ] 📝 文档内容更新
## 关联的Issue
## 如何测试
新增/更新 Python session allocator 相关单元测试,覆盖:
1. custom allocator 覆盖 default allocator 后,Python default owner 状态被清理;
2. 析构时只清理当前 session 仍持有的 default allocator;
3. 当前 stream owner 已变更为其他 session 时,旧 session 析构不 unregister;
4. C++/wrapper 绕过 Python owner 状态导致当前 allocator 不再是 default 时,析构不 unregister;
5. C 侧 unregister 失败时,不提前清理 Python 侧状态。
已执行基础检查:
```bash
python3 -m py_compile api/python/ge/ge/session/session.py tests/ge/ut/ge/graph/pyge_tests/session_test.py
git diff --check
```
## 核对清单
- [x] 我的代码遵循了项目的代码风格
- [x] 我已对代码进行了自测
- [x] 我已更新了相关的文档
- [x] 我在标题中使用了合适的类型标签(如:feat:, fix:)
- [x] 我已经详细阅读了贡献指南(CONTRIBUTING.md),并遵守了其中的所有规定,包括但不限于commit message的格式、无效commit的合并等
## 其他信息
See merge request: cann/ge!2297 | 1 个月前 |