Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"clangd.arguments": [
"--compile-commands-dir=${workspaceFolder}/build-snapdragon",
"--pch-storage=memory",
"--background-index",
"-j=32",
"--enable-config",
"--pretty",
// "--resource-dir=/home/docker/proj/p-sbs/prebuilts/clang/host/linux-x86/clang-r547379/lib/clang/20",
// "--log=error",
// "--background-index=FALSE",
// "--query-driver=/usr/bin/g++",
// "--log=verbose"
// "--index-file=/dev/null",
],
}
3 changes: 2 additions & 1 deletion docs/backend/hexagon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ At this point, you should also install some models:
...
2025-10-11 12:04:52 (10.7 MB/s) - ‘Llama-3.2-1B-Instruct-Q4_0.gguf’ saved [773025920/773025920]

~/src/llama.cpp$ adb shell mkdir -p /data/local/tmp/gguf
~/src/llama.cpp$ adb push Llama-3.2-1B-Instruct-Q4_0.gguf /data/local/tmp/gguf
Llama-3.2-1B-Instruct-Q4_0.gguf: 1 file pushed, 0 skipped. 38.3 MB/s (773025920 bytes in 19.250s)
```
Expand All @@ -106,7 +107,7 @@ Here are some examples of running various llama.cpp tools via ADB.
Simple question for Llama-3.2-1B

```
~/src/llama.cpp$ M=Llama-3.2-1B-Instruct-Q4_0.gguf D=HTP0 ./scripts/snapdragon/adb/run-cli.sh -no-cnv -p "what is the most popular cookie in the world?"
~/src/llama.cpp$ M=Llama-3.2-1B-Instruct-Q4_0.gguf D=HTP0 ./scripts/snapdragon/adb/run-cli.sh -no-cnv -p \"what is the most popular cookie in the world?\"
...
ggml-hex: Hexagon backend (experimental) : allocating new registry : ndev 1
ggml-hex: Hexagon Arch version v79
Expand Down
88 changes: 88 additions & 0 deletions ggml/src/ggml-hexagon/doc/ggml-hexagon_stage1_architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# 1. 架构概览与核心设计

## 技术栈与架构概览

- **主要技术栈**:
- **C/C++**: 项目主要使用 C 和 C++ 编写,C 用于编写 Hexagon DSP 上的内核代码,C++ 用于编写与 `ggml` 的集成代码。
- **Qualcomm Hexagon SDK**: 用于在 Qualcomm Hexagon DSP 上进行开发、调试和性能分析。
- **CMake**: 用于构建和管理项目。
- **FastRPC**: 用于 CPU 和 DSP 之间的远程过程调用。

- **架构概览**:
- 项目是一个专门为 `ggml` 设计的后端,旨在将计算密集型任务卸载到 Qualcomm Hexagon DSP 上。
- 架构遵循 **分层设计**,将 `ggml` 的核心逻辑与 Hexagon DSP 的具体实现分离开来。
- 它不是一个独立的应用,而是一个可以被 `ggml` 集成的 **插件式** 模块。

## 核心架构设计原则与设计模式

- **核心架构设计原则**:
- **高性能**: 通过利用 Hexagon Vector eXtensions (HVX) 和多线程来最大化计算性能。
- **低延迟**: 通过 FastRPC 和 DMA 实现 CPU 和 DSP 之间的高效通信。
- **模块化**: 将不同的操作(如矩阵乘法、激活函数等)分解到不同的文件中,便于维护和扩展。
- **高内聚、低耦合**: `ggml-hexagon` 模块封装了与 DSP 交互的所有细节,与 `ggml` 的核心代码解耦。

- **设计模式**:
- **代理模式 (Proxy Pattern)**: `ggml-hexagon.cpp` 可以看作是 Hexagon DSP 的代理,它接收来自 `ggml` 的计算任务,并将其转发给 DSP 执行。
- **生产者-消费者模式 (Producer-Consumer Pattern)**: CPU 作为生产者,将计算任务放入队列;DSP 作为消费者,从队列中取出任务并执行。

## 模块划分与主要组件交互

