性能优化特性之:LTO

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
EMR Serverless StarRocks,5000CU*H 48000GB*H
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 本文介绍了倚天实例上的编译优化特性:LTO,并从优化原理、使用方法进行了详细阐述。

优化原理

LTO,顾名思义,就是在链接的时候,继续做一系列的优化。又由于编译器的优化器是以IR为输入,因此编译器在链接时优化的编译过程中将每个源文件生成的不再是真正的二进制文件,而是"LTO对象文件"。这些文件中存储的不是二进制代码,而是编译器生成的IR。 链接时,编译器会将所有"LTO对象文件"合并到一起,合并后生成的巨大IR文件包含了所有源代码信息,这样就能跨文件对所有源代码(合并后的IR文件)进行集中的分析和优化,并生成一个真正的二进制文件,链接并得到可执行文件。因为编译器能够一次性看到所有源代码的信息,所以它做的分析具有更高的确定性和准确性,能够实施的优化也要多得多。 但在使用LTO优化大型的应用程序的时候,“链接”阶段将所有"LTO对象文件"合并成一个IR文件并生成的单个二进制文件可能非常庞大,这给系统虚拟内存造成很大压力,导致频繁内存换页,最终影响编译、链接的效率,甚至出现out of memory错误。 实际上,GCC编译器在LTO阶段首先会将所有文件中的符号表(symbol table)信息和调用图(call graph)信息合并到一起,这样不仅能跨文件对所有的函数进行全局的分析,而且内存压力也较小。WPA(whole program analysis, 全局分析)阶段会确定具体的优化策略,并依据优化策略将所有的"LTO对象文件"合并成一或多个IR文件。 这些IR文件再次并发经过优化器优化后,生成真正的二进制对象文件并传递给真正的链接器进行链接,最后得到可执行文件。

使用方法

举例说明如何使用LTO来进行编译优化:

  • 编写了一个包含两个源文件(source1.c 和 source2.c)和一个头文件(source2.h)的程序。由于头文件中非常简单地包含了source2.c中的函数原型, 所以并没有列出。
/* source1.c */
#include <stdio.h> // scanf_s and printf.
#include "source2.h"
int square(int x) { return x*x; }
int main() {
  int n = 5, m;
  scanf("%d", &m);
  printf("The square of %d is %d.\n", n, square(n));
  printf("The square of %d is %d.\n", m, square(m));
  printf("The cube of %d is %d.\n", n, cube(n));
  printf("The sum of %d is %d.\n", n, sum(n));
  printf("The sum of cubes of %d is %d.\n", n, sumOfCubes(n));
  printf("The %dth prime number is %d.\n", n, getPrime(n));
}
/* source2.c */
#include <math.h> // sqrt.
#include <stdbool.h> // bool, true and false.
#include "source2.h"
int cube(int x) { return x*x*x; }
int sum(int x) {
  int result = 0;
  for (int i = 1; i <= x; ++i) result += i;
  return result;
}
int sumOfCubes(int x) {
  int result = 0;
  for (int i = 1; i <= x; ++i) result += cube(i);
  return result;
}
static
bool isPrime(int x) {
  for (int i = 2; i <= (int)sqrt(x); ++i) {
    if (x % i == 0) return false;
  }
  return true;
}
int getPrime(int x) {
  int count = 0;
  int candidate = 2;
  while (count != x) {
    if (isPrime(candidate))
      ++count;
  }
  return candidate;
}

source1.c文件包含两个函数,有一个参数并返回这个参数的平方的square函数,以及程序的main函数。main函数调用source2.c中除了isPrime之外的所有函数。source2.c有5个函数。cube返回一个数的三次方;sum函数返回从1到给定数的和;sumOfCubes返回1到给定数的三次方的和;isPrime用于判断一个数是否是质数;getPrime函数返回第x个质数。笔者省略掉了容错处理因为那并非本文的重点。 这些代码简单但是很有用。其中一些函数只进行简单的运算,一些需要简单的循环。getPrime是当中最复杂的函数,包含一个while循环且在循环内部调用了也包含一个循环的isPrime函数。通过这些函数,我们将在LTO下看到函数内联,常量折叠等编译器最重要,最常见的优化。

  • 编译命令(gcc版本是9.0.1)
# Non-LTO:
gcc source1.c source2.c -O2 -o source-nolto
# LTO:
gcc source1.c source2.c -flto -O2 -o source-lto
  • 检查source-nolto的汇编
1. 可以发现square被main函数inline了,对于第一次square(n)的调用,由于n在编译时刻可知,所以代码
   被常数25替代,对于square的第二次调用square(m),由于m的值在编译时是未知的,所以编译器不能对
   计算估值。
