07 - SVM内存迁移机制

难度 : 🔴🔴 高级
预计学习时间 : 2.5-3小时
前置知识: 第6章、DMA基础、SDMA/TTM概念


📋 概述

内存迁移是SVM的核心特性,负责在系统RAM和GPU VRAM之间自动移动页面。打个比方,迁移就像在两个仓库间搬货物:

  • 🏢 系统RAM: CPU的本地仓库,访问快但GPU访问慢
  • 🏭 GPU VRAM: GPU的本地仓库,GPU访问快但CPU访问慢(或无法访问)
  • 🚚 SDMA引擎: GPU的搬运工,专门负责数据搬运
  • 📋 GART表: 地址翻译清单,让SDMA找到正确地址

本章深入迁移机制的实现细节。


7.1 迁移机制概览

迁移的两个方向

复制代码
RAM → VRAM (上行迁移)
    触发场景:
    - GPU频繁访问某段内存
    - 用户显式请求 (prefetch)
    - GPU页面错误触发
    
    流程:
    ┌──────┐     ┌──────┐     ┌──────┐
    │ RAM  │ →→→ │ SDMA │ →→→ │ VRAM │
    │pages │     │ copy │     │pages │
    └──────┘     └──────┘     └──────┘
    
VRAM → RAM (下行迁移)
    触发场景:
    - CPU需要访问VRAM页面
    - 内存不足需要回收VRAM
    - 进程退出清理
    
    流程:
    ┌──────┐     ┌──────┐     ┌──────┐
    │ VRAM │ →→→ │ SDMA │ →→→ │ RAM  │
    │pages │     │ copy │     │pages │
    └──────┘     └──────┘     └──────┘

迁移子系统组件

c 复制代码
// 主要组件
struct migrate_vma {
    struct vm_area_struct *vma;  // 虚拟内存区域
    unsigned long start;         // 起始地址
    unsigned long end;           // 结束地址
    unsigned long *src;          // 源页面数组
    unsigned long *dst;          // 目标页面数组
    unsigned long cpages;        // 收集的页面数
    // ...
};

核心API:

  1. migrate_vma_setup(): 准备迁移,锁定页面
  2. migrate_vma_pages(): 执行迁移,更新页表
  3. migrate_vma_finalize(): 完成迁移,清理资源

7.2 从RAM到VRAM的迁移

主函数:svm_migrate_ram_to_vram

c 复制代码
int svm_migrate_ram_to_vram(struct svm_range *prange, 
                            uint32_t best_loc,
                            unsigned long start_mgr, 
                            unsigned long last_mgr,
                            struct mm_struct *mm, 
                            uint32_t trigger)

参数详解

  • best_loc: 目标GPU节点ID
  • start_mgr/last_mgr: 迁移范围(页号)
  • mm: 进程的mm_struct
  • trigger: 触发原因(KFD_MIGRATE_TRIGGER_xxx)

迁移流程详解

复制代码
┌─────────────────────────────────────────┐
│ 1. 预检查                                │
│    - 验证范围有效性                      │
│    - 获取目标GPU节点                     │
│    - 预留VRAM空间                        │
└─────────────────────────────────────────┘
                ↓
┌─────────────────────────────────────────┐
│ 2. 分配VRAM                             │
│    svm_range_vram_node_new()            │
│    - 通过TTM分配VRAM                     │
│    - 记录在prange->ttm_res               │
└─────────────────────────────────────────┘
                ↓
┌─────────────────────────────────────────┐
│ 3. 按VMA遍历迁移                         │
│    for each VMA in [start, end]:        │
│      svm_migrate_vma_to_vram()          │
└─────────────────────────────────────────┘
                ↓
┌─────────────────────────────────────────┐
│ 4. 更新统计信息                          │
│    pdd->page_in += mpages               │
└─────────────────────────────────────────┘

svm_migrate_vma_to_vram 详解

c 复制代码
/**
 * svm_migrate_ram_to_vram - migrate svm range from system to device
 * @prange: range structure
 * @best_loc: the device to migrate to
 * @start_mgr: start page to migrate
 * @last_mgr: last page to migrate
 * @mm: the process mm structure
 * @trigger: reason of migration
 *
 * Context: Process context, caller hold mmap read lock, svms lock, prange lock
 *
 * Return:
 * 0 - OK, otherwise error code
 */
