# benchmark

## 什么是 benchmark?

benchmark 是一种评估和测量计算机的硬件或软件性能的方法，这通常涉及运行一系列 标准测试，然后对结果进行比较。这种方法可以用来评价不同硬件配置、操作系统、 或者软件程序的性能。

在软件开发中，benchmark 通常用来测量代码的运行效率，以便找出性能瓶颈并对其进行优化。

## sysbench

### 简介

sysbench 是一种模块化、跨平台和多线程的 benchmark 工具，用于评估操作系统性能， 如：运行密集负载下的数据库场景。这个 benchmark 合适快速获得系统性能的数据， 不需要设置复杂的数据库基准测试，甚至不需要安装任何数据库。sysbench 并行执行指定 数量的线程，实际工作负载取决于指定的测试模式。

内置的数据库，如下：

* mysql - MySQL driver
* pgsql - PostgreSQL driver

内置的测试模式，如下：

* fileio - File I/O test
* cpu - CPU performance test
* memory - Memory functions speed test
* threads - Threads subsystem performance test
* mutex - Mutex performance test

### 安装

```bash
$ apt install sysbench
```

### 参数解析

```bash
$ sysbench [common-options] --test=name [test-options] <command>
```

* common-options

`--threads=N`，指定使用的线程个数

* `--test=name`

可以指定内置的测试模式，如 `fileio`、`cpu`、`memory`、`threads`、`mutex`。 这些内置的测试模式都有默认的测试选项。如：`memory` 模式，默认内存块大小 1K 、 传输数据总量 100G、不从 HugeTLB 内存池分配内存、对内存执行写操作、按照顺序访问内存。

* test-options

每一个内置的测试模式都有不同的测试选项，可以通过 `sysbench --test=name help` 查看

* command

支持 prepare、run、cleanup、help 命令。

### 例子

`$ sysbench --test=memory run` 测试内存，使用默认值。

## hackbench

### 简介

