性能优化特性之:PGO

本文涉及的产品
云服务器 ECS,每月免费额度200元 3个月
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云服务器ECS,u1 2核4GB 1个月
简介: 本文介绍了倚天实例上的编译优化特性: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

相关文章
|
9月前
|
存储 编译器 C语言
性能优化特性之:LTO
本文介绍了倚天实例上的编译优化特性:LTO,并从优化原理、使用方法进行了详细阐述。
|
10月前
|
存储 缓存 NoSQL
性能优化方案及思考
周末闲暇在家,朋友让我帮忙优化一个接口,这个接口之前每次加载都需要40s左右,经过优化将性能提了10倍左右;又加了缓存直接接口响应目前为300ms左右,于是将自己的优化思路整理总结一下
|
12月前
|
Web App开发 SQL 缓存
性能优化
性能优化 前言 以前写过一篇性能优化的笔记前端性能优化小结,那时候算是列了一些优化的点,最近又读了几篇性能优化相关的文章,加上自己动手做了一些实践,相比之前有了更深一点的理解
|
SQL 缓存 NoSQL
服务性能优化总结
服务性能优化总结
|
Android开发 芯片 UED
初识性能优化
性能优化一词相信大家都经常听到,今天我们就简单的来认识以下性能优化,了解做性能优化的必要性以及优化的分类。
初识性能优化
|
SQL 缓存 JSON
性能优化之接口优化
本文从客户端的视角,分享客户端如何协同服务端进行接口时间的优化。
299 0
性能优化之接口优化
|
并行计算 程序员 Linux
C++服务性能优化的道与术-道篇:阿姆达尔定律
在之前的文章 《2004:当CPU温和地走入那个良夜》 中我讲到了2000年后摩尔定律的终结,CPU时钟频率定格,多核成为CPU发展的新方向,并行计算成为趋势。
189 0
C++服务性能优化的道与术-道篇:阿姆达尔定律
|
机器学习/深度学习 缓存 JavaScript
|
存储 人工智能 缓存
性能优化的本质
资源与时间的兑换 cache 空间资源与时间的兑换-- 提前计算,cache结果-- cache到内存中, 更快的内存空间换取时间-- 数据库设计中的反规范化设计, 通过增加冗余字段,减少子查询 -- 空间换取时间-- 网页中的静态化cache, 动态网页生成结果cache -- 空间换取时间集群,读写分离,主从库等.
1258 0