如何分析和提高大型项目(C/C++)的编译速度?

2023-10-29

/C++编译基本原理

对于C/C++代码通常来说整个构建过程分为以下几个主要部分:

  • 预处理
    在此阶段主要完成的工作是将头文件展开、替换宏指令、条件编译展开、消除注释。
  • 编译
    在此阶段主要将预编译好的文件转换成汇编语言(高级语言->LLVM平台无关语言->平台汇编语言)。
  • 汇编
    在此阶段将汇编语言转换为二进制机器语言。
  • 链接
    将编译产物和预编译制品(.o、.a、.so)“拼”成可执行文件,具体一些就是为main编译过程中每一个未定义的符号去编译产物中挨个寻找相应的实现代码,补全符号地址信息。

在编译耗时分析中也就应该对以上几个主要方面分别进行时间维度的评估,逐渐细化分析粒度确定时间瓶颈,直到某个文件、某个函数、某个模板才能有针对性地制定从宏观的构建系统到微观的文件、符号的具体优化方案。

预处理

gcc -E选项可以得到预处理后的结果,扩展名为.i 或 .ii。一般来说对预处理阶段的分析尤为重要,因为预处理完了之后的中间文件才是真正编译过程的输入。预处理后文件的体量大小直接影响了后续阶段各个部分的时间消耗水平。由于C/C++编译特点的影响,每个编译单元(源文件),都需要独立解析所有包含的头文件。也就是说如果N个源文件引用到了同一个头文件,则这个头文件需要解析N次。如果头文件中有模板(STL/Boost),则该模板在每个cpp文件中使用时都会做一次实例化,N个源文件中的std::vector会实例化N次。通常来说预处理阶段资源消耗是否合理一般可以通过以下几个具体指标进行查看。

  • 单个源文件头文件引用总数
  • 单个头文件被引用总数

编译

gcc -S选项可以得到编译后的汇编代码文件,扩展名为.s。在该阶段中,GCC为了满足用户不同程度的的优化需要,提供了近百种优化选项,用来对编译时间,目标文件长度,执行效率这个三维模型进行不同的取舍和平衡。优化的方法不一而足,总体上将有以下几类:

  1. 精简操作指令。
  2. 尽量满足CPU的流水操作。
  3. 通过对程序行为地猜测,重新调整代码的执行顺序。
  4. 充分使用寄存器。
  5. 对简单的调用进行展开等等。

而使用编译器提供的优化选项有时也可能需要再别的地方做取舍。部分优化选项会精简指令改变代码执行顺序,这会导致程序的可调试性大幅降低。另外一些涉及对寄存器、内存进行优化的指令可能会使程序在内存或者寄存器中结果的正确性得不到保障,这也是偶尔会在涉及到寄存器操作的代码中看到Volatile关键字的原因之一。

为了简化用户操作,GCC也提供了相应的一些预设优化方案例如O0~03

  • O0:不做任何优化,这是默认的编译选项。
  • O和O1:对程序做部分编译优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化。
  • O2:是比O1更高级的选项,进行更多的优化。GCC将执行几乎所有的不包含时间和空间折中的优化。当设置O2选项时,编译器并不进行循环展开以及函数内联优化。与O1比较而言,O2优化增加了编译时间的基础上,提高了生成代码的执行效率。
  • O3:在O2的基础上进行更多的优化,例如使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化。
  • Os:主要是对代码大小的优化, 通常各种优化都会打乱程序的结构,让调试工作变得无从着手。并且会打乱执行顺序,依赖内存操作顺序的程序需要做相关处理才能确保程序的正确性。

汇编

gcc -c选项可以得到汇编后的结果文件,扩展名为.o。.o文件,是按照的二进制编码方式生成的文件。在这个阶段中可以做的优化方案并不多,所以暂时只需要了解该阶段的基本作用即可。

链接

简单的讲,连接器的工作就是解析未定义的符号引用,将目标文件中的占位符替换为符号的地址。链接器还要完成程序中各目标文件的地址空间的组织,这可能涉及重定位工作。在C./C++程序的链接过程中主要涉及以下角色:

  • 静态库:指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了,其后缀名一般为“.a”。
  • 动态库:在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可执行文件比较小,动态库一般后缀名为“.so”。
  • 可执行文件:将所有的二进制文件链接起来融合成一个可执行程序,不管这些文件是目标二进制文件还是库二进制文件。

C++编译特性

编译单元

C/C++的编译系统和其他高级语言存在很大的差异,其他高级语言中,编译单元是整个Module,即Module下所有源码,会在同一个编译任务中执行。而在C/C++中,编译单元是以文件为单位。每个.c/.cc/.cxx/.cpp源文件是一个独立的编译单元,导致编译优化时只能基于本文件内容进行优化,很难跨编译单元提供代码优化。

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