- **模块划分**:
- **`ggml-hexagon.cpp`**: `ggml` 后端接口的实现,负责将 `ggml` 的计算图转换为可以在 Hexagon DSP 上执行的操作。
- **`htp-utils.c/h`**: 提供了与 Hexagon DSP 通信的实用函数,封装了 FastRPC 和内存管理的细节。
- **`htp/` 目录**: 包含了在 Hexagon DSP 上运行的代码,其中:
- `main.c`: DSP 端程序的入口点。
- `*-ops.c`: 实现了各种计算操作,如矩阵乘法、激活函数等。
- `hvx-*.c`: 包含了使用 HVX指令集进行优化的函数。
- `worker-pool.c`: 管理 DSP 上的线程池,用于并行计算。

- **主要组件交互**:
1. `ggml` 的计算图被发送到 `ggml-hexagon` 后端。
2. `ggml-hexagon.cpp` 将计算图中的操作转换为 DSP 可以理解的指令。
3. 通过 `htp-utils` 提供的函数,`ggml-hexagon.cpp` 将指令和数据发送到 DSP。
4. DSP 上的 `main.c` 接收到指令后,调用相应的 `*-ops.c` 中的函数来执行计算。
5. `*-ops.c` 中的函数可能会使用 `hvx-*.c` 中的函数来加速计算。
6. 计算完成后,结果通过 `htp-utils` 返回给 `ggml-hexagon.cpp`。
7. `ggml-hexagon.cpp` 将结果返回给 `ggml`。

## 架构图示 (Mermaid)

### 组件关系图

```mermaid
graph TD
subgraph GGML Core
A[ggml]
end

subgraph GGML Hexagon Backend
B[ggml-hexagon.cpp]
C[htp-utils.c/h]
end

subgraph Hexagon DSP
D[main.c]
E[*-ops.c]
F[hvx-*.c]
G[worker-pool.c]
end

A -- Offloads computation to --> B
B -- Uses --> C
C -- Communicates with --> D
D -- Dispatches to --> E
E -- Uses --> F
E -- Uses --> G
```

### 数据流图

```mermaid
sequenceDiagram
participant CPU
participant DSP

CPU->>DSP: Send computation task (e.g., matrix multiplication)
DSP->>DSP: Execute task using HVX and thread pool
DSP-->>CPU: Return result
```
52 changes: 52 additions & 0 deletions ggml/src/ggml-hexagon/doc/ggml-hexagon_stage2_goals_features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 2. 项目目标、演进与关键特性

## 项目目标与演进

- **短期目标**:
- 将 `ggml` 中最耗时的计算操作(如矩阵乘法、量化)卸载到 Hexagon DSP,以显著提升在移动设备上的性能。
- 支持最常见的 `ggml` 数据类型和操作,确保与主流模型的兼容性。

- **长期目标**:
- 成为 `ggml` 在 Qualcomm 平台上的首选后端。
- 持续优化性能,跟进 Hexagon DSP 的新特性。
- 扩展支持的操作范围,以覆盖更多模型。

- **演进路径**:
- **v1**: 实现核心的矩阵乘法和量化操作。
- **v2**: 增加对更多激活函数和归一化操作的支持。
- **v3**: 优化数据传输和内存管理,减少 CPU 和 DSP 之间的开销。
- **v4**: 支持混合精度计算,进一步提升性能。

## 核心组件、关键特性与核心功能

- **核心组件**:
- **`ggml_hexagon_session`**: 管理与 DSP 的会话,包括初始化、资源分配和任务提交。
- **`ggml_backend_hexagon_buffer`**: 管理在 DSP 上分配的内存,处理数据传输。
- **HTP (Hexagon Tensor Processor) 内核**: 在 DSP 上执行的实际计算代码,位于 `htp/` 目录下。

- **关键特性**:
- **DSP 卸载**: 将计算密集型任务从 CPU 卸载到低功耗、高性能的 DSP。
- **HVX 加速**: 利用 Hexagon Vector eXtensions (HVX) SIMD 引擎来加速计算。
- **异步执行**: CPU 和 DSP 可以并行工作,提升整体效率。

