龙芯开源社区

 找回密码
 注册新用户(newuser)
查看: 3239|回复: 15

[更新]优化龙芯处理器的ULR访问性能

[复制链接]
发表于 2016-1-8 17:41:41 | 显示全部楼层 |阅读模式
本帖最后由 heiher 于 2016-3-24 08:54 编辑

2016-03-24 方案由内核自动 patch,无需手动 patch elf,更方便使用,详见下方“2016-03-24 更新方案”
2016-01-08 方案无需破坏性能计数器的功能,而且具有更高的访问性能,详见下方“2016-01-08更新方案”。


User Local Register 是一个被C库函数及线程库高频访问的一个寄存器,可惜龙芯3A2000之前版本的CPU都没有实现,包含龙芯2E/2F/3A1000/3B1000等等。在没有硬件没有实现的CPU上,执行 rdhwr $29 指令会触发保留指令异常,由软件模拟实现,所以性能也大打折扣。

龙芯的开发者 Huang pei 提出了一种解决办法,通用复用龙芯性能计数器1的 Count 寄存器作 ULR,能够避免因软件模拟带来的额外开销。由于这个优化方案是以损失性能计数器的功能来换取的,只建议开发者尝试。要启用这个优化方案大概需要两个步骤:
1. 更换内核,要给内核打上一个补丁(见附件),并关闭内核配置 PREF_EVENTS 及 OPROFILE。
2. 更新系统中的应用程序,用 dmfc0 $25, 3 替换 rdhwr $29 来访问 ULR。

虽然 ULR 主要在C库及线程库中被访问,但 GCC 存在 inline 的访问 ULR 的功能,所有不能确定其它程序及库是否使用,因此重新编译应用程序的代价较大。为此,我制作了一个 patchelf 的程序直接在二进制程序上打补丁来替换访问 ULR 的实现。

性能测试结果:
1. 直接测试
  1. for (i=0; i<10000000; i++) {
  2.     asm volatile (
  3.         "rdhwr $0, $29 \n"
  4.         "rdhwr $0, $29 \n"
  5.         "rdhwr $0, $29 \n"
  6.         "rdhwr $0, $29 \n"
  7.     );
  8. }
复制代码


通过标准的 rdhwr $29 来访问 ULR,在3A1000上的4千万次时间开销约为 25 秒。

  1. for (i=0; i<10000000; i++) {
  2.     asm volatile (
  3.         "dmfc0 $0, $25, 3 \n"
  4.         "dmfc0 $0, $25, 3 \n"
  5.         "dmfc0 $0, $25, 3 \n"
  6.         "dmfc0 $0, $25, 3 \n"
  7.     );
  8. }
复制代码


通过复用的 Count 来访问 ULR,在3A1000上4千万次时间开销约为 0.717 秒。

2. C库函数 isupper 测试
  1. for (i=0; i<100000000; i++) {
  2.     r |= isupper ('a');
  3.     r |= isupper ('a');
  4.     r |= isupper ('a');
  5.     r |= isupper ('a');
  6. }
复制代码


通过标准的 rdhwr $29 来访问 ULR,在3A1000上时间开销为 1分17秒,而通过复用的 Count 下降到 27 秒。

2016-03-24 更新方案
由内核在处理 rdhwr $29 异常时自动对程序打补丁,无需用户手动执行 patchelf,方便应用。感谢 putty 的建议。
下载:
1. 内核补丁1:http://mirror.lemote.com/archls/testing/linux-4.1-ls-tls.patch
2. 内核补丁2:http://mirror.lemote.com/archls/testing/linux-4.1-ls-patch-tls.patch

详细步骤:
1. 内核打上补丁并换新内核启动系统。
4. 重启系统。

旧方案转 2016-03-24 新方案
如已经采用了旧方案的情况下切换新方案,请务必先执行以下步骤,再执行上述的“详细步骤”。
1. 下载旧方案的 patchelf 源代码并编译:http://mirror.lemote.com/archls/testing/patchelf-old.c
3. 执行上述“详细步骤”。

2016-01-08 方案转 2016-03-24 新方案
无需额外处理。

