ztxz16 / fastllm

纯c++的全平台llm加速库,支持python调用,chatglm-6B级模型单卡可达10000+token / s,支持glm, llama, moss基座,手机端流畅运行
Apache License 2.0
3.28k stars 332 forks source link

CPIU下推理速度并未随着线程数增加而提高 #178

Open TylunasLi opened 1 year ago

TylunasLi commented 1 year ago

测试环境: 华为Atlas 800 (9000) 服务器 CPU:HiSilicon Kunpeng 920 5250 48 cores 2.60GHz * 4 MEM:768GiB DDR4 OS:OpenEuler 22.03 LTS 编译环境 gcc 10.3.1 cmake 3.22.6 python 3.8.5

测试方法:

     /benchmark -p chatglm2-6b-int4.flm -t {Threads} --file ../example/benchmark/prompts/beijing.txt --batch 1
测试结果 线程数 精度 Batch size 速度 (Tokens/s)
24 fp16 1 3.120885
32 fp16 1 3.911469
48 fp16 1 4.306985
64 fp16 1 4.509292
128 fp16 1 3.803949
192 fp16 1 3.206572
256 fp16 1 2.557222
24 int4 1 6.410621
32 int4 1 6.803374
48 int4 1 7.449977
64 int4 1 6.734349
128 int4 1 4.962776

推理时指令集情况:

AVX: OFF
AVX2: OFF
AARCH64: ON
Neon FP16: ON
Neon DOT: ON

有幸使用鲲鹏CPU做了测试,但是很可惜,没有发挥出服务器多核CPU的实力,速度比报道中的骁龙865快不了多少。 在fp16下超过64核,int4下超过48核,推理速度随着和数的增加反而明显下降了, 另外,还观察到测试中CPU最高也只占用到60%左右,和openblas动辄全占满不同。 是否还有进一步的优化空间?(如支持OpenMP)

ztxz16 commented 1 year ago

我没有在鲲鹏上测试过,不过这个数据看起来确实比较低 (比如我在AMD 5975WX上测试16核可以达到30 token / s) 猜测是否有numa节点?如果有多numa节点,可能因为传输数据跨numa导致速度变慢,可以考虑用numactl绑定numa节点

TylunasLi commented 1 year ago

我没有在鲲鹏上测试过,不过这个数据看起来确实比较低 (比如我在AMD 5975WX上测试16核可以达到30 token / s) 猜测是否有numa节点?如果有多numa节点,可能因为传输数据跨numa导致速度变慢,可以考虑用numactl绑定numa节点

NUMA我试下,4颗CPU共有8个NUMA节点。 另外在Xeon Gold 6133 2(20核40线程2)上测得的结果类似,推理速度很低。

ztxz16 commented 1 year ago

嗯嗯,目前对多numa节点的支持较差,建议的方式是绑节点运行 (mem和cpu都要绑,类似 "numactl -C 0-19 -m 0" 这样)

TylunasLi commented 1 year ago
[root@huawei build]# numactl -H
available: 8 nodes (0-7)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
node 0 size: 96143 MB
node 1 cpus: 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
node 1 size: 96764 MB
node 2 cpus: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
node 2 size: 96764 MB
node 3 cpus: 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
node 3 size: 96764 MB
node 4 cpus: 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
node 4 size: 96764 MB
node 5 cpus: 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
node 5 size: 96764 MB
node 6 cpus: 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
node 6 size: 96727 MB
node 7 cpus: 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
node 7 size: 95729 MB
node distances:
node   0   1   2   3   4   5   6   7
  0:  10  11  24  25  24  25  24  25
  1:  11  10  25  32  25  32  25  32
  2:  24  25  10  11  24  25  24  25
  3:  25  32  11  10  25  32  25  32
  4:  24  25  24  25  10  11  24  25
  5:  25  32  25  32  11  10  25  32
  6:  24  25  24  25  24  25  10  11
  7:  25  32  25  32  25  32  11  10

绑定了同一个NUMA节点(24 cores, 96GiB),做了上述测试。

线程数 精度 Batch size 速度 (Tokens/s)
8 int4 1 4.580865
16 int4 1 6.609561
24 int4 1 5.965994
32 int4 1 6.676292
48 int4 1 6.684945
64 int4 1 6.829765
128 int4 1 6.542284
192 int4 1 5.952961

性能依然不高,也是在64线程左右性能相对最好。

补充一下不绑NUMA节点的数据: 线程数 精度 Batch size 速度 (Tokens/s)
8 int4 1 3.357206
16 int4 1 5.528090

另外,我还测试了64线程下跨NUMA的性能,同一CPU不同节点和不同CPU分别为 6.272048 Tokens/s 和 4.990523 Tokens/s

几点猜测:

  1. 跨NUMA节点会出现性能较低的情况,但不是决定性因素;
  2. 在8、16线程时由于线程数量不足,会产生过多任务,分配导致了跨NUMA节点计算,影响性能;
  3. 与昨天发的数据对比: a. 默认情况下在一定的线程数量范围内操作系统会尽量调度不跨NUMA节点的核来完成任务,24-64线程场景均如此; b. 不绑NUMA节点的情况下,超过64线程之后操作系统也会把任务分配到不同NUMA节点上。
  4. chatglm2-6b的矩阵乘法可能在按照64线程分解时能最大利用NEON指令集的效率?
ztxz16 commented 1 year ago

我手头没有鲲鹏,不过有一台别的A76服务器,我这边测试数据大概是这样

线程数 | 精度 | Batch size | 速度 (Tokens/s) -- | -- | -- | -- 1 | int4 | 1 | 1.431474 2 | int4 | 1 | 2.798379 3 | int4 | 1 | 5.318446 8 | int4 | 1 | 9.521655 16 | int4 | 1 | 13.723979

基本上8核以下是比较线性的,16核再往上就没什么提升了 原因是这个模型是IO bound的,速度受到DDR带宽限制 我这边CPU跟你应该是一样的,可以看到16核的时候基本就是2倍差距,这个看起来应该是因为DDR通道是2倍

不过确实,无论单核还是多核,ARM A76和AMD 5975WX差距还是相当大,个人感觉还是仿存机制有差异,我后面也再调调看 image

bigmover commented 1 year ago

我手头没有鲲鹏,不过有一台别的A76服务器,我这边测试数据大概是这样

线程数 精度 Batch size 速度 (Tokens/s) 1 int4 1 1.431474 2 int4 1 2.798379 3 int4 1 5.318446 8 int4 1 9.521655 16 int4 1 13.723979 基本上8核以下是比较线性的,16核再往上就没什么提升了 原因是这个模型是IO bound的,速度受到DDR带宽限制 我这边CPU跟你应该是一样的,可以看到16核的时候基本就是2倍差距,这个看起来应该是因为DDR通道是2倍

不过确实,无论单核还是多核,ARM A76和AMD 5975WX差距还是相当大,个人感觉还是仿存机制有差异,我后面也再调调看 image 我通过llm 读取模型codegeex2然后去在A10上跑只有43.15tokens/s image 想着codegeex2 转flm。但是 会报Bfloat16类型错误。 image benchmark 测试原始模型也会报FastLLM Error: FileBuffer.ReadInt error image 没太看懂这个报错 请问能执教一下哪里有问题吗?