如何分析和提高大型项目(C/C++)的编译速度? 的相关文章

  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • 如何在 VC++ CString 中验证有效的整数和浮点数

    有人可以告诉我一种有效的方法来验证 CString 对象中存在的数字是有效整数还是浮点数吗 Use tcstol http msdn microsoft com en us library w4z2wdyc aspx and tcstod
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 如何将 SOLID 原则应用到现有项目中

    我对这个问题的主观性表示歉意 但我有点卡住了 我希望之前处理过这个问题的人能够提供一些指导和建议 我有 现在已经成为 一个用 C 2 0 编写的非常大的 RESTful API 项目 并且我的一些类已经变得巨大 我的主要 API 类就是一个
  • 无法注册时间触发的后台任务

    对于 Windows 8 应用程序 在 C Xaml 中 我尝试注册后台任务 很难说 但我想我的后台任务已正确注册 但是当我单击调试位置工具栏上的后台任务名称时 我的应用程序停止工作 没有任何消息 我查看了事件查看器上的日志 得到 具有入口
  • 处理右值时的 insert 与 emplace

    std string myString std unordered set
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 如何将AVFrame转换为glTexImage2D使用的纹理?

    如您所知 AVFrame 有 2 个属性 pFrame gt data pFrame gt linesize 当我从视频 sdcard test mp4 android平台 读取帧后 并将其转换为RGB AVFrame副 img conve
  • 如何递归取消引用指针(C++03)?

    我正在尝试在 C 中递归地取消引用指针 如果传递一个对象 那就是not一个指针 这包括智能指针 我只想返回对象本身 如果可能的话通过引用返回 我有这个代码 template
  • 在 C 中使用枚举而不是 #defines 作为编译时常量是否合理?

    在 C 工作了一段时间后 我将回到 C 开发领域 我已经意识到 在不必要的时候应该避免使用宏 以便让编译器在编译时为您做更多的工作 因此 对于常量值 在 C 中我将使用静态 const 变量或 C 11 枚举类来实现良好的作用域 在 C 中
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • Oauth2中如何同时撤销RefreshToken和使AccessToken失效

    我正在使用 Owin Oauth2 授权和资源服务器相同 开发单页面应用程序 AngularJS Net MVC Json Rest API 的身份验证流程 我选择了 Bearer Token 路由而不是传统的 cookie session
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • 模板类的模板构造函数的 C++ 显式模板特化

    我有一个像这样的课程 template
  • 模板类中的无效数据类型生成编译时错误?

    我正在使用 C 创建一个字符串类 我希望该类仅接受数据类型 char 和 wchar t 并且我希望编译器在编译时使用 error 捕获任何无效数据类型 我不喜欢使用assert 我怎样才能做到这一点 您可以使用静态断言 促进提供一个 ht
  • 如何解压 msgpack 文件?

    我正在将 msgpack 编码的数据写入文件 在编写时 我只是使用 C API 的 fbuffer 如 我为示例删除了所有错误处理 FILE fp fopen filename ab msgpack packer pk msgpack pa
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • 为什么空循环使用如此多的处理器时间?

    如果我的代码中有一个空的 while 循环 例如 while true 它将把处理器的使用率提高到大约 25 但是 如果我执行以下操作 while true Sleep 1 它只会使用大约1 那么这是为什么呢 更新 感谢所有精彩的回复 但我
  • 在 System.Type 上使用条件断点时出错

    这是函数 public void Init System Type Type this Type Type BuildFieldAttributes BuildDataColumns FieldAttributes 我在第一行设置了一个断点
  • MySqlConnectionStringBuilder - 使用证书连接

    我正在尝试连接到 Google Cloud Sql 这是一个 MySql 解决方案 我能够使用 MySql Workbench 进行连接 我如何使用 C 连接MySqlConnectionStringBuilder 我找不到提供这三个证书的