static long svm_migrate_vma_to_vram(struct kfd_node *node,
                                   struct svm_range *prange,
                                   struct vm_area_struct *vma,
                                   uint64_t start, uint64_t end,
                                   uint32_t trigger, u64 ttm_res_offset)
{
    // 1. 准备迁移上下文
    struct migrate_vma migrate;
    memset(&migrate, 0, sizeof(migrate));
    migrate.vma = vma;
    migrate.start = start;
    migrate.end = end;
    migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;  // 只迁移系统内存
    migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
    
    // 2. 分配临时缓冲区
    // src数组 + dst数组 + DMA地址数组
    buf = kvcalloc(npages,
                  2 * sizeof(*migrate.src) + sizeof(u64) + sizeof(dma_addr_t),
                  GFP_KERNEL);
    migrate.src = buf;
    migrate.dst = migrate.src + npages;
    scratch = (dma_addr_t *)(migrate.dst + npages);
    
    // 3. 收集需要迁移的页面
    r = migrate_vma_setup(&migrate);
    if (r) {
        // 失败可能是页面已被锁定或正在使用
    }
    
    cpages = migrate.cpages;  // 实际收集的页面数
    
    // 4. 执行SDMA拷贝
    r = svm_migrate_copy_to_vram(node, prange, &migrate, 
                                &mfence, scratch, ttm_res_offset);
    
    // 5. 更新页表
    migrate_vma_pages(&migrate);
    
    // 6. 等待SDMA完成
    svm_migrate_copy_done(adev, mfence);
    
    // 7. 完成迁移
    migrate_vma_finalize(&migrate);
    
    // 8. 清理DMA映射
    svm_range_dma_unmap_dev(adev->dev, scratch, 0, npages);
    
    return mpages;  // 成功迁移的页面数
}

migrate_vma_setup 做了什么?

这是Linux内核HMM框架提供的API:

复制代码
1. 锁定VMA和页表
2. 遍历页表,找到满足条件的页面:
   - 页面在系统RAM (MIGRATE_VMA_SELECT_SYSTEM)
   - 页面未被锁定 (pin_user_pages)
   - 页面不是特殊页 (VM_SPECIAL)
3. 增加页面引用计数,防止被释放
4. 记录到migrate.src数组:
   src[i] = page_to_pfn(page) | MIGRATE_PFN_VALID

示例

复制代码
VMA: [0x1000-0x3000] 8页
    页0: 在RAM     → src[0] = PFN(页0) | MIGRATE_PFN_VALID
    页1: 在RAM     → src[1] = PFN(页1) | MIGRATE_PFN_VALID
    页2: 已锁定    → src[2] = 0 (跳过)
    页3: 在RAM     → src[3] = PFN(页3) | MIGRATE_PFN_VALID
    ...
    
cpages = 3  (实际只有3页可迁移)

7.3 SDMA拷贝实现

svm_migrate_copy_to_vram

c 复制代码
static int svm_migrate_copy_to_vram(struct kfd_node *node,
                                   struct svm_range *prange,
                                   struct migrate_vma *migrate,
                                   struct dma_fence **mfence,
                                   dma_addr_t *scratch,
                                   u64 ttm_res_offset)
{
    u64 npages = migrate->npages;
    struct amdgpu_device *adev = node->adev;
    struct device *dev = adev->dev;
    dma_addr_t *src;
    u64 *dst;
    int i, j;
    
    // 1. 为源和目标分配地址数组
    src = scratch;
    dst = (u64 *)(src + npages);
    
    // 2. 映射源页面到设备可见地址
    r = svm_migrate_copy_to_vram_map_src(dev, migrate, scratch, &npages);
    
    // 3. 准备目标VRAM地址
    r = svm_migrate_copy_to_vram_map_dst(node, prange, migrate,
                                        dst, ttm_res_offset);
    
    // 4. 通过GART执行SDMA拷贝
    r = svm_migrate_copy_memory_gart(adev, src, dst, npages,
                                    FROM_RAM_TO_VRAM, mfence);
    
    return r;
}

GART映射原理

什么是GART?

GART (Graphics Address Remapping Table) 是GPU的MMU,类似CPU的页表。

复制代码
问题:SDMA只能访问GPU地址空间
    系统RAM不在GPU地址空间内
    
