性能优化特性之:PGO

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
EMR Serverless Spark 免费试用,1000 CU*H 有效期3个月
简介: 本文介绍了倚天实例上的编译优化特性:PGO,并从优化原理、使用方法进行了详细阐述。

优化原理

PGO全称profile guided optimization,主要是为了解决传统编译器在执行优化的时候,只是是基于静态代码信息,而不去考虑用户可能的输入,从而无法有效对代码进行有效优化的问题。 PGO可以分为三个阶段,分别是instrument,train,optimize三个阶段。在instrument阶段中,会先对应用做一次编译。在这次编译中,编译器会向代码中插入一下指令,以便下一阶段可以收集数据。插入的指令分为三种类型,分别用来统计:

  1. 每个函数被执行了多少次
  2. 每个分支被执行了多少次(例如if-else的场景)
  3. 某些变量的值(主要用于switch-case的场景)

在train阶段中,用户需要使用最常用的输入来运行上一阶段编译生成的应用。由于上一阶段已经做好了收集数据的准备,在经过train阶段之后,该应用最常见的使用场景对应的数据就会被收集下来。 最后阶段是optimization阶段。在该阶段中,编译器会利用上一阶段收集到的数据,对应用进行重新编译。由于上一阶段的数据来自于用户输入的最常见的用户场景,那么最后优化得到的结果就能在该场景下有更好的优化。

使用方法

举例说明如何使用PGO来进行编译优化: 编写一段C++代码,该代码用较为低效的方式来判断一个数字是否为质数。代码如下:

//test.cpp
#include<iostream>
#include<stdlib.h>
using namespace std;
int main(int argc, char** argv){
    int num0 = atoi(argv[1]);
    int num1 = atoi(argv[1]);
    int branch = atoi(argv[2]);
    if (branch < 1){
        for (int i=2;i<=num0;i++){
            if (num0%i==0){
                cout<<i<<endl;
                break;
            }
        }
    } else {
        for (int i=2;i<num1;i++){
            if (num1%i==0){
                cout<<i<<endl;
                break;
            }
        }
    }
    return 0;
}

可以看到代码中根据branch的值不同,分为了两个分支。这两个分支的代码完全相同。这个是为了后续测试的目的。另外,2147483647是int范围内最大的质数,后面会用到。

不使用PGO

先看下不使用PGO的情况。用下列命令编译:

g++ test.cpp -O3 -o test

执行下面两条命令得到两个分支的时间

time ./test 2147483647 0
real    0m6.904s
user    0m6.902s
sys     0m0.000s
time ./test 2147483647 1
real    0m6.907s
user    0m6.905s
sys     0m0.000s

可以看到两个分支的执行时间几乎是相同的。

使用PGO

使用下面的命令做第一次编译

g++ test.cpp -O3 -fprofile-generate -o test.pgo_generate

这里得到的test.pog_generate即是前文提到的第一阶段生成用户收集数据的binary。 执行下列命令进行训练:

time ./test.pgo_generate 2147483647 0
real    0m11.894s
user    0m11.890s
sys     0m0.001s

这边只训练branch=0这个分支。可以看到由于需要收集数据,执行速度慢了很多。 接下来再做一次编译:

g++ test.cpp -O3 -fprofile-use -o test.pgo_use

这里得到的test.pgo_use即是最终经过PGO优化完成的binary。 执行下列命令测试时间

time ./test.pgo_use 2147483647 0
real    0m6.258s
user    0m6.255s
sys     0m0.001s
time ./test.pgo_use 2147483647 1
real    0m6.905s
user    0m6.903s
sys     0m0.000s

可以看到,被优化了的branch=0分支,运行速度得到了提升;而没有被优化的branch=1分支,执行时间保持不变。 这也就说明了PGO这样的优化是有效的。



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

更多调优信息,请参考:

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

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

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

相关文章
|
缓存 编译器
BOLT 二进制反馈优化技术
大型应用的代码往往达到数十甚至上百MB,这导致在程序执行时缓存机制无法充分利用,导致大量时间花费在CPU和内存链路上。通过对热点函数的布局进行优化,我们可以更好地利用CPU cache,从而获得较为可观的性能提升。针对这一问题,在编译技术上有PGO和Bolt两种解决办法,两者都是一种通过收集程序在运行时如跳转,调用关系,函数热度等执行信息,这些收集到的程序运行情况数据(profile data),可以更好地指导一些程序优化的策略,如是否对函数进行内联,以及对基本块和函数布局的排布来提高特定场景下的程序性能。
2192 2
BOLT 二进制反馈优化技术
|
数据采集 机器学习/深度学习 监控
Arm Coresight 介绍
Coresight 是 ARM 架构上的一款嵌入式系统监控和调试工具,能够为系统管理员和开发人员提供便捷的系统监控和调试功能。该平台可以实时追踪和分析处理器上的活动,以深入了解潜在的性能瓶颈和问题。本文将介绍Coresight的概念、优势及其安装、配置、故障排除和调试等方面的内容,并探讨其未来发展方向和重要性。
1926 1
|
数据中心 Anolis
性能优化特性之:LSE指令集编译优化
本文介绍了倚天实例上的编译优化特性:LSE,并从优化原理、使用方法进行了详细阐述。
|
机器学习/深度学习 监控 Ubuntu
perf性能分析工具使用分享
perf性能分析工具使用分享
2224 0
perf性能分析工具使用分享
|
6月前
|
存储 SQL 缓存
Perf Arm SPE介绍与使用
本次分享的主题是 Perf Arm-SPE 的介绍及使用,本次分享主要介绍如何在倚天 710 平台上利用 Arm-SPE 特性定位伪共享问题、分析内存访问、分析指令延时以及监控访存延时等功能。 1. 背景介绍 2. Arm SPE的原理 3. Arm SPE在倚天服务器上的应用 4. Arm SPE 更多特性与功能的探索
465 0
|
9月前
|
SQL 监控 Java
Java性能优化:提升应用效率与响应速度的全面指南
【10月更文挑战第21】Java性能优化:提升应用效率与响应速度的全面指南
|
缓存 算法 大数据
倚天710规模化应用 - 性能优化 - 软件预取分析与优化实践
软件预取技术是编程者结合数据结构和算法知识,将访问内存的指令提前插入到程序,以此获得内存访取的最佳性能。然而,为了获取性能收益,预取数据与load加载数据,比依据指令时延调用减小cachemiss的收益更大。
|
11月前
|
Web App开发 编译器 测试技术
Go PGO 快速上手,性能可提高 2~4%!
Go PGO 快速上手,性能可提高 2~4%!
|
10月前
|
C++
C++(十九)new/delete 重载
本文介绍了C++中`operator new/delete`重载的使用方法,并通过示例代码展示了如何自定义内存分配与释放的行为。重载`new`和`delete`可以实现内存的精细控制,而`new[]`和`delete[]`则用于处理数组的内存管理。不当使用可能导致内存泄漏或错误释放。
|
存储 编译器 C语言
性能优化特性之:LTO
本文介绍了倚天实例上的编译优化特性:LTO,并从优化原理、使用方法进行了详细阐述。