GCC编译优化应用预编译头

2023-11-17

服务器编译优化记录

对项目编译优化过程中一些思路和脚本工具实现。对内存受限的编译环境有一些帮助。

工具:

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时,我的方法是:

  1. 先使用了include-what-you-use 这个开源工具,去除重复包含的头文件,前置声明替换(也是一种优化)
  2. 分析路径下头文件的包含频率
  3. 筛选包含频率高但是改动频率小头文件,放在新的inc.h文件中
  4. 剔除cpp文件包含的上一步的头文件,并在cpp中首行插入#include "inc.h"
  5. 修改Makefile,修改依赖关系,编译时先对inc.h进行编译,生成最新的inc.h.gch
  6. Makefile 可以加入 -Winvalid-pch,inc.h.gch 不可用时编译报错

工具

从上面第二步开始 ,以我的仓库里的代码举例 ,GchTool/TestTool/dirA.bak 是预编译头优化前, dirA 是优化后 ,大家可以对比参考。

一些脚本说明

  • 分析路径下头文件包含频率: CheckInclude.cpp  

使用:  ./CheckInclude TestTool/dirA  ,

生成 analyseInc.txt , 供 ReplaceGCH.sh 脚本使用:

 analyseInc2.txt ,方便我们自己查看头文件包含频率 :

  • 可以根据 git 或者 svn 提交记录,手动从 analyseInc.txt 剔除改动频率大的头文件,(头文件包含应是递归包含的,当时没有考虑到嵌套问题)

  • 使用预编译头替换脚本 ReplaceGch.sh  

使用:./ReplaceGCH.sh TestTool/dirA/ 3     取 analyseInc.txt  前 3 头文件,对 dirA 路径下,将这些头文件从 cpp 文件中删除,新建文件 inc.h 用于包含这些头文件,并且将 #include "inc.h" 插入刚才修改的 cpp 文件的首行

要处理的头文件数量,根据我们的实际项目规模来确定,这里举例是 3

向受到影响的 cpp 文件 插入 inc.h ,会调用 InsertInc 脚本:

自动创建 inc.h :

  • 修改 Makefile

修改 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

代码与使用示例

旧的编译信息输出:

MHpEswWYvxXLhOBP.png!thumbnail

修改后:

使用方法:

  • 修改项目 Makefile

红框:调用脚本,我放在了targetA中调用,后台会fork子进程

绿框:ENTRY = ‘$@file’、DIR=$(DIRB)、  2>>$@error  将信息传给编译的子目录,编译信息会写入文件 targetAfile,错误信息写入文件 targetAerror ,  对于targetB 则是 targetBfile  targetBerror

黄框:表示 target 编译结束

  • 修改子目录下 Makefile ,举例 dirA/Makefile

红框:开始编译文件

绿框:开始链接

注意在这些命令前加上@, 在 $(CXX) xxxx 前也加上,这样就不会打印这条执行语句了。

小结

现在3.16的cmake,可以对预编译头友好支持,无需手动处理预编译头文件中的依赖关系(target_precompile_headers);也可以使用clang替换gcc;在内存足够、核心足够的机器上,预编译头可能是一种负担(如何筛选预编译的文件,标准库头文件)。

关于预编译机制:

第一次编译并保存这个预编译头状态比编译这些代码慢(时间代价20%-200%);

重新加载已保存的状态很快;

足够内存的系统,预编译头文件机制速度比编译单个标准头文件快很多;

根据头文件使用频率和稳定性分层(结论一致);

优化:(不行)

Plain Text

incA.h :  // 变动频率最低,几乎不变的标准库

#include <iostream>

#include <string>

#include <vector>

incB.h :  // 变动频率次低, 偶尔变化的头文件

#include <incA.h>  // 比如包含<iostream> <string> <vector> ,先生成 gchA 预编译头

#include <zCore.h> // 编译器从这里 先加载 gchA, 开始编译 incB.h 生产 gchB 预编译头

#include <zBase.h>

main.cpp :

#include <incB.h>  // 包含incB, 会导入 gchB

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC编译优化应用预编译头 的相关文章

