diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000..007607fd305a0 --- /dev/null +++ b/.vscode/settings.json @@ -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", + ], +} \ No newline at end of file diff --git a/docs/backend/hexagon/README.md b/docs/backend/hexagon/README.md index 85f136ef9eef0..09d8a94b5f114 100644 --- a/docs/backend/hexagon/README.md +++ b/docs/backend/hexagon/README.md @@ -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) ``` @@ -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 diff --git a/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage1_architecture.md b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage1_architecture.md new file mode 100644 index 0000000000000..0991daf7529e0 --- /dev/null +++ b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage1_architecture.md @@ -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 +``` diff --git a/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage2_goals_features.md b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage2_goals_features.md new file mode 100644 index 0000000000000..9bbfca4a16361 --- /dev/null +++ b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage2_goals_features.md @@ -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. 用户感受到流畅的交互,而手机的功耗和发热也得到了很好的控制。 diff --git a/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage3_perf_debug.md b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage3_perf_debug.md new file mode 100644 index 0000000000000..0bd44dbeeeea8 --- /dev/null +++ b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage3_perf_debug.md @@ -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` 的使用情况,检查是否存在内存泄漏。 + - 分析内存分配的模式,考虑是否可以使用内存池等技术来优化。 diff --git a/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage4_docs.md b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage4_docs.md new file mode 100644 index 0000000000000..ee28391f934c4 --- /dev/null +++ b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage4_docs.md @@ -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 从创建、计算到销毁的完整流程。 diff --git a/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage5_practice_best.md b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage5_practice_best.md new file mode 100644 index 0000000000000..a08bf63a98526 --- /dev/null +++ b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage5_practice_best.md @@ -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` 后端接口,以保持向后兼容性。 + - **模块化设计**: 在添加新功能时,尽量遵循现有的模块化设计,将不同的功能放到不同的文件中。 + - **考虑通用性**: 在实现新的计算内核时,考虑其是否可以被其他操作复用。 diff --git a/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage6_module_troubleshoot.md b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage6_module_troubleshoot.md new file mode 100644 index 0000000000000..27c9e49484d36 --- /dev/null +++ b/ggml/src/ggml-hexagon/doc/ggml-hexagon_stage6_module_troubleshoot.md @@ -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)**: + - 仔细审查最近的代码变更,看是否有可能引入问题的修改。 + - 请求其他同事对相关的代码进行审查。 diff --git a/scripts/snapdragon/adb/run-server.sh b/scripts/snapdragon/adb/run-server.sh new file mode 100755 index 0000000000000..3448d606112a6 --- /dev/null +++ b/scripts/snapdragon/adb/run-server.sh @@ -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 & diff --git a/surfing.txt b/surfing.txt new file mode 100644 index 0000000000000..2761d131a6618 --- /dev/null +++ b/surfing.txt @@ -0,0 +1 @@ +一步步推导点到平面距离公式。请先回答你是谁。还有哪些相关问题及灵感。 \ No newline at end of file