Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

内置 ccache 的一些表现上的问题 #2425

Closed
OuYangPaste opened this issue Jun 2, 2022 · 15 comments
Closed

内置 ccache 的一些表现上的问题 #2425

OuYangPaste opened this issue Jun 2, 2022 · 15 comments
Labels

Comments

@OuYangPaste
Copy link

OuYangPaste commented Jun 2, 2022

Xmake 版本

v2.6.7+dev.73eab3a

操作系统版本和架构

Linux paste 5.15.24-amd64-desktop #2 SMP Wed Mar 9 09:40:26 CST 2022 x86_64 GNU/Linux

描述问题

目前内置 ccache 测下来有两个不足的地方:

  1. 当 gcc -D 新增了一个宏,而这个宏并没有在文件中被使用,会导致 cache miss (因为很多时候在 xmake.lua 中是通过判断 option 从而选择性 add_defines,切换到新 option 的时候会导致批量 cache miss, 而实际上这个宏可能只在部分源文件中被使用)
  2. 当源文件 里使用了 __DATE__ __TIME__ 等宏时,xmake -rvD 会一直看到 cache hit, 这种情况下应该 cache miss 才对,我看到 xmake 最近的提交中也有对 __DATE__ __TIME__ 的相关处理,不过似乎只是对外部 add_defines 输入时才会关闭掉 directives_only

我也对比过 ccache 命令的结果,ccache 能对上面两种情况进行处理

期待的结果

期望内置 ccache 能对上面描述的情况进行处理

我在 $(programdir)/modules/core/tools/gcc.lua 里对需要被签名的 flags 对 -D 的输入进行了过滤
1654151440(1)
同时 去除了 directives_only 标志,几番测试下来似乎符合我的预期,不太明白为什么使用 directives_only,是为了加速预编译么?

工程配置

No response

附加信息和错误日志

No response

@OuYangPaste OuYangPaste added the bug label Jun 2, 2022
@waruqi
Copy link
Member

waruqi commented Jun 2, 2022

当 gcc -D 新增了一个宏,而这个宏并没有在文件中被使用,会导致 cache miss (因为很多时候在 xmake.lua 中是通过判断 option 从而选择性 add_defines,切换到新 option 的时候会导致批量 cache miss, 而实际上这个宏可能只在部分源文件中被使用)

这是由于目前 cachekey 包含了所有 flags 的计算,是否需要从中移除 -D 还有待评估,你可以翻下 ccache/fastbuild 看看,他们有没有忽略 -D,我这两天暂时没空细看。

当源文件 里使用了 DATE TIME 等宏时,xmake -rvD 会一直看到 cache hit, 这种情况下应该 cache miss 才对,我看到 xmake 最近的提交中也有对 DATE TIME 的相关处理,不过似乎只是对外部 add_defines 输入时才会关闭掉 directives_only

这个问题我知道,只是还没想到好的办法改进,所以先放着了,yadcc 里面是通过 memmem 去源文件中 找 DATE 来判断的,但是每个源文件都去读取找一遍,感觉太损耗性能,要么全禁用 directives_only,但这也会影响部分性能。

关于这个,主要参考了 yadcc 的优化,具体可以看下:
https://github.com/Tencent/yadcc/blob/master/yadcc/doc/rationale.md
https://github.com/Tencent/yadcc/blob/master/yadcc/doc/client.md

据说某些case可以减少 75% 的预处理时间。

@OuYangPaste
Copy link
Author

这是由于目前 cachekey 包含了所有 flags 的计算,是否需要从中移除 -D 还有待评估,你可以翻下 ccache/fastbuild 看看,他们有没有忽略 -D,我这两天暂时没空细看。

这个除了 flags 的 -D 影响之外,加了 directives_only 标志后预处理的 .c.c 文件里面也不会消除掉没有被使用掉的宏,也会造成 cache miss, 这个如果采取二次处理,相比不加 directives_only 不知道性能相差几何

关于这个,主要参考了 yadcc 的优化,具体可以看下: https://github.com/Tencent/yadcc/blob/master/yadcc/doc/rationale.md https://github.com/Tencent/yadcc/blob/master/yadcc/doc/client.md

据说某些case可以减少 75% 的预处理时间。

👌 我去了解下看看有没有什么好的思路

@waruqi
Copy link
Member

waruqi commented Jun 14, 2022

我加了个 set_policy("preprocessor.gcc.directives_only", false) 可以配置禁用 -fdirectives-only ,大部分情况下,默认开启这个都没啥事,毕竟用到 __DATE__ 的还是少数,如果有影响,可以禁用这个。

@OuYangPaste
Copy link
Author

OuYangPaste commented Jun 18, 2022

我加了个 set_policy("preprocessor.gcc.directives_only", false) 可以配置禁用 -fdirectives-only ,大部分情况下,默认开启这个都没啥事,毕竟用到 __DATE__ 的还是少数,如果有影响,可以禁用这个。
👌