2016-01-08 更新方案
新方案通过复用龙芯CAM的 index 0 行作 ulr,内核态通过 camwi 指令将 tls 地址写入 CAM index 0 行的 ram 域,用户态通过 ramri 指令读取 tls 地址。在龙芯3 CPU 上 ramri 指令相对 dmfc0 指令具有更高的性能。

  1. for (i=0; i<10000000; i++) {
  2.         asm volatile (
  3.           "ramri $0, $0 \n"
  4.                  "ramri $0, $0 \n"
  5.           "ramri $0, $0 \n"
  6.                  "ramri $0, $0 \n"
  7.         );
  8. }
复制代码

通过复用的 cam index 0 来访问 “ULR”,在3A1000上4千万次时间开销仅约为 0.338 秒。

下载:
1. 内核补丁:http://mirror.lemote.com/archls/testing/linux-4.1-ls-tls.patch
2. patchelf.c: http://mirror.lemote.com/archls/testing/patchelf.c

详细步骤:
1. 内核打上补丁并换新内核启动系统。
2. 编译 patchelf.c, gcc -o /tmp/patchelf patchelf.c
3. hack 二进制, sudo find /usr -type f -exec /tmp/patchelf {} \;
4. 重启系统。

旧方案转 2016-01-08 新方案
如已经采用了旧方案的情况下切换新方案,请务必先执行以下步骤,再执行上述的“详细步骤”。
1. 下载旧方案的 patchelf 源代码并编译:http://mirror.lemote.com/archls/testing/patchelf-old.c
2. 使用旧方案的 patchelf 程序将所有程序 revert 回原来的实现,sudo find /usr -type f -exec /tmp/patchelf.old {} \;
3. 执行上述“详细步骤”。
发表于 2016-1-10 20:19:48 | 显示全部楼层
厉害阿!!!老大最新力作!!!
发表于 2016-1-11 03:31:30 | 显示全部楼层
赞!我有一个想法,如果可以用count寄存器来模拟UserLocal,那么用context寄存器如何?因为龙芯总是在64位下运行的,那么context寄存器其实完全没有被用到。UserLocal只有32位,所以用context的高32位就好。这样就不用牺牲计数器的功能,在编译时加flag总是越少越好。如果真的运行在32位下,那就用XContext寄存器好啦,

你觉得这种想法是合理的吗?
发表于 2016-1-11 03:52:09 | 显示全部楼层
还有一个问题。用户程序是不能用dmfc0的,但是ULR特别地被处理成用户可以通过rdhwr访问。这个问题怎么处理啊?
 楼主| 发表于 2016-1-11 08:34:02 | 显示全部楼层
opensrc 发表于 2016-1-11 03:52
还有一个问题。用户程序是不能用dmfc0的,但是ULR特别地被处理成用户可以通过rdhwr访问。这个问题怎么处理 ...

感谢你的建议,有两点需要注意:1. 不是 cp0 的任意寄存器都可以在用户态访问的(你的第二从问题正好回答了第一个问题),而 pmu 的 count 寄存器被设计成用户态可以访问。2. ulr 的宽度与 abi 相关,n64 abi 则需要 64 位。
 楼主| 发表于 2016-1-11 08:35:20 | 显示全部楼层
powervr 发表于 2016-1-10 20:19
厉害阿!!!老大最新力作!!!

谢谢,我并不是原创,只是想推荐这个方法。
发表于 2016-1-11 08:45:06 | 显示全部楼层
heiher 发表于 2016-1-11 08:34
感谢你的建议,有两点需要注意:1. 不是 cp0 的任意寄存器都可以在用户态访问的(你的第二从问题正好回答 ...

明白了,所以用context寄存器是不可行的。谢谢!
发表于 2016-1-11 08:47:40 | 显示全部楼层
再一个问题。想完全确认一下,3B1500上也是没有 UserLocal 寄存器。这对吗?
发表于 2016-1-11 09:07:03 | 显示全部楼层
opensrc 发表于 2016-1-11 08:47
再一个问题。想完全确认一下,3B1500上也是没有 UserLocal 寄存器。这对吗?

目前只有3A2000有userlocal。
 楼主| 发表于 2016-2-16 20:08:05 | 显示全部楼层
Jamienstar 发表于 2016-2-16 09:31
请问这里的内核补丁只有针对4.1的吗,没有3.10内核的?

暂时没有,但有可能可以打上或只需简单修改。

本版积分规则

Archiver|手机版|小黑屋|Lemote Inc.

GMT+8, 2021-1-28 07:45 , Processed in 0.166707 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表