随机推荐

  • Redis常用value命令

    本文是根据B站大学动力节点课程总结而来 原视频请移步至Redis7 033 ZSet型value操作命令 2 哔哩哔哩 bilibili PS 其中的某个视频音画不同步 redis中的value类型有五种 分别是String 字符串类型 H
  • LC-3汇编语言求成绩等级

    题目描述 背景 16名学生成绩排序 及统计分析 成绩分类规则 A 全班排名前25 且成绩在85分及以上 B 非A成绩 全班排名前50 且成绩在75分及以上 C 非A B成绩 要求 使用LC 3汇编语言 编写程序实现以上功能 输入 16名学生
  • C#面向对象编程

    面向对象 C 不是一种纯粹的面向对象编程语言 它提供了多种编程范式 但是 面向对象是C 的一个重要概念 也是 NET 提供的所有库的核心原则 面向对象的三个最重要的概念是继承 封装和多态性 本章将介绍如何使用继承增强基类型 如何创建类层次
  • kafka应用问题

    1 问题一 Connection to node 2 could not be established Broker may not be available 解决办法 1 检查防火墙是否开放相关端口 2 如果是部署在云服务器 检查云服务器
  • C++ 拷贝(复制)构造函数

    拷贝构造函数用以将一个类的对象拷贝给同一个类的另一个对象 比如之前学习过的string类 string s1 string s2 s1 一般情况下的拷贝构造函数 class A private int n double d char s p
  • 小梅哥Xilinx FPGA学习笔记6——参数化设计及模块重用设计流水灯(跑马灯)

    参数化设计及模块重用设计流水灯 功能介绍 1 功能描述 一 代码编写 1 设计文件 2 激励文件 3 仿真图 二 总结 功能介绍 1 功能描述 8个Led灯以0 5s的的速率循环闪烁 参数化设计并且调用三八译码器模块完成该设计 三八译码器模
  • TCP/IP详解 卷1:协议 学习笔记 第六章 ICMP:Internet控制报文协议

    ICMP是IP层的组成部分 用来传递差错报文和其他需要注意的信息 它通常被更高层的协议 TCP UDP 使用 一些ICMP报文把差错返回给用户进程 类型字段可以有15个不同值 用来描述ICMP报文的类型 某些ICMP还使用代码字段的值进一步
  • 【BZOJ 4069】 [Apio2015]巴厘岛的雕塑

    4069 apio2015 巴厘岛的雕塑 Time limit 1000 ms Memory limit 65536 KB Description The province of Bali has many sculptures locat
  • QSharedMemory

    来源 https www devbean net 2013 11 qt study road 2 ipc Qt 提供了四种进程间通信的方式 1 使用共享内存 shared memory 交互 这是 Qt 提供的一种各个平台均有支持的进程间交
  • 难解的AIoT焦虑,华为是否在准备一剂特效药存在?

    几个月前有朋友问我 AIoT到底是什么 跟说了好多年的IoT有什么不同 我是这么回答的 想一想有台空调 可以手机来操控它打开和关闭 你想买不 我家的空调现在就可以 可是从来没用过手机操作 遥控器就在茶几上触手可得 打开手机找到APP再操作太
  • redis详解(二)—— 数据类型详解

    Redis常用数据类型详解 1 Redis最为常用的数据类型主要有以下 String Hash List Set Sorted set pub sub Transactions 在具体描述这几种数据类型之前 我们先通过一张图了解下Redis
  • 信号量与共享内存实现进程间通信(生产者消费者问题为例)

    一 信号量 信号量是IPC的一种 可以看做是一个计数器 计数值为可用的共享资源的数量 信号量可用于多进程的同步 为多个进程提供对共享资源的访问 linux下的信号量的接口函数如下 1 获取信号量 int semget key t key i
  • 学习心得_我的算法学习心得

    关于 严格来说 本文题目应该叫作 我的数据结构和算法面试学习心得 但这个写法实在太绕口 所以干脆叫 我的算法学习心得 希望对大家有帮助 需要说明下 本文主要是应对面试的算法学习 这篇文章讲了什么 对于算法的认知 算法的方法总结 小结 算法的
  • 解决python3 pkl文件打印出的数组有省略号的问题(numpy, pytorch)

    问题描述 python3 load了pkl文件后 发现打印出来的数组有省略号 不能用于继续的计算和操作 import pickle with open filename pkl rb as f data pickle load f prin
  • 'chcp' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 'cmd' 不是内部或外部命令,也不是可运行的...

    打开anaconda promp 提示 chcp 不是内部或外部命令 也不是可运行的程序 或批处理文件 cmd 不是内部或外部命令 也不是可运行的 解决办法 我在安装Anaconda是默认添加了环境变量 此时需要在环境变量的系统变量的pat
  • 经典网络VGGNet介绍

    经典网络VGGNet 其中VGG为Visual Geometry Group 由Karen Simonyan等于2014年提出 论文名为 Very Deep Convolutional Networks for Large Scale Im
  • oracle expdp导出时报 ora-39070:无法打开日志文件

    在通过expdp导出命令导出某个用户的对象时出现以下截图错误 ORA 39002 操作无效 ORA 39070 无法打开日志文件 ORA 39087 目录名
  • MVG学习笔记(1) --无处不在的射影几何

    文章目录 前言 无处不在的射影几何 坐标 齐次性 仿射和欧几里得几何 仿射几何 欧几里得几何 3D欧几里得几何 前言 关于计算机视觉圣经的学习笔记 本次此系列的博文除了本次博文 基本不会包含前言了 参考书 多视图几何 第二版 无处不在的射影
  • python基础一(print函数+变量赋值 )

    1print 函数 注意 敲代码必须是英文输入状态 1 1 无引号 print 123 1 2单引号 print 路飞 1 3 双引号 注意 是英文输入法下的双引号 不是两个单引号 与单引号效果没什么差别 print one piece 1
  • 如何分析和提高大型项目(C/C++)的编译速度?

    C 编译基本原理 对于C C 代码通常来说整个构建过程分为以下几个主要部分 预处理 在此阶段主要完成的工作是将头文件展开 替换宏指令 条件编译展开 消除注释 编译 在此阶段主要将预编译好的文件转换成汇编语言 高级语言 gt LLVM平台无关