解决:GART映射
    1. 将系统RAM的物理地址映射到GART表
    2. GART表项指向系统RAM
    3. SDMA通过GART地址访问系统RAM
    
示例:
    RAM物理地址: 0x123456000
    GART表入口:  entry[0] = 0x123456000 + flags
    GART虚拟地址: 0xA00000000 (GPU地址空间)
    
    SDMA读取 0xA00000000 → 硬件查GART表 → 访问 0x123456000

svm_migrate_copy_memory_gart

c 复制代码
static int svm_migrate_copy_memory_gart(struct amdgpu_device *adev,
                                       dma_addr_t *sys,  // 系统内存DMA地址
                                       u64 *vram,        // VRAM地址
                                       u64 npages,
                                       enum MIGRATION_COPY_DIR direction,
                                       struct dma_fence **mfence)
{
    const u64 GTT_MAX_PAGES = AMDGPU_GTT_MAX_TRANSFER_SIZE;  // 256MB
    struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
    u64 gart_s, gart_d;
    
    mutex_lock(&adev->mman.gtt_window_lock);
    
    // 分批处理(每次最多256MB)
    while (npages) {
        size = min(GTT_MAX_PAGES, npages);
        
        if (direction == FROM_RAM_TO_VRAM) {
            // 1. 映射源系统内存到GART
            r = svm_migrate_gart_map(ring, size, sys, &gart_s,
                                    KFD_IOCTL_SVM_FLAG_GPU_RO);
            
            // 2. 目标VRAM直接映射
            gart_d = svm_migrate_direct_mapping_addr(adev, *vram);
            
            // 3. SDMA拷贝: GART地址 → VRAM地址
            r = amdgpu_copy_buffer(ring, gart_s, gart_d,
                                  size * PAGE_SIZE,
                                  NULL, &next, false, true, false);
        } else if (direction == FROM_VRAM_TO_RAM) {
            // 反向操作
        }
        
        // 更新fence链
        dma_fence_put(*mfence);
        *mfence = next;
        
        // 更新指针
        npages -= size;
        sys += size;
        *vram += size * PAGE_SIZE;
    }
    
    mutex_unlock(&adev->mman.gtt_window_lock);
    return r;
}

GART映射详细流程

c 复制代码
static int svm_migrate_gart_map(struct amdgpu_ring *ring, 
                               u64 npages,
                               dma_addr_t *addr,  // 系统内存DMA地址
                               u64 *gart_addr,    // 输出:GART虚拟地址
                               u64 flags)
{
    struct amdgpu_device *adev = ring->adev;
    
    // 1. 使用GART窗口0(预留的映射空间)
    *gart_addr = adev->gmc.gart_start;
    
    // 2. 准备PTE(页表项)标志
    pte_flags = AMDGPU_PTE_VALID | AMDGPU_PTE_READABLE;
    pte_flags |= AMDGPU_PTE_SYSTEM | AMDGPU_PTE_SNOOPED;
    if (!(flags & KFD_IOCTL_SVM_FLAG_GPU_RO))
        pte_flags |= AMDGPU_PTE_WRITEABLE;
    
    // 3. 分配Job(GPU命令缓冲区)
    r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
                                ..., &job, ...);
    
    // 4. 生成GART更新命令
    // 将DMA地址数组转换为PTE条目
    cpu_addr = &job->ibs[0].ptr[num_dw];
    amdgpu_gart_map(adev, 0, npages, addr, pte_flags, cpu_addr);
    
    // 5. 使用SDMA将PTE写入GART表
    src_addr = job->ibs[0].gpu_addr + offset;  // PTE数据的GPU地址
    dst_addr = amdgpu_bo_gpu_offset(adev->gart.bo);  // GART表的GPU地址
    amdgpu_emit_copy_buffer(adev, &job->ibs[0], 
                           src_addr, dst_addr, num_bytes, 0);
    
    // 6. 提交并获取fence
    fence = amdgpu_job_submit(job);
    dma_fence_put(fence);
    
    return 0;
}

图解GART映射过程

复制代码
步骤1: 准备PTE数据
┌────────────────────────┐
│ CPU生成PTE数组          │
│ PTE[0] = sys_addr[0]   │
│ PTE[1] = sys_addr[1]   │
│ ...                    │
└────────────────────────┘
            ↓
