| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> GCC编译优化应用预编译头 -> 正文阅读 |
|
[游戏开发]GCC编译优化应用预编译头 |
服务器编译优化记录 对项目编译优化过程中一些思路和脚本工具实现。对内存受限的编译环境有一些帮助。 工具: https://github.com/wangxiaobai-dd/GccPrecompiledHeader 环境 32G内存,16核,Makefile,gcc9.2 效果 选择了代码比较多的三个目录进行预编译头优化,?进行下述操作。另外: 将小的编译单元合并成大的编译单元也是有效的,如 com.cpp 包含 a.cpp b.cpp , 在com.cpp 中首行也需要 #include "inc.h" ),编译时间从 24min30s左右 降到 14min 左右 ,节省 40%以上编译时间 方法 1. 梳理编译单元 编译时,我们每一个cpp文件将会生成对应的一个.o目标单元,将小的编译单元合并成大的编译单元对编译速度会有显著的提升(已有)。 类似上图,用n.cpp 包含 a.cpp,b.cpp,用m.cpp包含c.cpp,d.cpp,将 4 个编译单元变成 2 个编译单元。 注意,这里我认为应该将修改频率低的文件进行编译单元合并,如果将高修改频率的cpp文件放入合并后的编译单元,那么每次修改这个文件都会导致包含这个大编译单元重新编译。 另外,合并的编译单元尽可能地有一定关联度,可以按照业务功能来划分,或者通过一些数据统计来划分。 2. 应用gcc预编译头 按照图2,当a,cpp b.cpp c.cpp都包含temp.h头文件时,在编译的时候,temp.h会被解析三遍,分别与a,b,c结合生成.o文件。这样我们可以预先对头文件进行编译,生成temp.h.gch文件,这样只需要解析一次temp.h,原来的a.cpp,b.cpp,c.cpp文件仍然include temp.h就好了,只是要最先包含temp.h。 编译时 -H 可以看到cpp文件的依赖信息,应用gch后 !temp.h.gch 在应用gch时,我的方法是:
工具 从上面第二步开始 ,以我的仓库里的代码举例 ,GchTool/TestTool/dirA.bak 是预编译头优化前, dirA 是优化后 ,大家可以对比参考。 一些脚本说明:
使用: ?./CheckInclude TestTool/dirA ?, 生成 analyseInc.txt , 供 ReplaceGCH.sh 脚本使用: ?analyseInc2.txt ,方便我们自己查看头文件包含频率 :
使用:./ReplaceGCH.sh TestTool/dirA/ 3 ????取 analyseInc.txt ?前 3 头文件,对 dirA 路径下,将这些头文件从 cpp 文件中删除,新建文件 inc.h 用于包含这些头文件,并且将 #include "inc.h" 插入刚才修改的 cpp 文件的首行 要处理的头文件数量,根据我们的实际项目规模来确定,这里举例是 3 向受到影响的 cpp 文件 插入 inc.h ,会调用?InsertInc 脚本: 自动创建 inc.h :
修改 dirA/Makefile 依赖,保证每次编译先对 inc.h 进行编译 生成 inc.h.gch 修改 项目Makefile,支持多核编译(目录间多核,比如 dirA 对 inc.h 编译生成 inc.h.gch 时,其他目录仍然在编译): 这里 targetA 是公共库目录 ,targetB、targetC 都要依赖 targetA,如 targetA 生成的静态库 对 inc.h 包含的头文件递归检查,刷新 inc.h 的时间戳,促使生成新的 inc.h.gch (比如inc.h 包含 common.h ,我们对 common.h 修改,gcc 并不认为 inc.h 有改动,因此我编写了脚本 gchcheck.py?做编译前检查): 过程输出 进行编译优化后,发现在多核编译中, 目录A产生编译错误时,目录B不会停下来编译,会将错误信息刷屏,我们需要花很多时间向上滚屏翻记录,十分不友好;另外冗余的编译信息(如编译参数 链接参数 都可以在 Makefile 中查看)对我们用处不大。 于是编写脚本,在编译时收集编译信息,友好的展示出来:?compliedisplay.py 代码与使用示例: 旧的编译信息输出: 修改后: 使用方法:
红框:调用脚本,我放在了targetA中调用,后台会fork子进程 绿框:ENTRY = ‘$@file’、DIR=$(DIRB)、 ?2>>$@error ?将信息传给编译的子目录,编译信息会写入文件 targetAfile,错误信息写入文件 targetAerror , ?对于targetB 则是 targetBfile ?targetBerror 黄框:表示 target 编译结束
红框:开始编译文件 绿框:开始链接 注意在这些命令前加上@, 在 $(CXX) xxxx 前也加上,这样就不会打印这条执行语句了。 小结 现在3.16的cmake,可以对预编译头友好支持,无需手动处理预编译头文件中的依赖关系(target_precompile_headers);也可以使用clang替换gcc;在内存足够、核心足够的机器上,预编译头可能是一种负担(如何筛选预编译的文件,标准库头文件)。 关于预编译机制: 第一次编译并保存这个预编译头状态比编译这些代码慢(时间代价20%-200%); 重新加载已保存的状态很快; 足够内存的系统,预编译头文件机制速度比编译单个标准头文件快很多; 根据头文件使用频率和稳定性分层(结论一致); 优化: 二级预编译头机制
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/16 18:58:58- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |