Skip to content

Commit 7aa2428

Browse files
committed
First review of llama.cpp with Streamline Learning Path
1 parent 1cdc34f commit 7aa2428

8 files changed

Lines changed: 235 additions & 177 deletions

File tree

content/learning-paths/servers-and-cloud-computing/llama_cpp_streamline/1_overview.md

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,21 @@ weight: 2
66
layout: learningpathall
77
---
88

9-
## Overview: Profiling LLMs on Arm CPUs with Streamline
9+
## Profiling LLMs on Arm CPUs with Streamline
1010

11-
Large Language Models (LLMs) run efficiently on Arm CPUs.
12-
Frameworks that run LLMs, such as [**llama.cpp**](https://github.com/ggml-org/llama.cpp), provides a convenient framework for running LLMs, it also comes with a certain level of complexity.
11+
Deploying Large Language Models (LLMs) on Arm CPUs provides a power-efficient and flexible solution. While larger models may benefit from GPU acceleration, techniques like quantization enable a wide range of LLMs to perform effectively on CPUs alone.
12+
13+
Frameworks such as [**llama.cpp**](https://github.com/ggml-org/llama.cpp), provide a convenient way to run LLMs, but it also comes with a certain level of complexity.
1314

1415
To analyze their execution and use profiling insights for optimization, you need both a basic understanding of transformer architectures and the right analysis tools.
1516

16-
This learning path demonstrates how to use the **llama-cli** application from llama.cpp together with **Arm Streamline** to analyze the efficiency of LLM inference on Arm CPUs.
17+
This Learning Path demonstrates how to use `llama-cli` application from llama.cpp together with Arm Streamline to analyze the efficiency of LLM inference on Arm CPUs.
1718

18-
In this guide you will learn how to:
19-
- Profile token generation at the **Prefill** and **Decode** stages
19+
You will learn how to:
20+
- Profile token generation at the Prefill and Decode stages
2021
- Profile execution of individual tensor nodes and operators
21-
- Profile LLM execution across **multiple threads and cores**
22+
- Profile LLM execution across multiple threads and cores
2223

23-
You will run the **Qwen1_5-0_5b-chat-q4_0.gguf** model with llama-cli on **Arm64 Linux** and use Streamline for analysis.
24-
The same method can also be applied to **Arm64 Android** platforms.
24+
You will run the `Qwen1_5-0_5b-chat-q4_0.gguf` model using `llama-cli` on Arm Linux and use Streamline for analysis.
2525

26-
## Prerequisites
27-
Before starting this guide, you should be familiar with:
28-
- Basic understanding of llama.cpp
29-
- Understanding of transformer model
30-
- Knowledge of Streamline usage
31-
- An Arm Neoverse or Cortex-A hardware platform running Linux or Android to test the application
26+
The same method can also be applied to Android platforms.
Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,86 @@
11
---
2-
title: Understand the llama.cpp
2+
title: Understand llama.cpp
33
weight: 3
44

55
### FIXED, DO NOT MODIFY
66
layout: learningpathall
77
---
88

9-
## Understand the llama.cpp
9+
## Understand llama.cpp
1010

11-
**llama.cpp** is an open-source LLM framework implemented in C++ that supports both training and inference.
12-
This learning path focuses only on **inference on the CPU**.
11+
llama.cpp is an open-source LLM framework implemented in C++ that supports both training and inference.
1312

14-
The **llama-cli** tool provides a command-line interface to run LLMs with the llama.cpp inference engine.
13+
This Learning Path focuses on inference on Arm CPUs.
14+
15+
The `llama-cli` tool provides a command-line interface to run LLMs with the llama.cpp inference engine.
1516
It supports text generation, chat mode, and grammar-constrained output directly from the terminal.
1617

1718
![text#center](images/llama_structure.png "Figure 1. llama-cli Flow")
1819

19-
### What llama-cli does
20-
- Load and interpret LLMs in **.gguf** format
21-
- Build a **compute graph** based on the model structure
22-
- The graph can be divided into subgraphs, each assigned to the most suitable backend device
23-
- In this guide, all operators are executed on the **CPU backend**
24-
- Allocate memory for tensor nodes using the **graph planner**
25-
- Execute tensor nodes in the graph during the **graph_compute** stage, which traverses nodes and forwards work to backend devices
20+
### What does the Llama CLI do?
21+
22+
Here are the steps performed by `llama-cli`:
23+
24+
1. Load and interpret LLMs in GGUF format
25+
26+
2. Build a compute graph based on the model structure
27+
28+
The graph can be divided into subgraphs, each assigned to the most suitable backend device, but in this Learning Path all operations are executed on the Arm CPU backend.
29+
30+
3. Allocate memory for tensor nodes using the graph planner
2631

27-
Step2 to Step4 are wrapped inside the function **`llama_decode`**.
28-
During **Prefill** and **Decode**, `llama-cli` repeatedly calls `llama_decode` to generate tokens.
29-
The parameter **`llama_batch`** passed to `llama_decode` differs between stages, containing input tokens, their count, and their positions.
32+
4. Execute tensor nodes in the graph during the `graph_compute` stage, which traverses nodes and forwards work to backend devices
33+
34+
Steps 2 to 4 are wrapped inside the function `llama_decode`.
35+
During Prefill and Decode, `llama-cli` repeatedly calls `llama_decode` to generate tokens.
36+
37+
The parameter `llama_batch` passed to `llama_decode` differs between stages, containing input tokens, their count, and their positions.
38+
39+
### What are the components of llama.cpp?
3040

31-
### Components of llama.cpp
3241
The components of llama.cpp include:
33-
![text#center](images/llama_componetns.jpg "Figure 2. llmama.cpp components")
3442

35-
llama.cpp supports various backends such as `CPU`, `GPU`, `CUDA`, `OpenCL` etc.
43+
![text#center](images/llama_components.jpg "Figure 2. llama.cpp components")
44+
45+
llama.cpp supports various backends such as `CPU`, `GPU`, `CUDA`, and `OpenCL`.
46+
47+
For the CPU backend, it provides an optimized `ggml-cpu` library, mainly utilizing CPU vector instructions.
48+
49+
For Arm CPUs, the `ggml-cpu` library also offers an `aarch64` trait that leverages 8-bit integer multiply (i8mm) instructions for acceleration.
3650

37-
For the CPU backend, it provides an optimized `ggml-cpu` library (mainly utilizing CPU vector instructions).
38-
For Arm CPUs, the `ggml-cpu` library also offers an `aarch64` trait that leverages the new **I8MM** instructions for acceleration.
3951
The `ggml-cpu` library also integrates the Arm [KleidiAI](https://github.com/ARM-software/kleidiai) library as an additional trait.
4052

4153
### Prefill and Decode in autoregressive LLMs
42-
Most autoregressive LLMs are Decoder-only model.
43-
Here is a brief introduction to Prefill and Decode stage of autoregressive LLMs.
44-
![text#center](images/llm_prefill_decode.jpg "Figure 3. Prefill and Decode stage")
54+
55+
An autoregressive LLM is a type of Large Language Model that generates text by predicting the next token (word or word piece) in a sequence based on all the previously generated tokens.
56+
57+
The term "autoregressive" means the model uses its own previous outputs as inputs for generating subsequent outputs, creating a sequential generation process.
58+
59+
For example, when generating the sentence "The cat sat on the", an autoregressive LLM:
60+
1. Takes the input prompt as context
61+
2. Predicts the next most likely token (e.g., "mat")
62+
3. Uses the entire sequence including "mat" to predict the following token
63+
4. Continues this process token by token until completion
64+
65+
This sequential nature is why autoregressive LLMs have two distinct computational phases: Prefill (processing the initial prompt) and Decode (generating tokens one by one).
66+
67+
Most autoregressive LLMs are Decoder-only models. This refers to the transformer architecture they use, which consists only of decoder blocks from the original Transformer paper. The alternatives to decoder-only models include encoder-only models used for tasks like classification and encoder-decoder models used for tasks like translation.
68+
69+
Decoder-only models like LLaMA have become dominant for text generation because they are simpler to train at scale, can handle both understanding and generation tasks, and are more efficient for text generation.
70+
71+
Here is a brief introduction to Prefill and Decode stages of autoregressive LLMs.
72+
![text#center](images/llm_prefill_decode.jpg "Figure 3. Prefill and Decode stages")
4573

4674
At the Prefill stage, multiple input tokens of the prompt are processed.
47-
It mainly performs GEMM (A matrix is multiplied by another matrix) operations to generate the first output token.
75+
76+
It mainly performs GEMM (a matrix is multiplied by another matrix) operations to generate the first output token.
77+
4878
![text#center](images/transformer_prefill.jpg "Figure 4. Prefill stage")
4979

50-
At the Decode stage, by utilizing the [KV cache](https://huggingface.co/blog/not-lain/kv-caching), it mainly performs GEMV (A vector is multiplied by a matrix) operations to generate subsequent output tokens one by one.
80+
At the Decode stage, by utilizing the [KV cache](https://huggingface.co/blog/not-lain/kv-caching), it mainly performs GEMV (a vector is multiplied by a matrix) operations to generate subsequent output tokens one by one.
81+
5182
![text#center](images/transformer_decode.jpg "Figure 5. Decode stage")
5283

53-
Therefore,
54-
- **Prefill** is **compute-bound**, dominated by large GEMM operations
55-
- **Decode** is **memory-bound**, dominated by KV cache access and GEMV operations
84+
In summary, Prefill is compute-bound, dominated by large GEMM operations and Decode is memory-bound, dominated by KV cache access and GEMV operations.
5685

57-
This can be seen in the subsequent analysis with Streamline.
86+
You will see this highlighted during the analysis with Streamline.

content/learning-paths/servers-and-cloud-computing/llama_cpp_streamline/3_llama.cpp_annotation.md

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
11
---
2-
title: Integrating Streamline Annotations into llama.cpp
2+
title: Integrate Streamline Annotations into llama.cpp
33
weight: 4
44

55
### FIXED, DO NOT MODIFY
66
layout: learningpathall
77
---
88

9-
## Integrating Streamline Annotations into llama.cpp
9+
## Integrate Streamline Annotations into llama.cpp
1010

11-
To visualize token generation at the **Prefill** and **Decode** stages, we use **Streamline’s Annotation Marker** feature.
12-
This requires integrating annotation support into the **llama.cpp** project.
13-
More information about the Annotation Marker API can be found [here](https://developer.arm.com/documentation/101816/9-7/Annotate-your-code?lang=en).
11+
To visualize token generation at the Prefill and Decode stages, you can use Streamline's Annotation Marker feature.
12+
13+
This requires integrating annotation support into the llama.cpp project.
14+
15+
More information about the Annotation Marker API can be found in the [Streamline User Guide](https://developer.arm.com/documentation/101816/9-7/Annotate-your-code?lang=en).
1416

1517
{{% notice Note %}}
16-
You can either build natively on an **Arm platform**, or cross-compile on another architecture using an Arm cross-compiler toolchain.
18+
You can either build natively on an Arm platform, or cross-compile on another architecture using an Arm cross-compiler toolchain.
1719
{{% /notice %}}
1820

1921
### Step 1: Build Streamline Annotation library
2022

2123
Install [Arm DS](https://developer.arm.com/Tools%20and%20Software/Arm%20Development%20Studio) or [Arm Streamline](https://developer.arm.com/Tools%20and%20Software/Streamline%20Performance%20Analyzer) on your development machine first.
2224

23-
Streamline Annotation support code in the installation directory such as *"Arm\Development Studio 2024.1\sw\streamline\gator\annotate"*.
25+
Streamline Annotation support code is in the installation directory such as `Arm/Development Studio 2024.1/sw/streamline/gator/annotate`.
2426

25-
For installation guidance, refer to the [Streamline installation guide](https://learn.arm.com/install-guides/streamline/).
27+
For installation guidance, refer to the [Streamline installation guide](/install-guides/streamline/).
2628

2729
Clone the gator repository that matches your Streamline version and build the `Annotation support library`.
2830

29-
The installation step is depends on your development machine.
31+
The installation step depends on your development machine.
32+
33+
For Arm native build, you can use the following instructions to install the packages.
3034

31-
For Arm native build, you can use following insturction to install the packages.
32-
For other machine, you need to set up the cross compiler environment by install [aarch64 gcc compiler toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads).
33-
You can refer this [guide](https://learn.arm.com/install-guides/gcc/cross/) for Cross-compiler installation.
35+
For other machines, you need to set up the cross compiler environment by installing [Arm GNU toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads).
36+
37+
You can refer to the [GCC install guide](https://learn.arm.com/install-guides/gcc/cross/) for cross-compiler installation.
3438

3539
{{< tabpane code=true >}}
3640
{{< tab header="Arm Native Build" language="bash">}}
@@ -40,7 +44,6 @@ You can refer this [guide](https://learn.arm.com/install-guides/gcc/cross/) for
4044
git clone https://github.com/ARM-software/gator.git
4145
cd gator
4246
./build-linux.sh
43-
4447
cd annotate
4548
make
4649
{{< /tab >}}
@@ -49,20 +52,22 @@ You can refer this [guide](https://learn.arm.com/install-guides/gcc/cross/) for
4952
apt-get install ninja-build cmake gcc g++ g++-aarch64-linux-gnu curl zip unzip tar pkg-config git
5053
cd ~
5154
git clone https://github.com/ARM-software/gator.git
52-
5355
cd gator
5456
make CROSS_COMPILE=/path/to/aarch64_linux_gcc_tool
5557
{{< /tab >}}
5658
{{< /tabpane >}}
5759

58-
Once complete, the static library **libstreamline_annotate.a** will be generated at `~/gator/annotate/libstreamline_annotate.a` and the header file at: `gator/annotate/streamline_annotate.h`
60+
Once complete, the static library `libstreamline_annotate.a` will be generated at `~/gator/annotate/libstreamline_annotate.a` and the header file is at `gator/annotate/streamline_annotate.h`.
5961

6062
### Step 2: Integrate Annotation Marker into llama.cpp
6163

62-
Next, we need to install **llama.cpp** to run the LLM model.
63-
To make the following performance profiling content easier to follow, this Learning Path will use a specific release version of llama.cpp to ensure the steps and results remain consistent.
64+
Next, you need to install llama.cpp to run the LLM model.
6465

65-
Before the build **llama.cpp**, create a directory `streamline_annotation` and copy the library `libstreamline_annotate.a` and the header file `streamline_annotate.h` into the folder.
66+
{{% notice Note %}}
67+
To make the performance profiling content easier to follow, this Learning Path uses a specific release version of llama.cpp to ensure the steps and results remain consistent.
68+
{{% /notice %}}
69+
70+
Before building llama.cpp, create a directory `streamline_annotation` and copy the library `libstreamline_annotate.a` and the header file `streamline_annotate.h` into the new directory.
6671

6772
```bash
6873
cd ~
@@ -74,21 +79,21 @@ mkdir streamline_annotation
7479
cp ~/gator/annotate/libstreamline_annotate.a ~/gator/annotate/streamline_annotate.h streamline_annotation
7580
```
7681

77-
To link `libstreamline_annotate.a` library when building llama-cli, adding following lines in the end of `llama.cpp/tools/main/CMakeLists.txt`.
82+
To link the `libstreamline_annotate.a` library when building llama-cli, add the following lines at the end of `llama.cpp/tools/main/CMakeLists.txt`.
7883

7984
```makefile
8085
set(STREAMLINE_LIB_PATH "${CMAKE_SOURCE_DIR}/streamline_annotation/libstreamline_annotate.a")
8186
target_include_directories(llama-cli PRIVATE "${CMAKE_SOURCE_DIR}/streamline_annotation")
8287
target_link_libraries(llama-cli PRIVATE "${STREAMLINE_LIB_PATH}")
8388
```
8489

85-
To add Annotation Markers to llama-cli, change the llama-cli code **llama.cpp/tools/main/main.cpp** by adding
90+
To add Annotation Markers to `llama-cli`, change the `llama-cli` code in `llama.cpp/tools/main/main.cpp` by adding the include file:
8691

8792
```c
8893
#include "streamline_annotate.h"
8994
```
9095

91-
After the call to common_init(), add the setup macro:
96+
After the call to `common_init()`, add the setup macro:
9297

9398
```c
9499
common_init();
@@ -125,16 +130,16 @@ A string is added to the Annotation Marker to record the position of input token
125130
126131
### Step 3: Build llama-cli
127132
128-
For convenience, llama-cli is **static linked**.
133+
For convenience, llama-cli is statically linked.
129134
130-
Firstly, create a new directory `build` understand llama.cpp root directory and go into it.
135+
Create a new directory `build` under the llama.cpp root directory and change to the new directory:
131136
132137
```bash
133138
cd ~/llama.cpp
134-
mkdir ./build & cd ./build
139+
mkdir build && cd build
135140
```
136141

137-
Then configure the project by running
142+
Next, configure the project.
138143

139144
{{< tabpane code=true >}}
140145
{{< tab header="Arm Native Build" language="bash">}}
@@ -174,23 +179,20 @@ Then configure the project by running
174179
{{< /tabpane >}}
175180

176181

177-
Set `CMAKE_C_COMPILER` and `DCMAKE_CXX_COMPILER` to your cross compiler path. Make sure that **-march** in `DCMAKE_C_FLAGS` and `CMAKE_CXX_FLAGS` matches your Arm CPU hardware.
182+
Set `CMAKE_C_COMPILER` and `CMAKE_CXX_COMPILER` to your cross compiler path. Make sure that -march in `CMAKE_C_FLAGS` and `CMAKE_CXX_FLAGS` matches your Arm CPU hardware.
178183

179184

180-
In this learning path, we run llama-cli on an Arm CPU that supports **NEON Dotprod** and **I8MM** instructions.
181-
Therefore, we specify: **armv8.2-a+dotprod+i8mm**.
185+
With the flags above you can run `llama-cli` on an Arm CPU that supports NEON dot product and 8-bit integer multiply (i8mm) instructions.
182186

183-
We also specify **-static** and **-g** options:
184-
- **-static**: produces a statically linked executable, so it can run on different Arm64 Linux/Android environments without needing shared libraries.
185-
- **-g**: includes debug information, which makes source code and function-level profiling in Streamline much easier.
187+
The `-static` and `-g` options are also specified to produce a statically linked executable, so it can run on different Arm64 Linux/Android environments without needing shared libraries and to include debug information, which makes source code and function-level profiling in Streamline much easier.
186188

187-
so that the llama-cli executable is static linked and with debug info. This makes source code/function level profiling easier and the llama-cli executable runnable on various version of Arm64 Linux/Android.
188-
189-
Now you can build the project by running:
189+
Now you can build the project using `cmake`:
190190

191191
```bash
192192
cd ~/llama.cpp/build
193193
cmake --build ./ --config Release
194194
```
195195

196-
After the building process, you should find the llama-cli will be generated at **~/llama.cpp/build/bin/** directory.
196+
After the building process completes, you can find the `llama-cli` in the `~/llama.cpp/build/bin/` directory.
197+
198+
You now have an annotated version of `llama-cli` ready for Streamline.

0 commit comments

Comments
 (0)