步骤2: SDMA写入GART表
┌────────────────────────┐  SDMA拷贝  ┌────────────────────────┐
│ GPU内存中的PTE数据      │ ────────→  │ GART表(在VRAM)        │
│ @ job->ibs[0].gpu_addr │            │ @ adev->gart.bo        │
└────────────────────────┘            └────────────────────────┘
                                               ↓
步骤3: 映射生效
┌─────────────────────────────────────────────────────────┐
│ GART地址空间                                             │
│ [0xA00000000-0xA00001000] → 系统RAM @ 0x123456000       │
│ [0xA00001000-0xA00002000] → 系统RAM @ 0x123457000       │
│ ...                                                     │
└─────────────────────────────────────────────────────────┘

7.4 从VRAM到RAM的迁移

主函数:svm_migrate_vram_to_ram

c 复制代码
// 文件: kfd_migrate.c, 行: 800-920
int svm_migrate_vram_to_ram(struct svm_range *prange, 
                           struct mm_struct *mm,
                           unsigned long start_mgr, 
                           unsigned long last_mgr,
                           uint32_t trigger, 
                           struct page *fault_page)

关键特性

  • fault_page: CPU页面错误时传入,指定具体的故障页
  • 下行迁移通常由CPU页面错误触发

迁移流程

复制代码
1. 检查actual_loc
   if (!prange->actual_loc)
       return 0;  // 已经在RAM,无需迁移

2. 按VMA遍历
   for each VMA:
       svm_migrate_vma_to_ram()

3. 更新页面计数
   prange->vram_pages -= mpages

4. 释放VRAM(如果全部迁移完)
   if (prange->vram_pages == 0)
       svm_range_vram_node_free()

svm_migrate_vma_to_ram 详解

c 复制代码
static long svm_migrate_vma_to_ram(struct kfd_node *node,
                                  struct svm_range *prange,
                                  struct vm_area_struct *vma,
                                  uint64_t start, uint64_t end,
                                  uint32_t trigger,
                                  struct page *fault_page)
{
    // 1. 准备迁移上下文
    memset(&migrate, 0, sizeof(migrate));
    migrate.vma = vma;
    migrate.start = start;
    migrate.end = end;
    migrate.pgmap_owner = SVM_ADEV_PGMAP_OWNER(adev);
    
    // 选择设备页面(在VRAM的页面)
    if (adev->gmc.xgmi.connected_to_cpu)
        migrate.flags = MIGRATE_VMA_SELECT_DEVICE_COHERENT;
    else
        migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
    
    migrate.fault_page = fault_page;  // 指定故障页
    
    // 2. 收集VRAM页面
    r = migrate_vma_setup(&migrate);
    cpages = migrate.cpages;
    
    // 3. 分配RAM页面并执行SDMA拷贝
    r = svm_migrate_copy_to_ram(adev, prange, &migrate, 
                               &mfence, scratch, npages);
    
    // 4. 更新页表
    migrate_vma_pages(&migrate);
    
    // 5. 等待完成
    svm_migrate_copy_done(adev, mfence);
    migrate_vma_finalize(&migrate);
    
    return mpages;
}

svm_migrate_copy_to_ram

c 复制代码
static int svm_migrate_copy_to_ram(struct amdgpu_device *adev,
                                  struct svm_range *prange,
                                  struct migrate_vma *migrate,
                                  struct dma_fence **mfence,
                                  dma_addr_t *scratch, u64 npages)
{
    // 1. 分配目标RAM页面
    for (i = 0, j = 0; i < npages; i++) {
        if (migrate->src[i] & MIGRATE_PFN_VALID) {
            // 分配新页面
            dst_page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
            
            // 映射到设备可见地址
            r = svm_migrate_copy_to_ram_map_page(dev, dst_page, 
                                                 &scratch[j]);
            
            // 记录目标页面
            migrate->dst[i] = migrate_pfn(page_to_pfn(dst_page));
            
            // 准备源VRAM地址
            src[j] = svm_migrate_direct_mapping_addr(adev, 
                        prange->start + i - prange->offset);
            j++;
        }
    }
    
    // 2. SDMA拷贝: VRAM → RAM
    r = svm_migrate_copy_memory_gart(adev, scratch, src, npages,
                                    FROM_VRAM_TO_RAM, mfence);
    
    return r;
}

7.5 迁移优化技术

7.5.1 分批处理