- **核心功能/算法**:
- **量化/反量化**: 支持 `Q4_0`, `Q8_0` 等量化类型,包括在 CPU 和 DSP 之间传输时的打包/解包逻辑。
- **矩阵乘法**: 优化的 `mul_mat` 实现,是 Transformer 模型中的核心操作。
- **激活函数**: 实现了 `silu`, `gelu` 等常用的激活函数。
- **归一化**: 实现了 `rms_norm` 等归一化操作。

- **时间/空间复杂度**:
- **矩阵乘法**: 时间复杂度为 O(N*M*K),空间复杂度为 O(N*M + M*K + N*K)。通过 DSP 加速,实际执行时间会远小于在 CPU 上的执行时间。
- **数据传输**: 传输开销与数据大小成正比,是性能优化的关键点之一。

## 关键用例

- **用例:在手机上运行一个大型语言模型**
1. 用户在手机上启动一个使用 `ggml` 的应用(如聊天机器人)。
2. 应用加载模型,`ggml` 检测到设备支持 Hexagon DSP,并初始化 `ggml-hexagon` 后端。
3. 用户输入文本,模型开始进行推理。
4. 在推理过程中,`ggml` 将矩阵乘法等计算任务卸载到 `ggml-hexagon` 后端。
5. `ggml-hexagon` 将任务发送到 DSP 执行。
6. DSP 高效地完成计算,并将结果返回给 CPU。
7. CPU 继续后续的计算,并将最终结果呈现给用户。
8. 用户感受到流畅的交互,而手机的功耗和发热也得到了很好的控制。
37 changes: 37 additions & 0 deletions ggml/src/ggml-hexagon/doc/ggml-hexagon_stage3_perf_debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 3. 性能瓶颈分析与调试

## 潜在性能瓶颈

- **最可能发生性能瓶颈的部分**:
1. **CPU 与 DSP 之间的数据传输**:
- **原因**: 尽管有 DMA,但频繁或大量的数据传输仍然会带来显著的延迟。如果计算任务的粒度太小,数据传输的开销可能会超过在 DSP 上计算带来的收益。
2. **内存分配与管理**:
- **原因**: `rpcmem_alloc` 等函数的调用可能比较耗时。如果内存管理不当,频繁的分配和释放会导致性能下降。
3. **DSP 上的计算内核**:
- **原因**: 如果 HVX 代码没有被充分优化,或者线程池管理不当,可能会导致 DSP 的计算资源没有被充分利用。
4. **任务调度与同步**:
- **原因**: CPU 和 DSP 之间的同步开销,以及任务队列的管理,如果处理不当,可能会导致 DSP 空闲或者 CPU 等待时间过长。

## 调试与排查步骤

1. **高层性能分析**:
- 使用 `ggml` 的性能分析工具,确认是 `ggml-hexagon` 后端导致了性能问题。
- 记录 `ggml_hexagon_graph_compute` 等关键函数的执行时间。

2. **分析 CPU 与 DSP 的交互**:
- 在 `ggml-hexagon.cpp` 中,记录每次调用 `dspqueue_write` 和 `dspqueue_read` 的时间戳,分析任务提交和结果返回的延迟。
- 统计单位时间内的数据传输量,判断是否是数据传输的瓶颈。

3. **分析 DSP 端的性能**:
- 使用 Qualcomm Hexagon SDK 提供的性能分析工具(如 `hexagon-profiler`)来分析 DSP 上的代码。
- 确认是哪个计算内核(`*-ops.c`)最耗时。
- 检查 HVX 指令的利用率,确认计算单元是否饱和。
- 分析 L2 缓存的命中率,判断是否存在内存访问瓶颈。

4. **代码层面的调试**:
- 在 `ggml-hexagon.cpp` 和 `htp/` 目录下的代码中添加详细的日志输出,追踪代码的执行流程。
- 使用 Hexagon SDK 提供的调试工具(如 `hexagon-gdb`)来单步调试 DSP 上的代码,检查变量的值和程序的执行状态。

5. **内存分析**:
- 监控 `rpcmem` 的使用情况,检查是否存在内存泄漏。
- 分析内存分配的模式,考虑是否可以使用内存池等技术来优化。
61 changes: 61 additions & 0 deletions ggml/src/ggml-hexagon/doc/ggml-hexagon_stage4_docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 4. 文档建议

