创建仓库
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
---
|
||||
tags: []
|
||||
date created: 星期四, 十一月 20日 2025, 8:40:05 晚上
|
||||
date modified: 星期四, 十一月 20日 2025, 8:48:20 晚上
|
||||
---
|
||||
|
||||
# 2.2.1 锁页内存管理与分配策略 (Page-Locked&Pinned Memory Management)
|
||||
|
||||
### 一、 约束输入与对齐 (Constraints & Alignment)
|
||||
|
||||
根据前序审计与设计文档,我们面临以下**硬性约束**:
|
||||
|
||||
1. **OS 内存机制**: Kylin V10 (Linux) 使用虚拟内存分页。普通的 `malloc/new` 分配的是**可分页内存 (Pageable Memory)**。
|
||||
2. **DMA 物理限制**: GPU 的 DMA 引擎(Copy Engine)需要访问**物理地址**。如果使用可分页内存,驱动必须先隐式锁定页面(CPU 开销),再分块传输,导致带宽严重下降。
|
||||
3. **吞吐量目标**: 雷达接收模块要求 **\> 10,000 packets/sec**。频繁的系统调用(`malloc` / `free` / `cudaMallocHost`)是不可接受的。
|
||||
4. **硬件平台**: 智铠 MR-V100 的 SDK (CoreX) 兼容 CUDA 10.2 API。
|
||||
|
||||
-----
|
||||
|
||||
### 二、 权衡分析与选项呈现 (Trade-off Matrix)
|
||||
|
||||
#### 议题 1:锁页内存申请 API (Allocation API)
|
||||
|
||||
| 选项 | A. `cudaMallocHost` (推荐) | B. `malloc` + `cudaHostRegister` |
|
||||
| :--- | :--- | :--- |
|
||||
| **机制** | 直接由 GPU 驱动在内核态分配**物理连续**(尽可能)且**已锁定**的内存。 | 用户先申请普通内存,再通知驱动去锁定这些页面。 |
|
||||
| **DMA 性能** | **最高**。驱动对物理地址布局有完全控制权,TLB 命中率高。 | **中等/高**。取决于 OS 分配的物理页碎片化程度。 |
|
||||
| **UVA 适配性** | **完美**。配合 `cudaHostAllocMapped` 标志,可直接映射到 GPU 地址空间(为 2.2.4 铺路)。 | **较差**。虽然也支持 Mapped,但对齐要求严格,容易出错。 |
|
||||
| **CPU 开销** | 分配时开销极大(重系统调用),必须配合**内存池**使用。 | 注册/注销开销大,同样需要配合内存池。 |
|
||||
|
||||
#### 议题 2:内存池架构 (Pool Architecture)
|
||||
|
||||
| 选项 | A. 预分配固定块池 (Fixed-Block Pool) (推荐) | B. 动态堆内存池 (Dynamic Heap) |
|
||||
| :--- | :--- | :--- |
|
||||
| **机制** | 启动时申请一大块内存(如 512MB),切分为 N 个固定大小(如 64KB)的块。 | 像 OS 堆一样支持任意大小的 `alloc/free`。 |
|
||||
| **适配场景** | **雷达原始数据**。脉冲/包大小通常是固定的或有明确上限。 | 通用计算,大小不一的对象。 |
|
||||
| **性能** | **O(1) 极速分配**。无内存碎片。 | O(log n) 分配。存在外部碎片风险。 |
|
||||
| **设计一致性** | 符合 `01_数据接收模块设计.md` 中定义的 `packet_block_size_kb`。 | 增加不必要的复杂度。 |
|
||||
|
||||
-----
|
||||
|
||||
### 三、 基线确立与论证
|
||||
|
||||
基于上述分析,针对 **2.2.1 锁页内存管理与分配策略**,确立以下工程基线:
|
||||
|
||||
#### 1\. 分配 API 基线:`cudaMallocHost` + `cudaHostAllocMapped`
|
||||
|
||||
- **决策**:摒弃标准的 `new/malloc`,**强制**使用 GPU 运行时 API `cudaMallocHost` (在 CoreX SDK 中对应同名 API) 分配所有用于 H2D 传输的缓冲区。
|
||||
- **标志位 (Critical)**:必须使用 **`cudaHostAllocMapped`** 标志。
|
||||
- *论证*:这不仅锁定了页面,还将其映射到了 GPU 的统一地址空间(UVA)。这是实现后续 **2.2.4 零拷贝技术** 的先决条件。如果没有此标志,GPU 无法通过 PCIe 直接访问这块 CPU 内存。
|
||||
- **对齐约束**:`cudaMallocHost` 自动保证了页面对齐(通常 4KB 或 64KB),满足 DMA 要求。
|
||||
|
||||
#### 2\. 内存池策略:静态预分配 + 固定块管理
|
||||
|
||||
- **决策**:在系统初始化阶段(`initialize()`)一次性分配所有所需的锁页内存,**严禁**在 `start()` 后的运行时路径中调用 `cudaMallocHost`。
|
||||
- **实现细节**:
|
||||
- **池大小**:依据设计文档,预分配 **256MB**。
|
||||
- **块大小**:**64KB**。这足以容纳 9000 字节的 JUMBO Frame,且对齐友好。
|
||||
- **管理结构**:使用简单的 `std::stack<void*>` 或无锁队列 `SPSC` 管理空闲块指针,实现 O(1) 复杂度的获取与归还。
|
||||
|
||||
#### 3\. 伪代码规范 (C++14 Standard)
|
||||
|
||||
```cpp
|
||||
// 基线实现范式
|
||||
void* d_ptr; // Device pointer (mapped)
|
||||
void* h_ptr; // Host pointer
|
||||
|
||||
// 1. 必须使用 Mapped 标志以启用 UVA (为 2.2.4 准备)
|
||||
// 2. 必须使用 Portable 标志以支持多 GPU 上下文 (尽管目前是单卡,但在异构设计中是好习惯)
|
||||
unsigned int flags = cudaHostAllocMapped | cudaHostAllocPortable;
|
||||
|
||||
// 3. 分配 - 仅在初始化阶段执行
|
||||
cudaError_t err = cudaHostAlloc(&h_ptr, POOL_SIZE_BYTES, flags);
|
||||
if (err != cudaSuccess) {
|
||||
// 触发 Fatal Error 事件
|
||||
}
|
||||
|
||||
// 4. 获取对应的 Device 指针 (用于后续 2.2.4 Zero-Copy)
|
||||
cudaHostGetDevicePointer(&d_ptr, h_ptr, 0);
|
||||
|
||||
// … 将 h_ptr 切分为 64KB 的块放入 free_list …
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
**下一步行动**:
|
||||
|
||||
我们已确立了**如何分配**这块特殊的“高速内存”。接下来,我们需要讨论**如何调度**这块内存的传输,即 **2.2.2 异步流水线与计算通信重叠**,这将决定 GPU 的 Copy Engine 是否能被充分利用,从而掩盖 PCIe 带宽瓶颈。
|
||||
|
||||
**提问**:您是否同意使用带有 `Mapped` 标志的 `cudaMallocHost` 作为分配基线?确认后我们将进入 2.2.2 讨论三级流水线设计。
|
||||
Reference in New Issue
Block a user