c 复制代码
// 避免一次迁移过大的范围
const u64 GTT_MAX_PAGES = AMDGPU_GTT_MAX_TRANSFER_SIZE;  // 256MB

while (npages) {
    size = min(GTT_MAX_PAGES, npages);
    // 迁移 size 页
    npages -= size;
}

原因

  • GART窗口有限(通常256MB)
  • 避免长时间锁定gtt_window_lock
  • 允许其他操作穿插执行

7.5.2 部分迁移

c 复制代码
// migrate_vma_setup 可能只收集部分页面
if (cpages != npages)
    pr_debug("partial migration, 0x%lx/0x%llx pages\n",
             cpages, npages);

常见原因

  • 页面被pin_user_pages锁定(RDMA、GPU直接访问)
  • 页面正在被其他操作使用
  • 页面是特殊页(huge pages, VM_SPECIAL)

7.5.3 异步执行

c 复制代码
// SDMA操作返回fence,允许异步执行
struct dma_fence *mfence = NULL;

// 提交SDMA任务(立即返回)
svm_migrate_copy_memory_gart(..., &mfence);

// 继续其他工作...
migrate_vma_pages(&migrate);

// 需要时等待完成
svm_migrate_copy_done(adev, mfence);

7.5.4 XGMI优化

c 复制代码
// 对于XGMI连接的GPU,可以直接访问
if (adev->gmc.xgmi.connected_to_cpu) {
    // 使用设备一致性内存
    migrate.flags = MIGRATE_VMA_SELECT_DEVICE_COHERENT;
} else {
    // 使用设备私有内存
    migrate.flags = MIGRATE_VMA_SELECT_DEVICE_PRIVATE;
}

XGMI(AMD Infinity Fabric)

  • CPU可以直接访问VRAM
  • 无需迁移即可访问
  • 性能接近本地内存

7.6 迁移触发场景

触发原因(trigger参数)

c 复制代码
enum KFD_MIGRATE_TRIGGERS {
    KFD_MIGRATE_TRIGGER_PREFETCH,     // 用户预取
    KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU,// GPU页面错误
    KFD_MIGRATE_TRIGGER_PAGEFAULT_CPU,// CPU页面错误
    KFD_MIGRATE_TRIGGER_TTM_EVICTION, // TTM驱逐(内存不足)
    KFD_MIGRATE_TRIGGER_SUSPEND,      // 系统挂起
};

触发流程示例

场景1:GPU页面错误

复制代码
1. GPU访问地址0x1234
   ↓
2. 地址未映射,触发GPU页面错误
   ↓
3. XNACK重试机制暂停GPU执行
   ↓
4. GPU中断CPU
   ↓
5. 中断处理程序调用:
   svm_range_restore_pages()
   ↓
6. 检查页面位置:
   if (在RAM)
       → 只需建立映射
   else
       → 调用svm_migrate_ram_to_vram()
   ↓
7. 迁移完成,更新GPU页表
   ↓
8. XNACK恢复GPU执行

场景2:CPU页面错误

复制代码
1. CPU访问VRAM地址0x5678
   ↓
2. 页表项标记为设备私有,触发页面错误
   ↓
3. 内核页面错误处理程序调用:
   vm_ops->fault()
   ↓
4. AMDGPU驱动注册的处理函数:
   svm_migrate_to_ram()
   ↓
5. 调用svm_migrate_vram_to_ram()
   参数: fault_page = vmf->page
   ↓
6. 迁移完成,更新CPU页表
   ↓
7. CPU重新执行访问指令

场景3:用户预取

复制代码
用户程序:
    hipMemPrefetchAsync(ptr, size, deviceId);
    ↓
内核处理:
    svm_range_prefault()
    ↓
    svm_migrate_ram_to_vram(trigger=PREFETCH)

7.7 代码示例

完整迁移示例

c 复制代码
// 将一个范围迁移到GPU 0
struct kfd_process *p = kfd_get_process(current);
struct svm_range *prange = ...;
uint32_t gpu_id = 0;

// 锁定必要的锁
mmap_read_lock(p->mm);
mutex_lock(&prange->migrate_mutex);

// 执行迁移
r = svm_migrate_ram_to_vram(prange, 
                           gpu_id,
                           prange->start,  // 整个范围
                           prange->last,
                           p->mm,
                           KFD_MIGRATE_TRIGGER_PREFETCH);