## Wiki 文档与详细设计文档

### Wiki 文档建议

- **1. 快速入门 (Quick Start)**
- **1.1. 环境搭建**:
- 如何安装 Qualcomm Hexagon SDK。
- 如何配置 `ggml` 以启用 Hexagon 后端。
- **1.2. 编译与运行**:
- 详细的编译步骤。
- 如何运行一个简单的示例来验证环境是否配置成功。

- **2. 架构概览 (Architecture Overview)**
- **2.1. 核心设计**:
- 项目的设计目标和核心原则。
- **2.2. 组件交互**:
- CPU 和 DSP 之间如何通信。
- `ggml-hexagon` 后端如何与 `ggml` 核心库交互。

- **3. 性能调优 (Performance Tuning)**
- **3.1. 性能分析**:
- 如何使用 `hexagon-profiler` 等工具来分析性能。
- **3.2. 常见优化技巧**:
- 如何减少数据传输开销。
- 如何优化 DSP 上的计算内核。

- **4. 如何贡献 (Contributing)**
- **4.1. 代码风格**:
- 项目遵循的编码规范。
- **4.2. 提交流程**:
- 如何提交 Pull Request。
- 如何编写有意义的 Commit Message。

### 详细设计文档建议

- **1. 接口设计 (Interface Design)**
- **1.1. `ggml` 后端接口**:
- `ggml-hexagon` 实现了 `ggml` 的哪些后端接口。
- 每个接口的输入、输出和功能。
- **1.2. CPU-DSP 通信接口**:
- 使用的 FastRPC 接口定义。
- 数据传输的格式和协议。

- **2. DSP 端设计 (DSP-Side Design)**
- **2.1. 线程模型**:
- `worker-pool` 的实现细节。
- 如何进行多线程同步。
- **2.2. 内存管理**:
- DSP 上的内存布局。
- VTCM 的使用策略。
- **2.3. HVX 内核设计**:
- 关键计算内核(如矩阵乘法)的 HVX 实现细节。
- 如何进行指令级的优化。

- **3. 数据流 (Data Flow)**
- **3.1. 计算图的执行**:
- `ggml` 的计算图如何被解析并发送到 DSP。
- **3.2. 数据的生命周期**:
- 一个 tensor 从创建、计算到销毁的完整流程。
41 changes: 41 additions & 0 deletions ggml/src/ggml-hexagon/doc/ggml-hexagon_stage5_practice_best.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 5. 练习题目与最佳实践

## 入门路径与练习题目

### 入门路径

1. **环境搭建**:
- 成功编译并运行 `ggml` 的一个示例,并启用 Hexagon 后端。
2. **理解数据流**:
- 在 `ggml-hexagon.cpp` 中添加日志,跟踪一个 `ggml` 操作(如 `ggml_mul_mat`)从被调用到在 DSP 上执行完成的全过程。
3. **理解 DSP 代码**:
- 阅读 `htp/main.c` 和 `htp/matmul-ops.c`,理解 DSP 是如何接收任务并执行矩阵乘法的。
4. **尝试修改**:
- 在 `htp/matmul-ops.c` 中,修改矩阵乘法的实现(例如,将其改为一个简单的循环),并观察结果的变化。

### 练习题目

1. **添加一个新的激活函数**:
- **题目**: 在 `htp/unary-ops.c` 中,实现一个新的激活函数(如 `LeakyReLU`)。
- **目标**: 学习如何添加一个新的 DSP 计算内核,并将其集成到 `ggml-hexagon` 后端中。
2. **优化数据传输**:
- **题目**: 找到一个可以优化的数据传输场景(例如,多个小的 `memcpy` 可以合并为一个大的),并进行优化。
- **目标**: 学习如何分析和优化 CPU 与 DSP 之间的数据传输。
3. **使用 HVX 指令**:
- **题目**: 选择一个简单的操作(如向量加法),并使用 HVX intrinsics 来实现它。
- **目标**: 学习如何使用 HVX SIMD 引擎来加速计算。

## 最佳实践