之前我看了下 ccache, -D 确实只参与预编译,不参与生成 cachekey(毕竟预编译后,无论加不加 directives_only,-D 宏定义的信息就已经平铺在里面了)
对于 __DATE__ 等检测是通过自行扫描文件进行 memcmp 匹配的方式进行筛选...

@waruqi
Copy link
Member

waruqi commented Jun 18, 2022

之前我看了下 ccache, -D 确实只参与预编译,不参与生成 cachekey(毕竟预编译后,无论加不加 directives_only,-D 宏定义的信息就已经平铺在里面了)

这个可以尝试改进下 cachekey

对于 DATE 等检测是通过自行扫描文件进行 memcmp 匹配的方式进行筛选...

这个我觉得不是很划算,一个项目用了 DATE 的概率原本就不高,却要对每个源文件不停地去扫 mem ,太影响效率,还不如根据自身项目特性,按需禁用:set_policy("preprocessor.gcc.directives_only", false)

@waruqi
Copy link
Member

waruqi commented Jun 18, 2022

之前我看了下 ccache, -D 确实只参与预编译,不参与生成 cachekey(毕竟预编译后,无论加不加 directives_only,-D 宏定义的信息就已经平铺在里面了)

不对,刚看了下,如果开了 directives_only ,就不能忽略 -D 。。因为生成的预处理文件里面,相关宏是没被展开的。。

比如 TEST 宏,预编译文件还是这样。。

    cout << TEST << endl;

如果忽略 -D 来缓存,不管你 -DTEST=1 还是后面改成了 -DTEST=2,参与链接的 obj 永远是首次缓存的那个 obj 。。结果是不对的,我刚验证过了。。

只有在禁用 directives_only 的情况下,才能忽略 -D

@waruqi
Copy link
Member

waruqi commented Jun 18, 2022

-Dxx 的 cachekey 问题我改进过了,如果没启用 directives_only,所有宏都会在预处理阶段被展开,cachekey 里面我会去忽略它,但如果开了 directives_only,我就会保留所有 -D 到 cachekey。

@OuYangPaste
Copy link
Author

不对,刚看了下,如果开了 directives_only ,就不能忽略 -D 。。因为生成的预处理文件里面,相关宏是没被展开的。。

啊这...我之前测试过好像是会展开成 #define 在 .c.c 里面的,emmm 可能跟什么东西搞混了,我有空再验一下看看

@OuYangPaste
Copy link
Author

OuYangPaste commented Jun 18, 2022

-Dxx 的 cachekey 问题我改进过了,如果没启用 directives_only,所有宏都会在预处理阶段被展开,cachekey 里面我会去忽略它,但如果开了 directives_only,我就会保留所有 -D 到 cachekey。

👍 那我可以配合 xmakerc.lua 去复用编译文件了,因为我这边的项目都是那种规模不大,但是要随时切 config 重新编译的那种,由于资源限制和一些特殊的客户定制需求,现在都膨胀到两三百个 config 配置了,批量构建的时候就一次性切两三百次 config😂所以我这种环境下减少-D带来的影响从而拉高点命中率会比较重要

那么这个 issue 我先关闭了

@OuYangPaste
Copy link
Author

如果忽略 -D 来缓存,不管你 -DTEST=1 还是后面改成了 -DTEST=2,参与链接的 obj 永远是首次缓存的那个 obj 。。结果是不对的,我刚验证过了。。

只有在禁用 directives_only 的情况下,才能忽略 -D

奇怪了,我这边验,就算带上 directives_only,外部传入的 -D 会平铺进去

gcc -o test.i -fdirectives-only -E test.c -Dtest1=1 -Dtest2=2
cat test.i | grep test
# 1 "test.c"
#define test1 1
#define test2 2
   test macros that may be defined in a source file before it first
...

gcc (Uos 8.3.0.3-3+rebuild) 8.3.0

@waruqi
Copy link
Member

waruqi commented Jun 20, 2022

$ gcc -o test.i -fdirectives-only -E src/main.cpp -DTEST=1
$ cat ./test.i | grep TEST
#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1
#define TEST 1
    cout << TEST << endl;

确实,之前漏看了上面的 #define 定义,如果是这样的话,那这个 -fdirectives-only 感觉也没啥什么用么。。

@OuYangPaste
Copy link
Author

😂

@waruqi
Copy link
Member

waruqi commented Jun 20, 2022

我改进过了,去掉了 -fdirectives-only 的cacheky里面判断,不过我看只有用户定义的 -Dxxx 才会被展开,而 DATE 这种,-fdirectives-only 时候,还是不会被展开

@OuYangPaste
Copy link
Author

👌

@waruqi
Copy link
Member

waruqi commented Jul 27, 2022

看来 -fdirectives-only 还是会有不少问题,不行回头只能先默认禁用了,按需自己开启。

#2603

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants