Skip to content

GGML 后端与硬件抽象 — 代码走读

ggml/src/ggml-backend.cpp — 后端注册表

后端通过注册表模式管理:

c
// 注册后端(注册的是后端注册对象,而非 backend 实例本身)
void ggml_backend_register(ggml_backend_reg_t reg);

现代 API 通过**设备(device)**枚举来发现后端,而不是按类型直接取一个 backend:

c
// 枚举所有已注册的设备
size_t             ggml_backend_dev_count(void);
ggml_backend_dev_t ggml_backend_dev_get(size_t index);          // 按下标取设备
ggml_backend_dev_t ggml_backend_dev_by_name(const char * name); // 按名称取设备
ggml_backend_dev_t ggml_backend_dev_by_type(enum ggml_backend_dev_type type); // 按类型取设备

// 再用设备初始化一个真正的后端实例
ggml_backend_t ggml_backend_dev_init(ggml_backend_dev_t device, const char * params);

注意:ggml_backend_register 的参数类型是 ggml_backend_reg_t(后端注册对象),而设备枚举走 ggml_backend_dev_* 系列函数。上述签名均见 ggml/include/ggml-backend.h

核心结构(定义于内部头 ggml/src/ggml-backend-impl.h不在 公开头中):

c
struct ggml_backend {
    ggml_guid_t        guid;      // 后端 GUID
    struct ggml_backend_i iface;  // 函数指针表
    ggml_backend_dev_t device;    // 所属设备
    void *             context;   // 后端私有数据
};

ggml_backend_i 是后端的主函数指针表(涵盖同步的图计算 graph_compute 等,以及可选的异步张量 / 事件操作),成员(节选,见 ggml-backend-impl.h):

c
struct ggml_backend_i {
    const char * (*get_name)(ggml_backend_t backend);
    void         (*free)(ggml_backend_t backend);

    // (可选)异步张量数据访问
    void (*set_tensor_async)(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size);
    void (*get_tensor_async)(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size);
    bool (*cpy_tensor_async)(ggml_backend_t backend_src, ggml_backend_t backend_dst, const struct ggml_tensor * src, struct ggml_tensor * dst);

    // (可选)完成所有挂起操作(支持异步时必需)
    void (*synchronize)(ggml_backend_t backend);

    // (可选)计算图计划(当前未使用)
    ggml_backend_graph_plan_t (*graph_plan_create)(ggml_backend_t backend, const struct ggml_cgraph * cgraph);
    void                      (*graph_plan_free)(ggml_backend_t backend, ggml_backend_graph_plan_t plan);
    void                      (*graph_plan_update)(ggml_backend_t backend, ggml_backend_graph_plan_t plan, const struct ggml_cgraph * cgraph);
    enum ggml_status          (*graph_plan_compute)(ggml_backend_t backend, ggml_backend_graph_plan_t plan);

    // 计算图(后端支持异步时永远异步)
    enum ggml_status (*graph_compute)(ggml_backend_t backend, struct ggml_cgraph * cgraph);

    // (可选)事件同步
    void (*event_record)(ggml_backend_t backend, ggml_backend_event_t event);
    void (*event_wait)  (ggml_backend_t backend, ggml_backend_event_t event);

    // (可选)对图中节点排序/优化(本窗口签名新增第三参 params,可回调 add_alloc_dep)
    void (*graph_optimize)(ggml_backend_t backend, struct ggml_cgraph * cgraph, const struct ggml_backend_graph_optimize_params * params);
};

旧笔记里列的 alloc_buffersupports_opget_buffer_alignment 并不属于 ggml_backend_i:缓冲区分配接口在 ggml_backend_buffer_type_i,算子能力查询(supports_op)在设备接口 ggml_backend_device_i,而 get_buffer_alignment 在当前源码中并不存在。

ggml/src/ggml-cpu/ — CPU 后端

关键文件:

  • ggml-cpu.c — CPU 后端主实现
  • ggml-cpu.cpp — C++ 封装
  • quants.c — 量化操作实现(位于 ggml/src/ggml-cpu/
  • ARM/NEON 优化代码位于 ggml/src/ggml-cpu/arch/arm/(如 quants.crepack.cppcpu-feats.cpp),不再有单独的 ggml-cpu-aarch64.cpp 文件

SIMD Kernel 选择

运行时检测 CPU 特性并选择最优 kernel:

c
#if defined(__AVX512F__)
    // AVX-512 实现 (512-bit SIMD)
#elif defined(__AVX2__)
    // AVX2 实现 (256-bit SIMD)
#elif defined(__ARM_NEON)
    // NEON 实现 (128-bit SIMD)
#else
    // 标量回退
#endif

ggml/src/ggml-cuda/ — CUDA 后端

关键文件:

  • ggml-cuda.cu — CUDA 后端入口(注意是 .cu 源文件,不是 .cpp
  • mmq.cuh — 量化矩阵乘法 kernel
  • fattn.cuh — Flash Attention kernel
  • dequantize.cuh — 反量化 kernel
  • fwht.cu / fwht.cuh — 快速 Walsh-Hadamard 变换

ggml/src/ggml-metal/ — Metal 后端

关键文件:

  • ggml-metal.cpp — Metal 后端主实现(C++)
  • ggml-metal-context.m — Metal 上下文(Objective-C,与 MTLDevice/MTLCommandQueue 交互)
  • ggml-metal-device.m / ggml-metal-device.cpp — 设备接口实现
  • ggml-metal-common.cpp — 公共辅助代码
  • kernels/*.metal(约 23 个文件)— Metal Compute Shaders,按算子拆分(+ common.h / dequantize.h / quantize.h

旧版单体 ggml-metal.m 已不存在,后端被拆分成了上面的 .cpp / .m 多文件结构;随后单体 ggml-metal.metal 也被拆进 kernels/ 目录(本窗口,b615f5b4b),metallib 相应拆成 8 个库并行编译加载——目录里已没有顶层 .metal 文件。另有 ggml-metal-tuning.cpp/.h 管理各 kernel 的调优参数。

Metal 后端利用 Apple Silicon 的统一内存:

objc
// Metal buffer 直接映射到 CPU 地址空间
id<MTLBuffer> metal_buffer = [device newBufferWithBytesNoCopy:ptr
    length:size options:0 deallocator:nil];

关键函数索引

函数文件说明
ggml_backend_cpu_initggml-cpu.cpp初始化 CPU 后端
ggml_backend_cuda_initggml-cuda.cu初始化 CUDA 后端
ggml_backend_metal_initggml-metal.cpp初始化 Metal 后端
ggml_backend_alloc_ctx_tensorsggml-backend.cpp为张量分配设备内存
ggml_backend_graph_compute各后端在设备上执行计算图