Callback 与 Allocator 安全桥接路线:从 Pointer-Free Readiness 到真实 Runtime Proof
写在前面
TensorRT callback 不是普通的 P/Invoke 函数。
普通函数调用在返回后通常结束跨语言关系;callback 会把一个可长期存活的对象、vtable、managed delegate、线程切换、borrowed pointer 和释放顺序同时带入 native runtime。任何一个生命周期环节模糊,都可能表现为随机崩溃、double free、回调进入已释放 delegate、异常穿过 C ABI,或者 device memory 在仍被 TensorRT 使用时提前释放。
因此 TensorRtSharp4.0 不以“manifest 里有入口”作为 callback 完成标准。本文给出从 copied metadata、managed owner、native no-throw vtable、attach/detach、in-flight accounting 到真实 package consumer invocation proof 的完整路线,并说明为什么 direct callback rows 当前仍必须保留 deferred history。
适用读者
- 设计 C++/C# callback bridge 的维护者。
- 审核 allocator、output allocator、debug listener 或 stream reader/writer 生命周期的 reviewer。
- 需要理解 managed readiness 与 real callback runtime proof 差异的 release owner。
- 排查 callback dispose、native vtable、device pointer 和 stream ordering 问题的工程师。
解决问题
本文解决:
- callback 为什么不能直接暴露
IntPtr/nint。 - 当前仓库已有哪几层安全组件。
- 五个 callback family 分别缺什么。
- TRT8/TRT10/TRT11 应如何独立 guard。
- native/managed owner 如何建立对称生命周期。
- 真实 callback invocation proof 要记录哪些字段。
- 哪些 evidence 只能保持 managed readiness,不能移除 deferred。
背景与场景
TensorRT callback family 包括:
IGpuAllocator;IGpuAsyncAllocator;IOutputAllocator;IDebugListener;IStreamReader/IStreamReaderV2/IStreamWriter;- logger、profiler、progress monitor 等已采用独立受控 wrapper 的 callback。
这些 family 的共同难点不是“能否声明一个 delegate”,而是 runtime 是否在 owner 存活期间真实调用它,以及 callback 返回后 native/managed/device 状态是否仍满足 TensorRT 合同。
当前结论
当前 pointer-free managed readiness 已经形成多个可调用诊断面,但 real callback runtime proof 仍未闭环:
- closure matrix 有 5 个 family;
- closure-ready family 当前为 0;
- runtime-proof-attempt-ready family 当前为 0;
- package-consumer-runtime-proof-ready family 当前为 0;
- execution pack 仍缺 14 类 owner 输入;
DeferredRowsStillRequired=true;- callback execution pack 保持
blocked-owner-action-required。
这个结论并不表示所有 callback 代码都是空白。它表示“安全组件存在”与“真实 TensorRT runtime invocation 已证明”之间仍有未完成的列。
六层证据模型
flowchart TD
A["Copied interface metadata"] --> B["Managed owner state machine"]
B --> C["Native non-copyable owner storage"]
C --> D["No-throw vtable and exception mapping"]
D --> E["Attach/detach + in-flight drain"]
E --> F["Opt-in compatible-host runtime smoke"]
F --> G["External package consumer callback proof"]
G --> H["Deferred promotion review"]
任何一层缺失都不能跳到 H。
各层能证明什么
| 层 | 能证明 | 不能证明 |
|---|---|---|
| copied metadata | interface/version/diagnostic 可安全复制 | callback 已安装 |
| managed owner | delegate/状态/释放逻辑可审计 | native vtable 正确 |
| native owner | storage/create/destroy 对称 | TensorRT 已调用 |
| no-throw vtable | exception 不穿 ABI | device pointer ownership 正确 |
| attach/detach | lifecycle ordering 可控 | runtime invocation 已发生 |
| runtime smoke | 指定 callback 在兼容主机被调用 | package consumer route 成立 |
| package proof | 指定 package/key/host callback 闭环 | 所有版本/family 都已完成 |
为什么 Public API 不暴露裸指针
以下 API 形状不可接受:
// 仅用于说明禁止形状,不是仓库 API。
public IntPtr Alloc(ulong size);
public void InstallCallback(IntPtr callback);
public nint DebugTensor { get; }
问题包括:
- 调用方不知道谁释放;
- device/host/borrowed pointer 语义丢失;
- 无法阻止 owner dispose 后继续调用;
- 无法表达 stream 关联和 in-flight 状态;
- SafeHandle 也不能自动解决 borrowed/device pointer 所有权。
公开面应返回 copied scalar/string/array、owner-scoped token、只读 snapshot 或有明确 dispose 语义的高层 owner。
当前代码与文件入口
Pointer-free aggregation
src/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtCallbackAllocatorReadiness.cs与TensorRtCallbackAllocatorReadinessSnapshot.cssrc/JYPPX.TensorRtSharp/Execution/TensorRtExecutionContextCallbackAllocatorSafeControlSummary.cssrc/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrix.cs:只保留五个 family 的 Evaluate 顺序。src/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrix.Allocators.cssrc/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrix.OutputDebug.cssrc/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrix.StreamIo.cssrc/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrix.RowConstruction.cssrc/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrix.Blockers.cssrc/JYPPX.TensorRtSharp/Callbacks/Core/TensorRtCallbackOwnerClosureMatrixRow.cs与TensorRtCallbackOwnerClosureMatrixResult.cssrc/JYPPX.TensorRtSharp/Execution/TensorRtExecutionContext.Readiness.cs
Owner and precheck
src/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.cs:只保留 owner state、constructor 与 properties。src/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.Lifecycle.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.ManagedDryRun.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.NativeDryRun.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.StateLedger.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.InternalPrototype.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorCallbackOwner.ResultMapping.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorDryRunRequest.cs与同目录的 result/snapshot/delegate model 文件。src/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorLedgerSafetyGate.cs与TensorRtAllocatorLedgerSafetyGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtAllocatorInterfaceInfoDesignGate.cs与TensorRtAllocatorInterfaceInfoDesignGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorCallbackOwner.cs:只保留 owner state、constructor 与 properties。src/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorCallbackOwner.DesignDiagnostic.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorCallbackOwner.Snapshots.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorCallbackOwner.Lifecycle.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorCallbackRequest.cs与TensorRtOutputAllocatorCallbackOwnerSnapshot.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorRuntimeGate.cs与其Entries、Snapshots、Lifecycle、Invocation、Trampoline、Formattingpartial 及 internal request/result model。src/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorRuntimeProofPrecheck.cs与TensorRtOutputAllocatorRuntimeProofPrecheckResult.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputAllocatorAttachDetachDesignGate.cs与TensorRtOutputAllocatorAttachDetachDesignGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/MemoryAllocation/TensorRtOutputBufferOwnershipSafetyGate.cs与TensorRtOutputBufferOwnershipSafetyGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackOwner.cs:只保留 owner state、constructor 与 properties。src/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackOwner.DesignDiagnostic.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackOwner.Snapshots.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackOwner.Lifecycle.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackOwner.Trampoline.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackOwner.ShapeFormatting.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackRequest.cs与TensorRtDebugListenerCallbackOwnerSnapshot.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackProofGapReport.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerCallbackProofGapReportResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRuntimeProofPrecheck.cs与其DesignPrerequisites、NativeAttachDesign、OwnerLifecycle、RuntimeScaffold、FinalRuntimeGatespartial。src/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRuntimeProofPrecheckResult.cs
这些文件只做职责归类。16 个 precheck Evaluate overload、closure matrix 的 5 个 family row 顺序、
Dispose -> callback drain -> GCHandle/delegate release 顺序、pointer-free marker 和 real-runtime non-proof 分类均保持不变;
源码 evidence consumer 必须读取完整文件集,不能再把 core 单文件当作完整实现。
OutputAllocator 的 synthetic notify/reallocate runtime gate 与 native ledger dry-run 仍只是 design evidence;拆分不会把它们
升级为 TensorRT 已调用 IOutputAllocator::notifyShape / reallocateOutput 的 runtime proof,也不会解除对应 deferred rows。
DebugListener native/runtime scaffolding
src/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeNoThrowVTableDesignGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeNoThrowVTableDesignGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeNoThrowVTableScaffoldGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeNoThrowVTableScaffoldGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeNoThrowDestructor.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeNoThrowDestructorResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeOwnerNonCopyableStorage.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeOwnerNonCopyableStorageResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerBorrowedTensorSafetyGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerBorrowedTensorSafetyGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachBridgeShapeGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachBridgeShapeGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerInFlightAccountingGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerInFlightAccountingGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachEntryMinimalSafety.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachEntryMinimalSafetyResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachEntryRuntimeScaffold.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachEntryRuntimeScaffoldResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerAttachVTableSafetyGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerAttachVTableSafetyGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachEntryDesignGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeAttachEntryDesignGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeOwnerAddressDesignGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeOwnerAddressDesignGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeOwnerVTableInstallExperiment.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeOwnerVTableInstallExperimentResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeDetachBeforeReleaseDesignGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeDetachBeforeReleaseDesignGateResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeVTableInstallPreflight.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNativeVTableInstallPreflightResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerProcessDebugTensorCallbackTrampoline.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugTensorMetadataSnapshot.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerProcessDebugTensorCallbackTrampolineResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNoThrowVTableCallbackStub.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerNoThrowVTableCallbackStubResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRuntimeProofAttemptPreflight.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRuntimeProofAttemptPreflightResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRealNonNullAttachRuntimeSmoke.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRealNonNullAttachRuntimeSmokeResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRealCallbackRuntimeProof.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerRealCallbackRuntimeProofResult.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerBorrowedDebugTensorMetadataRuntimeGate.cssrc/JYPPX.TensorRtSharp/Callbacks/Debugging/TensorRtDebugListenerBorrowedDebugTensorMetadataRuntimeGateResult.cs
Smoke and proof pack
smoke/CallbackAllocatorSafeControlsSmokeRunnereng/Export-CallbackRuntimeProofExecutionPack.ps1eng/Test-CallbackRuntimeProofExecutionPack.ps1artifacts/final-release/callback-runtime-proof-execution-pack.jsondocs/articles/zh-cn/real-callback-runtime-evidence-schema.md
Managed Readiness 聚合
TensorRtCallbackAllocatorReadinessSnapshot 聚合 logger、profiler、progress monitor、allocator ledger、OutputAllocator precheck 和 DebugListener precheck 的 copied evidence。
关键字段包括:
IsPublishSafeForManagedCallbacks;IsRuntimeInvocationProofComplete;BlockedReasonCount;RuntimeProofBlocked;RealCallbackInvocationProofReady。
它的价值是给高层 wrapper、smoke 和 package consumer 一个统一摘要。它不 attach callback,不创建 native vtable,不证明 TensorRT 已调用 allocator/output/debug listener。
典型 marker:
CallbackAllocatorReadinessSnapshot=managed-readiness
这个 marker 必须保持 non-proof 语义。
ExecutionContext Safe-Control Summary
TensorRtExecutionContextCallbackAllocatorSafeControlSummary 通过:
context.GetCallbackAllocatorSafeControlSummary(outputTensorName)
聚合 output allocator、temporary-storage allocator 和 debug listener 的 copied interface-info availability、diagnostic 和 CopiedInterfaceInfoCount。
它明确:
- copied metadata only;
- borrowed pointer not exposed/owned;
- no callback invocation;
- not runtime proof。
这是用户可调用的只读诊断 API,不是 callback trampoline。
Callback Owner Closure Matrix
TensorRtCallbackOwnerClosureMatrixResult 把每个 family 的闭环列展开:
- managed owner state;
- SafeHandle/GCHandle keep-alive;
- native non-copyable storage;
- create/destroy symmetry;
- attach/detach/clear;
- detach before release;
- no-throw destructor/vtable;
- managed exception capture;
- exception-to-status mapping;
- in-flight callback accounting;
- borrowed pointer escape blocker;
- opt-in runtime smoke;
- package consumer runtime proof;
- deferred rows still required。
RuntimeEvidenceKind=closure-matrix 只是排工和审计证据,不能作为真实 TensorRT callback runtime proof。
五个 Family 当前差距
1. GpuAllocator
方法:
IGpuAllocator::allocate;IGpuAllocator::free/deallocate;IGpuAllocator::reallocate。
当前已有 managed owner prototype、ledger safety gate、pointer-free snapshot 和 dispose diagnostics。
仍需:
- TRT8/TRT10/TRT11 line-specific
setGpuAllocatorattach/detach; - native no-throw vtable;
- managed exception -> bridge status mapping;
- device pointer ledger;
- allocation/free/reallocate size/alignment contract;
- in-flight callback drain;
- real package consumer invocation proof。
device pointer 不能返回给普通 public API。native owner 必须记录内部 token/size/alignment/operation,并在 copied snapshot 中返回统计。
2. GpuAsyncAllocator
方法:
IGpuAsyncAllocator::allocateAsync;IGpuAsyncAllocator::deallocateAsync。
它比同步 allocator 多出 CUDA stream lifetime 和 ordering:
- stream handle 是 borrowed 还是 owner-bound;
- callback 返回时 allocation 是否可立即使用;
- deallocateAsync 与 enqueue 顺序;
- owner dispose 时如何同步/拒绝新调用;
- TRT10/TRT11 API 差异。
在 stream lifetime 未闭环前,不得仅复用同步 allocator trampoline。
3. OutputAllocator
方法:
IOutputAllocator::notifyShape;IOutputAllocator::reallocateOutput。
当前已有:
TensorRtOutputAllocatorCallbackOwner;- attach/detach design gate;
- runtime proof precheck;
- copied owner snapshot;
- pointer escape blocker。
仍需:
- native stable owner;
- no-throw vtable;
- output tensor name copied into owner storage;
- current memory/device pointer ledger;
- requested size/alignment validation;
- dynamic shape notification ordering;
- null/failure result mapping;
- real notifyShape/reallocateOutput invocation log。
notifyShape 不返回 memory,但仍可能与 reallocation 并发或交错。两个 callback 必须共享 owner state machine。
4. DebugListener
方法:
IDebugListener::processDebugTensor。
仓库已建立较多专门组件:
- non-copyable native owner/lifecycle gate;
- no-throw destructor/vtable scaffold;
- managed exception capture/status mapping;
- in-flight accounting;
TensorRtDebugListenerProcessDebugTensorCallbackTrampoline;TensorRtDebugListenerRealCallbackRuntimeProof数据模型。
仍不能直接宣布完成,因为 closure 还要求:
- non-null attach 在目标 TensorRT line 真正启用;
- TensorRT runtime 真实触发
processDebugTensor; - invocation count 大于 0;
- borrowed debug tensor pointer 不逃逸;
- callback 返回前 copied metadata 完成;
- detach/clear + in-flight drain + release 顺序真实执行;
- full package consumer proof。
类名包含 RealCallbackRuntimeProof 只是实现 proof model,不代表当前已有有效 proof instance。
5. StreamReaderWriter
方法:
IStreamReader::read;IStreamReaderV2::read;IStreamReaderV2::seek;IStreamWriter::write。
仍需:
- managed stream owner;
- native create/destroy;
- no-throw read/seek/write vtable;
- size/offset/seek origin 校验;
- partial read/write contract;
- exception-to-status mapping;
- in-flight accounting;
- owner-scoped metadata copy;
- deserialize/serialize runtime proof。
不能把任意 Stream 直接固定后跨 runtime 长期保存,而不定义 dispose 与并发行为。
跨版本策略
| Family | TRT8 | TRT10 | TRT11 | 版本边界重点 |
|---|---|---|---|---|
| GpuAllocator | 支持 family,需独立 attach | 支持 | 支持 | 方法名/allocator attachment owner |
| GpuAsyncAllocator | 不宣称同等支持 | 支持 | 支持 | stream lifetime/API line guard |
| OutputAllocator | 支持相关接口 | 支持 | 支持 | execution context attach/clear |
| DebugListener | 不宣称 TRT10/11 同形入口 | 支持 | 支持 | debug tensor API/version guard |
| StreamReaderWriter | 按 vendor header 审计 | reader/writer 差异 | reader/writer 差异 | deserialize/serialize API line |
每个 line 都必须同时核对:
- vendor header;
- import library/DLL symbol 或 virtual interface availability;
- manifest version guard;
- native source compile guard;
- generated interop entry;
- managed route;
- smoke capability marker。
不能用 #if TRT_VERSION >= 10000 粗略覆盖所有 family。
Owner 生命周期状态机
stateDiagram-v2
[*] --> Created
Created --> Attached: native attach succeeds
Attached --> Invoking: TensorRT enters callback
Invoking --> Attached: callback returns and inflight--
Attached --> Detaching: owner requests dispose
Invoking --> Detaching: dispose blocks new entry
Detaching --> Draining: clear native attachment
Draining --> Released: inflight == 0
Released --> [*]
必须定义:
- attach 失败是否回滚;
- callback 入场如何增加 in-flight;
- dispose 后新 callback 如何拒绝;
- callback 内抛异常如何捕获;
- detach 是否可能重入;
- release hook 顺序;
- finalizer 是否只能做 no-throw fallback;
- process exit 时如何避免进入已卸载 runtime。
Native Bridge 规则
No-throw C ABI
所有 native entry 与 virtual callback 都必须 catch:
std::exception;- unknown C++ exception;
- 平台可控的 structured exception 边界(按仓库既有策略)。
异常转换为 bridge status/captured diagnostic,不得穿过 C ABI 或 TensorRT vtable。
Non-copyable Owner
native callback owner 应删除 copy/move,避免多个 wrapper 指向同一 vtable/storage 却各自释放。
对称 Create/Destroy
每个成功 create 必须只有一条 destroy ownership path;attach 失败也要正确释放。
Borrowed Pointer
callback 参数中的 tensor/device/stream pointer 默认 borrowed。允许:
- 在 callback 内验证;
- 复制 scalar/shape/name;
- 记录不透明内部 token 用于 owner ledger。
不允许:
- 暴露到 public API;
- callback 返回后由 managed 任意访问;
- 让 GC/finalizer 推断 native lifetime。
Managed Bridge 规则
- delegate 必须由 owner 强引用保持;
- GCHandle/SafeHandle 只解决 managed/native identity,不替代 device ownership;
- managed exception 必须捕获并转成稳定 status;
- callback body 避免阻塞和未知重入;
- dispose 必须可重复且不抛出跨 finalizer 异常;
- snapshot 只能复制诊断,不返回 native handle;
- cancellation/timeout 不能在 callback 正执行时强制释放 owner。
实施顺序
Gate A:接口存在性
审计 vendor header、line guard 和实际可链接/可调用入口。没有真实接口就保持 deferred。
Gate B:Pointer-free Public Contract
先定义 request/result/snapshot 和 owner,不把 IntPtr 当临时 API。
Gate C:Managed Dry-run
验证 state machine、exception capture、dispose、in-flight counter 和 borrowed escape blocker。
dry-run 不是 runtime proof。
Gate D:Native Owner/VTable
实现 no-throw non-copyable owner、对称 create/destroy、attach/detach/clear 和 status mapping。
Gate E:Opt-in Runtime Smoke
只在兼容主机、显式 opt-in 下执行。日志必须包含 callback scenario、invocation marker/count、status、detach/release 和 host metadata。
Gate F:Package Consumer Proof
在仓库外 clean consumer 中使用真实 package/runtime key 重跑,保存 package hash 和日志 hash。
Gate G:Deferred Promotion Review
只有前六个 gate 全部通过,才审查 manifest alias 与 deferred-history 合并。旧 deferred manifest 不删除。
Smoke 输出合同
CallbackAllocatorSafeControlsSmokeRunner 当前输出多层 marker:
CallbackAllocatorSafeControlSummary=...
CallbackAllocatorReadinessSnapshot=...
CallbackOwnerClosureMatrix=...
真实 callback runtime proof 还必须新增或绑定:
CallbackScenario=<family-and-case>
InvocationMarker=<runtime-generated-marker>
InvocationCount=<greater-than-zero>
RealCallbackRuntime=True
IsRealCallbackRuntimeProof=True
DetachCompleted=True
InFlightCallbackCount=0
这些 marker 必须来自真实 runtime log 和 validator,不能从本文复制。
Execution Pack
生成当前 owner execution pack:
pwsh -NoProfile -ExecutionPolicy Bypass -File `
.\eng\Export-CallbackRuntimeProofExecutionPack.ps1 `
-RuntimePackageKey win-x64-trt11.0-cuda13.2-cudnn9.22
验证 pack 的非晋级边界:
pwsh -NoProfile -ExecutionPolicy Bypass -File `
.\eng\Test-CallbackRuntimeProofExecutionPack.ps1 `
-PackPath .\artifacts\final-release\callback-runtime-proof-execution-pack.json
当前 pack 的 performsRuntimeExecution=false,缺少:
- compatible host;
- runtime package key 的真实执行;
- callback scenario;
- repository-external consumer root;
- runtime smoke command/log/hash;
- invocation marker;
- invocation count > 0;
- real proof validator evidence;
- stdout/stderr summary;
- host metadata;
- owner review。
pack 是 runbook,不是 proof。
Real Callback Evidence Schema
权威 schema 文档:
docs/articles/zh-cn/real-callback-runtime-evidence-schema.md
真实 record 至少包含:
| 字段组 | 关键字段 |
|---|---|
| identity | callback family/scenario、TensorRT line、runtime key |
| owner | owner id/state、attach/detach/release timestamps |
| invocation | marker、count、failure count、in-flight max/final |
| memory | allocation/deallocation/reallocation ledger 或 copied tensor metadata |
| exception | managed exception count、native status mapping、stderr summary |
| package | managed/runtime id/version/SHA256、clean consumer |
| host | OS/GPU/driver/CUDA/TensorRT/cuDNN |
| logs | command、exit code、stdout/stderr、log path/SHA256 |
| proof | RealCallbackRuntime、IsRealCallbackRuntimeProof、validator state |
不同 family 还要增加专属字段;不能只用统一 InvocationCount 隐藏 memory/stream/tensor 语义。
Family 专属 Runtime Case
GpuAllocator Case
最小网络构建/运行应触发 allocate + free,对每个 allocation token 记录 size/alignment,最终 outstanding count 为 0。若 runtime 可能缓存 allocation,要定义 case 结束与 runtime destroy 的边界。
GpuAsyncAllocator Case
记录 stream identity、allocateAsync/deallocateAsync ordering、synchronization 和 owner release。不能只触发同步 fallback。
OutputAllocator Case
使用 data-dependent/dynamic output,证明 notifyShape 与 reallocateOutput 真实进入;记录 shape、requested/current size、alignment 和 result status。
DebugListener Case
启用明确 debug tensor,证明 runtime 触发 processDebugTensor;只复制 name/shape/type/metadata,不让 borrowed tensor pointer 逃逸。
StreamReaderWriter Case
对 serialize/deserialize 输入执行 read/seek/write,覆盖 partial operation、EOF/error 和 dispose ordering。
失败注入
真实实现不仅要测试成功,还要测试受控失败:
- managed delegate 抛异常;
- invalid alignment;
- allocation 返回失败;
- output tensor name/shape invalid;
- debug listener consumer 拒绝数据;
- stream read short/EOF;
- dispose 与 callback 并发;
- attach 后 runtime 初始化失败;
- detach 期间 callback 进入。
预期结果必须是稳定 bridge status/captured diagnostic,而不是进程崩溃或异常越过 ABI。
质量门禁
Source gate
- manifest 与 version guard 一致;
- native owner non-copyable;
- destructor/vtable no-throw;
- public surface 无 raw pointer;
- generated interop entry 存在;
- deferred history 保留。
Managed gate
- owner state machine 单元测试;
- dispose/idempotency/concurrency;
- exception capture/status mapping;
- snapshot copied-only;
- no public IntPtr/nint/UIntPtr。
Runtime gate
- compatible host;
- opt-in smoke;
- invocation count > 0;
- family-specific ledger;
- detach/release/in-flight=0;
- real logs/hash。
Package gate
- repository-external clean consumer;
- no ProjectReference/local feed/direct package shortcut;
- package id/version/hash;
- exact runtime key;
- strict callback proof validator。
常见错误
“Managed owner test 通过,所以 callback 完成”
错误。managed owner test 只证明 state machine,不证明 native vtable 或 TensorRT invocation。
“Interface-info 可以读取,所以 callback 已 attach”
错误。copied interface info 是 query evidence。
“类名里有 RuntimeProof,所以 proof 存在”
错误。proof model/schema 可以先于真实 proof instance 存在。
“SmokeResult=passed 就够了”
错误。必须看到 family-specific invocation marker/count、owner lifecycle、package/hash/host 和 validator。
“SafeHandle 能管理 device pointer”
错误。SafeHandle 管理一个 release contract;borrowed/device pointer 是否可释放由 TensorRT/CUDA contract 决定。
“失败时吞掉异常返回 null 即可”
错误。需要稳定 status、captured diagnostic、failure count 和 owner-safe cleanup。
“删掉 deferred manifest 就能提高 coverage”
禁止。promotion 通过真实实现 alias 合并 deferred history,不能删除历史记录改变统计。
边界说明
以下均不能替代 real callback runtime proof:
- design gate;
- managed-readiness;
TensorRtCallbackAllocatorReadinessSnapshot;TensorRtExecutionContextCallbackAllocatorSafeControlSummary;- closure matrix;
- precheck-only;
- dry-run-only;
- schema-only;
- build-only;
- parse-only;
- template/runbook/execution pack;
- readonly diagnostics;
- dependency-probe-only;
- local feed;
- ProjectReference;
- direct
.nupkg; - blocked-by-cuda-driver;
- source/manifest coverage;
- callback 类或 trampoline 源码存在。
package-consumer-runtime 也必须包含 callback-specific invocation proof,普通 identity smoke 不能自动证明 callback family。
real-model-runtime 证明指定模型样例真实运行,同样不能替代 allocator/debug listener 的 invocation、owner lifecycle 与 in-flight 归零证据。
对外表述
可以说:
- 项目已有 pointer-free managed readiness、owner gate、safe-control summary 和 family closure matrix;
- DebugListener 等路径已有 no-throw/trampoline/proof model 组件;
- direct callback rows 在真实 invocation/package proof 前继续 deferred;
- 当前 execution pack 仍需要 compatible host 和 owner 输入。
不能说:
- 所有 callback 已完成;
- managed readiness 等于 runtime proof;
- callback source 存在等于 TensorRT 已调用;
- blocked/skipped smoke 等于 passed。
发布前 Checklist
- [ ] vendor header/symbol/virtual interface 已按 TRT8/10/11 审计。
- [ ] public API 不暴露 IntPtr/nint/UIntPtr/device pointer。
- [ ] managed owner 强引用 delegate 并有明确 dispose。
- [ ] native owner non-copyable,create/destroy 对称。
- [ ] vtable/destructor/C ABI 全部 no-throw。
- [ ] managed exception 转稳定 bridge status。
- [ ] attach/detach/clear 可控且失败可回滚。
- [ ] dispose 阻止新 entry,并等待 in-flight 归零。
- [ ] borrowed pointer 未逃逸。
- [ ] family-specific memory/tensor/stream ledger 完整。
- [ ] compatible host opt-in smoke 真实触发 callback。
- [ ] invocation marker/count 来自真实日志。
- [ ] repository-external package consumer 通过。
- [ ] package/log hash、host metadata、stdout/stderr 可复核。
- [ ] deferred history 未删除。
- [ ] strict validator 通过后才进入 promotion review。
下一步
下一批 callback 实现不应一次横跨五个 family。优先选择一个已有 owner/lifecycle 组件最多、vendor contract 清晰、能构造确定性 runtime case 的 family,完成 native vtable、attach/detach、failure injection、compatible-host smoke 和 package proof的完整闭环;其余 family 继续保留 deferred。当前 closure matrix 会直接显示下一列缺口,避免继续只增加 managed-only gate 字段。
DebugListener native attach/no-throw preflight 与 native owner stable identity 也遵循同一文件职责边界:evaluator 文件只保留评估和 blocker 聚合,*Result.cs 文件保留 pointer-free 结果属性与诊断。该 source split 只改善可维护性,不改变 ABI、生命周期顺序、evidence classification 或任何 deferred row。
同样,attach/detach design gate 与 exception/status mapping gate 的 evaluator/result 也已分别归入同名文件。该归类不启用 non-null attach,不提升 exception mapping 为 runtime proof。