随机推荐

  • 单片机通信数据延迟问题排查

    1 问题说明 笔者在最近的项目中 发现系统的响应延迟较高 经过排查 排除了单片机运行卡死的问题 2 原因分析 具体排查过程这里就不细致说明了 直接给出排查后原因 任务执行周期规划不合理 导致freertos队列发送接收到的命令有延迟 为了便
  • sublime 代码提示插件

    Sublime Text 2是个相当棒的编辑器 这一点异次元和Lucifr的文章都介绍的很充分了 用了一段时间觉得Sublime确实 性感 而 强大 只是Sublime Text 2毕竟是一款 编辑器 而非 集成开发环境 IDE 在很多ID
  • Vue3.0组件—banner轮播图(渐入渐隐效果)

    Vue3 0组件 banner轮播图 渐入渐隐效果 组件产生 最近遇到一个需求 项目首页banner轮播 开始是直接使用element3 0的el carousel走马灯效果 但是产品觉得切换太快 给用户的体验效果不好 经过多次修改产品给出
  • 【网络编程】应用层协议——HTTP协议

    文章目录 一 HTTP协议基本认识 二 URL的认识 2 1 urlencode和urldecode 三 HTTP协议格式 3 1 HTTP请求与响应格式 3 2 如何保证请求和响应被应用层完整读取 3 3 请求和响应如何做到序列化和反序列
  • 查看用户表空间

    权限大的能查询权限小的内容 dba tablespaces 系统级别的管理员查看的数据字典 dba users 系统级别的管理员查看的数据字典 user tablespaces 普通用户以及系统级别管理查看的数据字典 user users
  • 数学:凸包算法详解

    一 概念 凸包 Convex Hull 是一个计算几何 图形学 中的概念 在一个实数向量空间V中 对于给定集合X 所有包含X的凸集的交集S被称为X的凸包 X的凸包可以用X内所有点 X1 Xn 的线性组合来构造 在二维欧几里得空间中 凸包可想
  • 海思芯片(hi3516dv300)uboot镜像生成过程详解

    1 前言 1 本文介绍的uboot编译过程是基于海思提供SDK包里的uboot源码进行编译 具体的编译参数是根据hi3516dv300芯片来设置的 编译生成的uboot烧录镜像也是用于hi3516dv300芯片的uboot镜像 2 对于Ma
  • 4.1 独立键盘检测

    题目 用数码管的前两位显示一个十进制的数 00 59变化 开始显示00 每按下S2键一次 数值加1 每按下S3键一次 数值减1 每按下S4键一次数值归零 按下S5键一次 利用定时器功能使数值开始自动每秒加1 再按下S5键 数值停止自动加1
  • Sqlite研究系列-1

    文章目录 简介 架构 简介 sqlite是一个开源的嵌入式关系型数据库 与常规数据库不同的地方是 零配置 没有账号概念 客户端和服务端运行在应用程序的进程空间 不需要网络配置 sqlite可以编译到应用程序中 依赖于文件系统 占用资源少 支
  • mpu6050数据实时发布到mqtt服务器

    vcc 5V SDA i2c数据 pin3 SDL i2c时钟 pin5 GND import smbus import SMBus module of I2C import time import math import json imp
  • 顺序表插入元素

    顺序表在插入元素时应注意 1 插入元素不可以插在最后一个位置 2 插入元素不可以插在超过顺序表的长度 代码实现 include
  • iOS下XMPP开发之XMPP开发环境配置(二)mac上搭建openfire服务器

    一 下载并安装openfire 1 到http www igniterealtime org downloads index jsp下载最新openfire for mac版 比如 Openfire 3 8 1 下载后的文件 openfir
  • XSS跨站脚本攻击(一)----XSS攻击的三种类型

    一 简介 什么是XSS 百度百科的解释 XSS又叫CSS Cross Site Script 跨站脚本攻击 它指的是恶意攻击者往Web页面里插入恶意html代码 当用户浏览该页之时 嵌入其中Web里面的html代码会被执行 从而达到恶意用户
  • gitlab项目代码仓库管理指南(自用)

    gitlab项目管理流程 注意事项 任何项目开始即创建对应项目仓库 issues应覆盖项目从原始需求 gt 项目结题过程中各环节 记录问题 解决思路等 及时整理 及时归档 流程图 git常用命令图 创建项目团队 注意事项 正式项目应所属团队
  • 相似性度量总结

    整理自 机器学习中的相似性度量 余弦距离 欧氏距离和杰卡德相似性度量的对比分析 在做分类时常常需要估算不同样本之间的相似性度量 Similarity Measurement 这时通常采用的方法就是计算样本间的 距离 Distance 采用什
  • VS2017突然不检查语法错误

    VS2017用着用着不检查语法错误 生成只说失败 错误列表显示0 只需要退出软件 到工程目录中删除 vs文件夹 重启软件即可 VS2019也是一样的
  • 关于https://goproxy.cn,direct与https://proxy.golang.org的问题,国内无法访问https://proxy.golang.org设置了GOPROXY仍不可行

    关于https goproxy cn direct与https proxy golang org的问题 国内无法访问https proxy golang org设置了GOPROXY仍不可行 一步一步说 首先 遇到报错信息 go github
  • NLP基础知识点:BLEU(及Python代码实现)

    Bleu 1 是IBM在2002提出的 用于机器翻译任务的评价 BLEU还有许多变种 根据n gram可以划分成多种评价指标 常见的指标有BLEU 1 BLEU 2 BLEU 3 BLEU 4四种 其中n gram指的是连续的单词个数为n
  • 校招真题练习008 浇花(百度)

    浇花 题目描述一个花坛中有很多花和两个喷泉 喷泉可以浇到以自己为中心 半径为r的圆内的所有范围的花 现在给出这些花的坐标和两个喷泉的坐标 要求你安排两个喷泉浇花的半径r1和r2 使得所有的花都能被浇到的同时 r1 2 r2 2 的值最小 输
  • GCC编译优化应用预编译头

    服务器编译优化记录 对项目编译优化过程中一些思路和脚本工具实现 对内存受限的编译环境有一些帮助 工具 https github com wangxiaobai dd GccPrecompiledHeader 环境 32G内存 16核 Mak