自编教材实操课程分享:第五章—运行时优化
先进编译实验室
2024年05月11日 08:00
收录于文集
共28篇


本文主要介绍运行时优化。实验环境是CentOS7 + LLVM。

1. 优化方法简述

1.1 影响程序启动的因素

可执行文件在操作系统中以进程的方式执行,首先将可执行文件加载到内存中,然后系统分配内存资源完成进程的创建。影响可执行文件运行性能的因素如下:

(1)可执行文件的大小:系统针对全局函数表和内部函数表分别实现了动态链接和延迟绑定优化。一方面提高了装载速度,另一方面减少了不必要的内存损耗。

(2)进程的创建方式:系统做了写入时复制优化,即在子进程时不直接复制父进程的所有资源,只允许读数据,在只有一个进程要执行写操作时才拷贝所有内容分配给子进程。

1.2 程序启动性能优化

应用程序启动速度是应用程序可用性的重要指标。下面介绍源代码、库文件和可执行文件三种优化方法。

(1)优化源代码

假设应用程序在启动时需要频繁访问某一个文件A,但是每次访问该文件的不同部分,每次访问的大小也没有规律,这种频繁随机的访问模式势必导致大量的 IO 时间浪费在寻道时间。相反地如果一次性把需要频繁访问的文件全部预读入内存,那么这种操作顺序由于是顺序访问,从而可以节省大量的时间。预读文件由以下两种方法实现:

<1> 构造相应的数据结构,把文件读入内存并解析后,将其内容存放到一个内存数据结构中,以供后续存取。

<2> 利用操作系统的文件缓存特性,程序启动时直接预读一遍待缓存的文但并不放在具体的数据结构中,由于操作系统会缓存该文件到内存中,从而可达到同样的效果且代码量较小,在预读时尽量用内存映射函数。

同时也可以构造一个和应用程序独立的预加载序,预先加载应用程序启动时需要的动态链接库和其他数据,这样当应用程序启动时所需的大部分代码页和数据页已经出现在内存中,可以避免相应的缺页中断。

(2)优化库文件

减少动态链接库的数量是提高程序启动性能的一个重要原则,是构造大型应用程序时考虑的首要问题。减少动态链接库可以通过以下两种方法实现:

<1> 合并动态链接库,将启动时需要加载的多个较小的动态链接库合并成一个大的动态库

<2> 强制性修改代码,减少不必要的动态链接库依赖。

(3)优化可执行文件

通过优化可执行文件实现程序启动时的优化,可以通过减少动态链接尺寸如方法减少IO操作,具体实现有使用编译优化没项和清除冗余代码两种方法。

在LLVM编译过程中,添加-ffunction-sections和-fdata-sections会在输出文件object中给每个函数和全局变量控制在一个section中并以对应的函数名或者全局变量命名。

2. 示例分析

下面给出了一个优化可执行文件示例,命名为test-1.c.

在LLVM编译过程中,添加-ffunction-sections和-fdata-sections会在输出文件object中给每个函数和全局变量控制在一个section中并以对应的函数名或全局变量名命名。

运行命令:

(1)clang -O3 test-1.c -S -o test-ori.s

(2)clang -O3 -ffunction-sections test-1.c -S -o test-opt.s

生成的汇编文件对比如下所示:

经过对比可发现,使用-ffunction-sections选项后生成的汇编文件中增加了section汇编指示。因为在生成可执行文件的链接过程中查找符号是以section为单元进行引用的,只要在section中的某个符号被引用,该section就会被加入可执行程序,如果section中的所有符号都没有被引用到,则该section不会被加入可执行文件,所以可以排除无用的函数,从而减少可执行文件的大小。

3. 总结

本节主要从影响进程的运行性能因素及如何优化程序的启动性能两方面,详细阐述了运行时优化的有关内容。

4. 参考资料

(1)gcc之 -ffunction-sections-CSDN博客

(2)在gcc中使用`-fdata-sections和`-ffunction-sections这两个选项的目的是什么? - 我爱学习网 (5axxw.com)