2. 可以发现isPrime被getPrime函数inline了,这是由于candidate有初始值,inline后可以做常量折叠;
   另外一方面,isPrime是static函数,且只有getPrime调用了它,inline之后,可以将这个函数当作dead
   code删除,减小代码体积。
  • 检查source-lto的汇编
1. 可以看到除了scanf之外的所有函数都被作为了内联函数,因为在GCC LTO的WPA阶段, 这些函数的定义都是
   可见的。并且,由n编译时刻已知,编译器在编译时刻就会完成函数square(n), cube(n),sum(n)和
   sumOfCubes(n)的计算。
2. LTO获得了30%以上的性能提升
  • 结论
1. 某些优化,当其作用于整个程序级别时,往往比其作用于局部时更加有效,函数内联就是这种类型的优化之一。
2. 事实上,大多数优化都在全局范围内都更加有效,这也就是我们编译大型应用程序时,推荐使用LTO的原因和理由。
3. FireFox、Chrome、 Mysql等大型应用使用LTO build都获得了5%-15%不等的性能提升




---------------------------------------------------------------------------------------

更多调优信息,请参考:

龙蜥社区:https://openanolis.cn/

KeenTune SIG:https://openanolis.cn/sig/KeenTune

阿里云龙蜥操作系统专区:https://developer.aliyun.com/group/aliyun_linux

目录
打赏
0
1
0
0
1
分享
相关文章
BOLT 二进制反馈优化技术
大型应用的代码往往达到数十甚至上百MB,这导致在程序执行时缓存机制无法充分利用,导致大量时间花费在CPU和内存链路上。通过对热点函数的布局进行优化,我们可以更好地利用CPU cache,从而获得较为可观的性能提升。针对这一问题,在编译技术上有PGO和Bolt两种解决办法,两者都是一种通过收集程序在运行时如跳转,调用关系,函数热度等执行信息,这些收集到的程序运行情况数据(profile data),可以更好地指导一些程序优化的策略,如是否对函数进行内联,以及对基本块和函数布局的排布来提高特定场景下的程序性能。
2245 2
BOLT 二进制反馈优化技术
安谋科技(Arm China)马闯:Arm架构下性能分析与优化介绍
2023年9月19日,系列课程第九节《Arm®架构下性能分析与优化介绍》正式上线,由安谋科技 (Arm China)主任工程师马闯主讲,内容涵盖:Arm架构下性能监控单元 (PMU) 介绍、Arm统计性能分析扩展 (SPE) 介绍、Arm性能分析工具介绍、Arm架构下性能优化案例分享,本期节目在阿里云官网、阿里云微信视频号、阿里云钉钉视频号、InfoQ官网、阿里云开发者微信视频号、阿里云创新中心直播平台 & 微信视频号同步播出,同时可以点击【https://developer.aliyun.com/topic/ecs-yitian】进入【倚天实例迁移课程官网】了解更多内容。
Arm Coresight 介绍
Coresight 是 ARM 架构上的一款嵌入式系统监控和调试工具,能够为系统管理员和开发人员提供便捷的系统监控和调试功能。该平台可以实时追踪和分析处理器上的活动,以深入了解潜在的性能瓶颈和问题。本文将介绍Coresight的概念、优势及其安装、配置、故障排除和调试等方面的内容,并探讨其未来发展方向和重要性。
1962 1
性能优化特性之:16K原子写
本文介绍了在倚天实例上进行内存优化的调优特性:16K原子写 的优化原理、使用方法。
性能优化特性之:LSE指令集编译优化
本文介绍了倚天实例上的编译优化特性:LSE,并从优化原理、使用方法进行了详细阐述。
倚天710规模化应用 - 性能优化 - 软件预取分析与优化实践
软件预取技术是编程者结合数据结构和算法知识,将访问内存的指令提前插入到程序,以此获得内存访取的最佳性能。然而,为了获取性能收益,预取数据与load加载数据,比依据指令时延调用减小cachemiss的收益更大。
系统性能优化总结
系统性能优化总结
207 10
性能优化特性之:PGO
本文介绍了倚天实例上的编译优化特性:PGO,并从优化原理、使用方法进行了详细阐述。
CoreBolt——在倚天上基于 Coresight 做 BOLT 优化
CoreBolt 是一种倚天平台的性能优化解决方案。CoreBolt 通过 Coresight 在程序运行时采集程序运行信息,对程序的热代码和冷代码进行区分,并通过 BOLT 对程序进行代码段重排,从而提升程序代码的局部性,减少程序运行过程中由 CPU iCache miss 和 iTLB miss 引发的性能下降,提升程序的整体性能。
1379 6
深入gcc编译器:C/C++代码如何变为可执行程序
深入gcc编译器:C/C++代码如何变为可执行程序
349 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问