hackbench 是内核调度器的基准测试和压力测试，属于 [rt-tests](https://wiki.linuxfoundation.org/realtime/documentation/howto/tools/rt-tests) 工具的一部分。也能够通过重复创建/销毁线程对内存子系统进行压力测试。在一定程度上， 也能够对进程间通信(local sockets, pipes) 进行压力测试。

hackbench 目的是识别系统中的瓶颈，从而进行优化。

hackbench 能够用于生成系统负载，从而使用 cyclictest 测量延迟。但是，它不能用于 准确模拟 RT 进程生成的负载，因为 hackbench 不测试设备通信。

### 安装

```bash
$ apt install rt-tests
or
$ git clone git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
$ cd rt-tests
$ make all      ## or make hackbench 只编译 hackbench 命令
$ make install
```

### 参数解析

* -f --fds=NUM 指定每个 group 使用多少个发送/接收 FD 来测试， 默认 20, 即 20 send FD + 20 receive FD
* -g --groups=NUM 指定使用多少个 group 来测试，默认 10
* -p --pipe 指定通过 pipe 来发送数据
* -l --loops=LOOPS 指定发送数据的次数，默认 100
* -s --datasize=SIZE 指定每次发送数据的大小，默认 100
* -T --threads 线程模式
* -P --process 进程模式，默认

### 例子

```bash
$ hackbench -s 512 -l 200 -g 15 -f 25 -P
Running in process mode with 15 groups using 50 file descriptors each (== 750 tasks)
Each sender will pass 200 messages of 512 bytes
Time: 8.968
```

进程模式，使用 15 个 group，每个 group 使用 25 个发送/接收 FD，循环发送 200 次数据， 每次发送数据的大小为 512 bytes。花费时间为 8.968 秒

## unixbench

### 简介

UnixBench 用于测试系统性能，这是一个系统基准测试，而不是 CPU、RAM、disk 的基准测试。

如果系统有多个 CPU，默认同一个测试用例运行两次，一次在单核运行测试，另一次 在多核运行测试。这旨在评估：

* 运行单个任务时系统的性能
* 运行多个任务时系统的性能
* 系统实现并行处理带来的收益

### 安装

```bash
$ git clone https://github.com/kdlucas/byte-unixbench.git
```

### 参数解析

```bash
$ ./Run [ -q | -b | -v ] [-i <n> ] [-c <n> [-c <n> ...]] [test ...]
```

* `-q` 运行在 quiet 模式，不要输出日志到终端
* `-b` 运行在 brief 模式，不要显示 cpu 信息详细信息
* `-v` 运行在 verbose 模式
* `-i <count>` 指定一个测试用例运行的次数
* `-c <n>` 指定多少个 CPU 同时运行一个测试用例
* `test` 指定只运行某个测试用例，通过 [USAGE-Tests](https://github.com/kdlucas/byte-unixbench/blob/master/UnixBench/USAGE) 小节获得有哪些测试用例。

### 例子

```bash
$ cd byte-unixbench/UnixBench/
$ ./Run                         ## 相当于 ./Run -c 1 -c <max_cpu_nr> index
```

默认运行 system test 的所有测试用例，分别以单核/多核方式运行，最后输出分数。

```bash
$ ./Run -c 1 syscall
```

以单核方式只运行 syscall 测试用例，最后输出分数。

## memtester

### 简介

memtester是一个有效的用户空间测试器，用于对内存子系统进行压力测试。

### 安装

```bash
$ apt install memtester
```

### 参数解析

```bash
$ memtester [-p PHYSADDR [-d DEVICE]] <MEMORY> [ITERATIONS]
```

* `-p PHYSADDR`

指定从物理地址 PHYSADDR（十六进制）开始的内存区域进行测试，还可以由 `-d` 指定 测试设备（默认为 `/dev/mem`）。主要用于硬件开发人员，用于测试内存映射 I/O 设备。

注意，在测试期间，指定的内存区域将被覆盖。如果指定为系统软件的内存区域是不安全的， 会导致 crash 现象。如果必须测试指定内存区域，建议让测试软件分配指定内存区域并且 保持分配状态，再使用此选项。

* `MEMORY`

代表分配、测试的内存大小，可以添加 `B/K/M/G` 后缀，默认以 `M` 为单位。 注意，指定测试的内存大小必须小于系统中可用内存总量。

* `ITERATIONS`

代表循环次数，默认为无限循环。

### 例子

`$ memtester 10M 1` 分配 10MB 内存进行压力测试，循环测试1轮。

## mmtests

### 简介

mmtests 是一个用于自动化和标准化 Linux 内核性能测试的框架。它支持多种测试场景 （如内存、调度、IO 等），通过统一的配置和脚本，简化测试流程，便于对不同内核版本或参数进行对比分析。

mmtests 具有高度可扩展性，适合批量运行和结果收集，广泛用于内核开发和性能调优。

mmtests 是一个测试框架，支持测试 kbuild、vm-scalability、redis、unixbenc、stress-ng 等。

### 下载

```bash
$ git clone https://github.com/gormanm/mmtests.git
```

### 安装依赖

```bash
## fedora
$ dnf install perl perl-File-Slurp R
$ perl -MCPAN -e "install List::BinarySearch"
$ perl -MCPAN -e "install Math::Gradient"

## ubuntu
$ apt install perl r-base
$ cpanm File::Which
```

### 使用

```bash
$ ./run-mmtests.sh --no-monitor --config configs/config-workload-kernbench-max baseline
$ ./run-mmtests.sh --no-monitor --config configs/config-workload-kernbench-max withxxx
$ cd work/log
$ ../../compare-kernels.sh --baseline baseline --compare withxxx
```

使用 config-workload-kernbench-max 测试 kbuild，最终调用 compare-kernels.sh 输出结果。 下面对每一个配置文件进行解释。

* config-workload-kernbench-max : 使用 make 编译 linux 内核，统计消耗时间
* config-memdb-redis-benchmark-small : 使用 redis-benchmark 测试，统计 p50/p95/p99
* config-workload-usemem : 使用 vm-scalability usemem 进行压力测试

### 搭建本地 mirror

[通过 Apache HTTP 服务器来搭建本地 mirror](/notes/tools/http.md)

### 减少性能波动

由于系统本身存在噪音，即使在同一个环境中（物理机/操作系统/内核/benchmark配置等）， 运行多次后，存在一定范围的性能波动。

为了减少性能波动，我们需要尽量排除一些影响较大的波动，其中影响最大的是 CPU 频率、 idle 深度睡眠、高温降频、大小核等。下面分别对这些影响项进行调整。

* CPU governors

```bash
$ cpupower frequency-set -g performance                          ## 设置 cpu governor 为 performance 模式
$ cpupower -c all frequency-info | grep "performance preference" ## 查询
```

* cpu idle status

```bash
$ cpupower idle-set -D 1 ## 设置 CPU 空闲状态，禁用深度睡眠状态
$ cpupower idle-info     ## 查询
```

* big-small core

```bash
$ cpupower -c all frequency-info | grep "hardware limits" ## 查询
$ taskset -pc 0-15 <pid>                                  ## 将进程 pid 绑定在大核 0~15
```

如果测试机器存在大小核，尽量将测试项绑核在大核进行测试，避免自动选择大小核导致 性能波动大。

## stress-ng

## kselftest

### 简介

`kselftest` 是 **Linux 内核自带的测试套件**。它不是一个单一的测试程序， 是一个**框架和一组测试用例的集合**，用于对 Linux 内核的各个子系统进行**功能测试**。

它的主要特点是：

* **轻量级**：测试程序通常是简单的用户空间程序。
* **快速**：旨在为内核开发者提供快速的反馈。
* **自包含**：源码位于内核源代码树内（`tools/testing/selftests`）。

> 内核编译项：
>
> * tools/testing/selftests/mm/config
> * tools/testing/selftests/bpf/config

### 编译+执行测试

对全部 kselftest 进行 `build/clean/run` 操作，如下：

```bash
$ make kselftest         ## Build and run kernel selftest
$ make kselftest-all     ## Build kernel selftest
$ make kselftest-clean   ## Remove all generated kselftest files
```

只对 kselftest 的 mm 部分进行 `build/clean/run` 操作，如下：

```bash
$ cd tools/testing/selftests/mm
$ make                      ## build
$ make clean                ## clean
$ ./run_vmtests.sh -a       ## run all mm tests
$ ./run_vmtests.sh -t "cow" ## run cow tests only
```

### 参考

Documentation/dev-tools/testing-overview\.rst `The Difference Between KUnit and kselftest` Documentation/dev-tools/kselftest.rst

## kunit

Documentation/dev-tools/testing-overview\.rst `The Difference Between KUnit and kselftest` Documentation/dev-tools/kunit/

## vm-scalability

为了测试 Linux 内核 `mm/` 目录中的功能

`hw_vars`：提供系统配置环境信息（如总内存、CPU 数量、大页数量等），可提取所有 `/proc/meminfo` 输出。 `run_cases`：执行全部测试用例 `run`：执行指定测试用例，下面对每一个测试进行简单介绍。

**基础内存测试**

`case-000-anon`：通过匿名内存区域连续写入填充 1/3 总内存，测试页错误处理及内存分配 `case-000-shm`：通过 mmap 访问 tmpfs 文件进行连续写入填充 1/3 内存

**匿名页测试**

`case-anon-w-seq/rand`：多进程分配系统内存 1/2 进行顺序/随机写入 `case-anon-w-seq/rand-mt`：多线程分配系统内存 1/2 进行顺序/随机写入, `-mt` 都为多线程版本 `case-anon-r-seq/rand(-mt)`：mmap 匿名区域后顺序/随机读取，触发页错误，测试零页快速路径 `case-anon-cow-seq/rand(-mt)`：父进程分配匿名内存后 fork 子进程，进行顺序/随机写入，测试写时复制(COW) `case-anon-rx-seq-mt`：预分配后顺序读取，对比非预分配场景性能 `case-anon-wx-seq/rand-mt`：预分配后写入

**文件页测试**

`case-lru-file-mmap-read/rand`：多进程 mmap 文件顺序/随机读取测试 LRU `case-lru-file-mmap-write`：同上，改为写入操作 `case-lru-file-readonce`：dd 读取文件（单次） `case-lru-file-readtwice`：文件读取两次 `case-lru-memcg`：内存限制为 1/3 总内存时执行 LRU 测试 `case-lru-shm`：多进程在 tmpfs 创建稀疏文件并读取填充半数内存 `case-lru-shm-rand`：随机读取版

**高级内存管理**

`case-mbind`：多进程分配内存后，通过 numa\_move\_pages/mbind 跨节点迁移页 `case-migrate-across-nodes`：多节点进程分配内存后迁移页，测试 migrate\_pages `case-mincore`：多线程随机读取后，mincore 统计驻留页 `case-mlock`：多进程 mlock 锁定内存区域 `case-mmap-pread-seq/rand`：mmap 稀疏文件后多进程顺序/随机读取（LRU 压力） `case-msync`：多进程写入稀疏文件后 msync 同步 `case-shm-pread-seq/rand`：多进程读取 tmpfs 文件（占 1/2 内存）

**特殊功能测试**

`case-direct-write`：O\_DIRECT 模式持续写入稀疏文件 `case-fork`：启动 20000 个空进程测试 fork 性能 `case-fork-sleep`：进程退出前睡眠 10 秒测试高并发进程场景 `case-hugetlb`：通过 `/proc/sys/vm/nr_hugepages` 分配/释放 1/3 内存的大页 `case-ksm`：每节点启动进程，分配 MemTotal/1000 私有匿名区，触发 KSM 合并零页 `case-ksm-hugepages`：透明大页场景下的 KSM 测试

### Download

```bash
$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/wfg/vm-scalability.git
```

### Compiling

```bash
$ cd vm-scalability
$ make
```

如果想要收集 `/proc/lock_stat`, `/debug/gcov` 和 `perf stats` 数据，需要使能 Linux 内核以下特性，并且系统安装 `perf`。

```
CONFIG_LOCK_STAT=y
CONFIG_GCOV_KERNEL=y
CONFIG_GCOV_PROFILE_ALL=y
CONFIG_PERF_EVENTS=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_TRANSPARENT_HUGEPAGE=y
```

### Running tests

```bash
$ cd vm-scalability
$ ./run case-anon-w-seq
```

运行 N 个任务，每个任务通过 mmap 映射匿名内存区域，其大小为整个系统内存的1/(2N)， 并顺序地向该区域写入，触发 pagefault 进行内存分配。

即 N 个进程分配系统内存 1/2 进行顺序写入测试。

## kdevops

## ltp

ltp 全称 Linux Test Project，该项目旨在为开源社区提供测试套件，用于验证 Linux 内核的可靠性、健壮性和稳定性。

* testcases 目录包含测试用例
* runtest 目录包含测试集，由多个测试用例组成
* scenario\_groups 目录包含测试场景集合，由多个测试集组成

### Download

```bash
$ git clone --recurse-submodules https://github.com/linux-test-project/ltp.git
```

### Compiling and installing all testcases

```bash
$ make autotools
$ ./configure
$ make
$ make install # install LTP inside /opt/ltp by default
```

### Running tests

```bash
$ cd /opt/ltp

# run mm testing suite
$ ./kirk --run-suite mm
or
$ ./runltp -f mm
```

通过 `kirk`/`runltp` 执行测试集 `mm`, 包含多个测试用例

测试集 `mm` 存储在 `runtest` 目录中

### build and run single tests

```bash
$ cd testcases/kernel/mem/foo
$ make
$ PATH=$PATH:$PWD ./foo01
```

编译 mem 目录下的所有测试用例，同时只执行 foo01 测试用例

## LKP-tests

## redis-benchmark

### 简介

redis-benchmark 是 redis 自带的性能测试工具，主要用于评估 redis 服务器的性能表现。

主要用途：

* 评估性能，测试 redis 在不同配置、负载或硬件下的吞吐量（QPS）和延迟。
* 发现瓶颈，协助发现系统可能的性能瓶颈。
* 对比验证，比较不同版本 redis、不同参数配置或不同环境下的性能差异。

下面对 redis-benchmark 输出结果进行详细解释

### 详细解释

```bash
====== MSET (10 keys) ======
  100000 requests completed in 0.88 seconds
  50 parallel clients
  3 bytes payload     :
  keep alive: 1
  host configuration "save": 3600 1 300 100 60 10000 # RDB 持久化配置
  host configuration "appendonly": no                # 未开启 AOF 持久化
  multi-thread: no                                   # 单线程模式
```

* 标题：Redis 执行 MSET ( 10 个 keys ) 操作的压力测试结果
* 总完成了 10 万次请求（即 10 万 \* 10 = 100 万个 key 的设置），总耗时 0.88 秒
* 使用了 50 个并发客户端来模拟压力
* 每个键值对的大小是 3 个字节（如 "abc"）
* 使用了 TCP 长连接，避免了频繁建立连接的开销

```bash
Latency by percentile distribution:
0.000% <= 0.095 milliseconds (cumulative count 1)
50.000% <= 0.223 milliseconds (cumulative count 86306)
87.500% <= 0.231 milliseconds (cumulative count 94049)
96.875% <= 0.303 milliseconds (cumulative count 98583)
99.219% <= 0.367 milliseconds (cumulative count 99250)
99.609% <= 0.375 milliseconds (cumulative count 99691)
99.805% <= 0.383 milliseconds (cumulative count 99805)
99.902% <= 0.447 milliseconds (cumulative count 99912)
99.951% <= 12.623 milliseconds (cumulative count 99952)
99.976% <= 12.911 milliseconds (cumulative count 99976)
99.988% <= 13.103 milliseconds (cumulative count 99988)
99.994% <= 13.175 milliseconds (cumulative count 99994)
99.997% <= 13.215 milliseconds (cumulative count 99997)
99.998% <= 13.247 milliseconds (cumulative count 99999)
99.999% <= 13.255 milliseconds (cumulative count 100000)
100.000% <= 13.255 milliseconds (cumulative count 100000)
```

延迟百分位分布：

* 一句话解释：百分之X的请求，延迟都低于Y毫秒
* 如何阅读：先关注左侧的百分比，再看右边对应的延迟值。

如：99.902% 的请求，延迟都低于 0.447 ms

```bash
Cumulative distribution of latencies:
0.002% <= 0.103 milliseconds (cumulative count 2)
0.391% <= 0.207 milliseconds (cumulative count 391)
98.583% <= 0.303 milliseconds (cumulative count 98583)
99.895% <= 0.407 milliseconds (cumulative count 99895)
99.945% <= 0.503 milliseconds (cumulative count 99945)
99.950% <= 0.607 milliseconds (cumulative count 99950)
99.988% <= 13.103 milliseconds (cumulative count 99988)
100.000% <= 14.103 milliseconds (cumulative count 100000)
```

延迟累积分布：

* 一句话解释：延迟低于Y毫秒的请求，占了百分之X
* 如何阅读：先关注右侧的延迟阈值，再看左边对应的百分比

如：延迟低于 0.607 ms 的的请求，占了 99.950%

```bash
Summary:
  throughput summary: 113507.38 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        0.229     0.088     0.223     0.263     0.335    13.255
```

吞吐量 (Throughput) 表示平均每秒处理 113,507 次 MSET 操作，由于每次 MSET 包含 10 个 KEY，所以相当于每秒处理了 1,135,070 次 key-val 设置。

延迟 (Latency) 表示从发送请求到收到响应所需的时间，如下：

* 平均延迟为 0.229 ms
* 最快请求为 0.088 ms
* 中位数延迟为 0.223 ms，即有一半的请求响应时间 小于等于 0.223 ms
* 95% 延迟 <= 0.263 ms
* 99% 延迟 <= 0.335 ms
* 最慢请求为 13.255 ms

### 什么是尾部延迟（Tail Latency）？

尾部延迟是指响应时间分布中 "尾部" 部分请求的延迟，即最慢的那一小部分请求的延迟表现。

* 头部：最快的请求（p0-p50）
* 身体：主要请求群（p50-p90）
* 尾部：最慢的请求（p90-p100）

尾部延迟通常指：

* p95: 0.303ms # 尾部延迟开始
* p99: 0.367ms # 典型尾部延迟
* max: 13.255ms # 最极端尾部延迟

尾部延迟不是某一个具体百分位，而是高百分位（p95、p99、max）延迟的整体现象。

### 什么是 BGSAVE ?

BGSAVE 是 redis 的一个核心命令，用于在后台（Background）异步地将当前 redis 实例的数据集保存到一个名为 `dump.rdb` 的磁盘文件中。这个过程也称为创建 RDB 快照。

BGSAVE 是 redis 实现数据持久化的一个非阻塞、后台异步命令，通过 fork 子进程来完成真正的持久化工作，而主进程继续处理客户端的请求，不会阻塞。

由于子进程由主进程 fork 而生，它拥有与主进程完全相同的内存数据副本。但是，这个 复制过程利用了操作系统的 `写时复制 COW` 机制。这意味着，开始时，子进程和主进程 共享相同的内存页。如果主进程接收到了新的写命令，需要修改某一块内存数据，操作系统 会先将这一块内存数据复制一份，然后再进行修改。这样，子进程所看到的内存数据就是 它被创建那一刻的快照，保持不变。

| 特性   | BGSAVE (BackGround SAVE) | SAVE             |
| ---- | ------------------------ | ---------------- |
| 执行方式 | 异步，fork 子进程处理            | 同步，主进程处理         |
| 是否阻塞 | 不阻塞主进程，客户端请求正常处理         | 阻塞主进程，客户端命令都无法处理 |
| 使用场景 | 生产环境                     | 调试，极端情况          |

Q: 如何判断 redis 使用 BGSAVE 机制？

```bash
$ redis-cli INFO persistence | grep bgsave_status
rdb_last_bgsave_status:ok
```

显示 `ok` 代表上一次保存 `dump.rdb` 是通过 BGSAVE 机制来完成的。

## STREAM

### 简介

STREAM 是内存带宽测试，通过模拟四种典型的内存操作模式，测试内存子系统在 连续数据流处理中的带宽性能（单位：MB/s）

* COPY ：纯内存复制 `a[i] = b[i]`，涉及两次访存（读+写）。
* SCALE ：内存复制+标量乘法 `a[i] = q * b[i]`，涉及两次访存和一次浮点乘法。
* ADD ：内存加法 `a[i] = b[i] + c[i]`，涉及三次访存和一次浮点加法。
* TRIAD ：混合运算 `a[i] = b[i] + q * c[i]`，涉及三次访存和两次浮点运算（加法+乘法）。

操作中访存次数越多，越能掩盖内存延迟，带宽越高。 浮点计算越多，完成时间越长，带宽越低。 测试结果反映可持续内存带宽（非理论峰值）。

### 下载编译

```bash
$ wget https://www.cs.virginia.edu/stream/FTP/Code/stream.c
$ gcc -O3 -march=native -fopenmp -DSTREAM_ARRAY_SIZE=10000000 -DNTIMES=10 stream.c -o stream
```

STREAM\_ARRAY\_SIZE ：数组大小，大于最后一级缓存总和的4倍（如：64MB L3 cache，设置值需要大于256MB） TIMES : 运行次数 -fopenmp ：启用多线程支持，通过 OMP\_NUM\_THREADS 设置线程数。

### 测试

```bash
## 单线程测试
$ export OMP_NUM_THREADS=1
$ ./stream

## 多线程测试，默认
$ export OMP_NUM_THREADS=8  ## 8 个线程
$ ./stream
Function    Best Rate MB/s  Avg time     Min time     Max time
Copy:           49232.5     0.003792     0.003250     0.006448
Scale:          46795.1     0.003872     0.003419     0.006406
Add:            50346.8     0.005193     0.004767     0.007915
Triad:          52888.8     0.004916     0.004538     0.006513
```

### 影响性能的关键因素

* 硬件配置：内存频率、通道数（双通道 vs 四通道）。
* 系统架构：CPU缓存效率、NUMA（非统一内存访问）优化。
* 软件优化：编译器选项、内存对齐（OFFSET参数）。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vernon2gb.gitbook.io/notes/linuxdebug/benchmark.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