if (r > 0) {
    pr_info("migrated %d pages to GPU %u\n", r, gpu_id);
    prange->actual_loc = gpu_id;
} else if (r < 0) {
    pr_err("migration failed: %d\n", r);
}

mutex_unlock(&prange->migrate_mutex);
mmap_read_unlock(p->mm);

监控迁移统计

c 复制代码
// 每个GPU有独立的统计
struct kfd_process_device *pdd = ...;

pr_info("GPU %u statistics:\n", pdd->dev->id);
pr_info("  Pages migrated in:  %llu\n", pdd->page_in);
pr_info("  Pages migrated out: %llu\n", pdd->page_out);

💡 重点提示

  1. GART是关键:理解GART映射机制是理解迁移的基础。

  2. 两阶段提交

    • SDMA拷贝数据(异步)
    • migrate_vma_pages 更新页表(同步)
  3. 部分迁移是常态:不要期望所有页面都能迁移。

  4. 锁顺序:mmap_lock → migrate_mutex,避免死锁。

  5. 异步操作:SDMA返回fence,允许并发执行。


⚠️ 常见陷阱

陷阱1:"忘记等待SDMA完成"

  • ✅ 正确:调用svm_migrate_copy_done()等待fence。

陷阱2:"大范围迁移不分批"

  • ✅ 正确:使用GTT_MAX_PAGES分批处理。

陷阱3:"假设所有页面都能迁移"

  • ✅ 正确:检查cpagesmpages,处理部分失败。

陷阱4:"在中断上下文调用迁移"

  • ✅ 正确:迁移需要进程上下文(可能睡眠)。

📝 实践练习

  1. 追踪迁移路径

    bash 复制代码
    # 启用迁移调试
    echo 'file kfd_migrate.c +p' > /sys/kernel/debug/dynamic_debug/control
    
    # 运行GPU程序并观察迁移
    dmesg | grep "svm_migrate"
  2. 查看迁移统计

    bash 复制代码
    # 查看进程的SVM统计
    cat /sys/kernel/debug/kfd/proc/<pid>/svm_ranges
  3. 思考题

    • 为什么需要GART表?不能直接拷贝吗?
    • CPU页面错误时为什么要传入fault_page
    • 如果迁移过程中页面被修改会怎样?
    • XGMI连接的优势是什么?
  4. 代码探索

    bash 复制代码
    # 查看GART映射实现
    grep -A 50 "svm_migrate_gart_map" drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
    
    # 查看SDMA拷贝命令
    grep -A 20 "amdgpu_emit_copy_buffer" drivers/gpu/drm/amd/amdgpu/amdgpu_job.c

📚 本章小结

  • 两个方向:RAM→VRAM(上行)和VRAM→RAM(下行)
  • 核心API:HMM框架的migrate_vma_xxx系列函数
  • GART映射:让SDMA能够访问系统RAM
  • SDMA拷贝:GPU的DMA引擎执行实际数据搬运
  • 异步执行:使用fence机制允许并发
  • 分批处理:避免长时间占用资源
  • 部分迁移:灵活处理不可迁移的页面

📖 扩展阅读


➡️ 下一步

掌握了迁移机制后,下一章我们将学习页面映射与GPU页表------如何让GPU能够访问这些页面。


🔗 导航

相关推荐
DeeplyMind2 天前
06 - SVM范围管理
svm·amdgpu·rocm·kfd
啊阿狸不会拉杆2 天前
《机器学习导论》第 13 章-核机器
人工智能·python·算法·机器学习·支持向量机·svm·核机器
DeeplyMind3 天前
05 - 进程与SVM的关系
svm·amdgpu·rocm·kfd
DeeplyMind4 天前
03 - AMDGPU驱动架构概览
svm·amdgpu·rocm·kfd
DeeplyMind5 天前
ROCm rocr-libhsakmt分析系列4: HsaMemFlags分析
rocm·rocr·libhsakmt·hsamemflags
DeeplyMind7 天前
附录A:AMDGPU SVM 属性类型
kfd·amdgpu svm
DeeplyMind7 天前
04 - SVM核心数据结构详解
svm·amdgpu·kfd
DeeplyMind9 天前
02 - SVM相关的Linux内核基础
hmm·rocm·kfd·共享虚拟内存·amdgpu svm
DeeplyMind10 天前
01 - 什么是SVM
svm·amdgpu·rocm·kfd