- **开发**:
- **编写单元测试**: 为每个 DSP 计算内核编写单元测试,确保其正确性。
- **使用性能分析工具**: 在开发过程中,持续使用 `hexagon-profiler` 等工具来监控性能,避免引入性能回退。
- **代码注释**: 为关键的代码路径和算法添加详细的注释,方便他人理解。
- **维护**:
- **持续集成 (CI)**: 搭建 CI 系统,自动编译和运行测试,确保代码质量。
- **版本管理**: 使用清晰的版本号,并为每个版本提供详细的发布说明。
- **文档同步**: 在修改代码的同时,及时更新相关的文档。
- **扩展**:
- **保持接口稳定**: 尽量不要修改现有的 `ggml` 后端接口,以保持向后兼容性。
- **模块化设计**: 在添加新功能时,尽量遵循现有的模块化设计,将不同的功能放到不同的文件中。
- **考虑通用性**: 在实现新的计算内核时,考虑其是否可以被其他操作复用。
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 6. 模块问题排查

## 模块出现问题的可能原因

- **1. 环境配置问题**:
- Hexagon SDK 版本不兼容。
- 环境变量(如 `HEXAGON_SDK_ROOT`)未正确设置。
- 编译选项不正确。
- **2. 硬件或驱动问题**:
- 设备不支持 Hexagon DSP。
- DSP 驱动版本过低。
- 硬件故障。
- **3. 代码 Bug**:
- **CPU 端**:
- 内存管理错误(如内存泄漏、越界访问)。
- 任务调度逻辑错误。
- 数据同步问题。
- **DSP 端**:
- 计算内核实现错误。
- HVX 指令使用不当。
- 线程同步问题(如死锁)。
- **4. 数据问题**:
- 输入数据格式不正确。
- 输入数据中包含 NaN 或 Inf。

## 模块排查步骤

1. **检查配置和环境**:
- 确认 Hexagon SDK 版本是否与项目要求一致。
- 检查所有相关的环境变量是否已正确设置。
- 清理并重新编译整个项目。

2. **运行最小可复现示例**:
- 使用一个最简单的模型和输入,看问题是否能够复现。
- 如果最小示例可以正常运行,说明问题可能与特定的模型或数据有关。

3. **查看日志**:
- 仔细检查 `ggml` 和 `ggml-hexagon` 输出的日志,查找错误或警告信息。
- 增加更详细的日志输出,以定位问题发生的代码位置。

4. **分段排查**:
- **禁用 Hexagon 后端**: 临时禁用 `ggml-hexagon` 后端,看问题是否消失。如果问题消失,说明是 `ggml-hexagon` 模块的问题。
- **CPU-DSP 边界排查**: 在 `ggml-hexagon.cpp` 中,检查发送到 DSP 的数据是否正确,以及从 DSP 返回的数据是否符合预期。
- **DSP 内部排查**: 使用 `hexagon-gdb` 来单步调试 DSP 上的代码,检查计算过程中的中间结果。

5. **硬件和驱动检查**:
- 在另一台相同型号的设备上运行,看问题是否能够复现。
- 检查设备的系统更新,确保 DSP 驱动是最新版本。

6. **代码审查 (Code Review)**:
- 仔细审查最近的代码变更,看是否有可能引入问题的修改。
- 请求其他同事对相关的代码进行审查。
8 changes: 8 additions & 0 deletions scripts/snapdragon/adb/run-server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cd /data/local/tmp/llama.cpp
export LD_LIBRARY_PATH=$PWD/lib
export ADSP_LIBRARY_PATH=$PWD/lib

GGML_HEXAGON_NDEV=2 ./bin/llama-server --no-mmap -m ../gguf/LFM2-8B-A1B-Q4_0.gguf \
--poll 1000 -t 6 --cpu-mask 0xfc --cpu-strict 1 \
--ctx-size 8192 --batch-size 128 -ctk q8_0 -ctv q8_0 -fa on \
-ngl 99 --device HTP0,HTP1 --host 0.0.0.0 --verbose &
1 change: 1 addition & 0 deletions surfing.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
一步步推导点到平面距离公式。请先回答你是谁。还有哪些相关问题及灵感。