d的ldc的pgo优化

news/2024/7/10 4:08:58 标签: d, ldc, 优化, pgo
du_pl"> <div id="article_content" class="article_content clearfix"> <div id="content_views" class="markdown_views prism-atom-one-light"> display: none;"> d" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

原文

三个月前,我使用de>LDCde>按配置文件优化de>(PGO)de>测量了D编译器de>前端de>代码,有de>7%de>的性能提升.现在,部分de>PGOde>工作于de>2016de>年de>1de>月20日合并到de>LDCde>主分支中!

de>LDCde>使用de>PGOde>,类似de>Clangde>使用de>PGOde>这里,大部分内容也适合de>Clangde>.

d="PGO_6">按配置优化de>(PGO)de>

d="PGO_7">带de>PGOde>构建

de>配置de>文件可用de>不同de>的方式获得,但(目前)de>LDCde>仅支持指令分析.编译器在de>第一个de>编译阶段中添加"de>指令de>"代码.然后,使用de>要优化de>代码的de>用例de>的de>输入de>,运行程序,并在de>退出de>时,de>输出de>配置文件数据到de>单独de>文件中.编译器在de>第二个de>编译阶段使用此配置文件数据文件来de>编译和优化de>.

1,使用指令编译:de>ldc2 -fprofile-instr-generate=profile.raw yourprogram.d -of=instrumented_programde>
2,用常见de>工作de>负载(要优化de>工作de>负载类型)运行de>instrumented_programde>.这应该创建de>profile.rawde>文件.
3,de>转换de>原始配置文件为de>LDCde>可用格式:de>ldc-profdata merge -output=profile.data profile.rawde>

4,使用de>配置de>文件数据de>重新编译de>程序:de>ldc2 -O3 -fprofile-instr-use=profile.data yourprogram.d -of=optimized_programde>

de>指令de>会使de>程序de>明显变慢,但de>不必de>经常生成新的de>配置文件de>.在de>重新de>编译有de>更改de>程序时,可de>重用de>配置文件数据;de>LDCde>会de>检测de>控制流的de>变化de>,并de>简单de>忽略de>过时de>的配置文件数据.

d="_19">配置文件输出文件名

可在de>编译时de>指定,配置文件输出文件名,如上所示(de>-fprofile-instr-generate=<filename>de>).如果未指定文件名,则改用de>LLVM_PROFILE_FILEde>环境变量.如果未定义de>LLVM_PROFILE_FILEde>,则使用默认de>default.profrawde>文件名.

一般,单次运行程序不能创建有de>统计de>代表的配置文件.想使用不同的de>输入de>来分析de>多趟de>指令程序.每次运行程序,可设置de>LLVM_PROFILE_FILEde>为不同文件名,但配置文件运行时还支持配置文件名中的de>替换de>说明符来帮助你.分别用进程de>pidde>和de>主机名de>替换文件名中的de>%pde>和de>%hde>说明符.(de>%hde>需要de>LLVM>=3.9de>).

如果使用de>-fprofile-instr-generate=test.%p.rawde>编译并de>运行de>几次程序,最终会得到一组de>test.*.rawde>配置文件数据文件.然后,可如常使用de>ldc-profdatade>合并它们:

de class="prism language-cpp">profdata merge -o test.profdata test.*.raw
de>

d="_30">检查配置文件数据

de>ldc-profdatade>工具(与构建de>ldc2de>时使用的de>LLVMde>版本匹配的de>llvm-profdatade>的重命名版本)可来de>检查de>配置文件de>数据de>文件的内容.de>看看de>如下:

de class="prism language-cpp">d">extern(C)
d">void foo(d">int x) {
    d">if (x > 0) {
        d">if (x > 500) {
            // ...
        }
    }
}

d">void main() {
    foreach (i; 0 .. 1000) {
        foo(i);
    }
}
de>

使用

de class="prism language-cpp">ldc2 -fprofile-instr-generate=d">default.profraw -run test_foo.d
de>

编译并运行它.然后,

de class="prism language-cpp">ldc-profdata show -all-functions d">default.profraw
de>

输出:

de class="prism language-cpp">Counters:
  foo:
    Hash: 0x00000000000002cb
    Counters: 3
    Function count: 1000
  _Dmain:
    Hash: 0x0000000000000004
    Counters: 2
    Function count: 1
Functions shown: 2
Total functions: 2
Maximum function count: 1000
Maximum internal block count: 1000
de>

de>配置de>文件数据文件包含有de>每个函数de>计数器和de>其他信息de>的数据结构.在此,看到程序只有de>两个de>指令函数:de>foode>和de>_Dmainde>.

de>foode>函数包含3个执行计数器(每个de>ifde>语句,函数项加上计数器),该函数被调用de>1000de>次(“de>函数计数de>”).在de>-fprofile-instr-usede>编译步骤中,de>LDCde>使用de>"hash"de>字段来检查是否可使用de>配置文件数据de>.

d="_78">重用配置文件数据

de>LDCde>可de>重用de>旧版本程序获得的de>配置de>文件数据.在源码稍有de>更改de>时允许,de>重用de>配置文件,在配置文件中de>存储de>函数控制流的de>哈希de>.在de>-fprofile-instr-usede>编译步骤中,de>LDCde>确保配置文件中的de>函数哈希de>等于正在编译代码的哈希.

如果没有de>匹配项de>,de>LDCde>忽略该de>函数de>的配置文件数据.de>哈希de>并不完美:不同de>代码段de>可能产生相同的哈希,因此对de>新代码de>可应用de>旧版本de>代码获得的de>配置文件de>.如:

de class="prism language-cpp">d">void foo(d">int x) {
    d">if (x > 0) { // 1000x 真, 4x 假
        // ...
    }
}
de>

de>foode>函数几乎总是用de>正xde>调用,de>ifde>语句的配置文件数据是"是分支有de>1000de>次,否分支有4次".如果代码现在从de>x>0de>更改为de>x<0de>,则de>函数de>哈希不变(当前de>LDCde>行为),且错误地de>使用de>了旧的de>配置文件数据de>.

de class="prism language-cpp">d">void foo(d">int x) {
    d">if (x < 0) { // 用旧数据:1000x真, 4x假.错了
        // ...
    }
}
de>

de>哈希de>可依赖更多de>代码de>来区分de>>和<de>式.目前,哈希主要是为了避免在de>配置de>文件信息de>不足或过多de>时出现编译错误,

如,只有de>ifde>语句的函数才de>放入de>哈希中.de>哈希de>不完善是de>设计de>使然,因为某些de>更改de>不太可能de>更改de>旧配置文件数据的de>有效性de>.考虑将代码从de>x>1000de>更改为de>x>1001de>.此时,de>旧的de>配置文件数据可能仍足够好,de>丢弃它de>,性能会更糟.

无需苦恼:de>PGOde>不会de>改变de>D的de>语义de>,它只是个de>优化技术de>.因此,如果de>配置de>文件数据不再与de>修改de>后的de>代码匹配de>,则可能的最坏情况是程序性能de>下降de>.因为你已在(de>正确de>)测量有和没有de>PGOde>的程序性能,所以可轻松知道de>配置de>文件何时需要更新.

d="_106">启动代码后重置配置文件

de>ldc.profilede>模块包含对接de>配置de>文件指令的de>函数de>.唯一真正有用的函数是de>resetAll()de>.其他de>ldc.profilede>函数公开的de>函数de>是非常低级的,且在de>编译器/LLVMde>未来版本中可能不可用.de>resetAll()de>重置所有de>性能分析de>信息,并可从de>配置de>文件中de>删除de>程序启动行为:

de class="prism language-cpp">d">import dule">ldc.profile : resetAll;
d">void main()
{
    initializeProgram();
    resetAll();
    operate();
}
de>

这样,de>PGOde>优化器,为了获得最佳de>操作()de>性能,会降低de>initializeProgram()de>的性能.

d="_121">允许/禁止函数级分析

de>函数级de>分析实现,因此用新的de>(LDC_profile_instr,{true|false})de>指示de>打开/关闭de>指定函数的de>指令de>非常简单.de>指示de>与de>指示(inline,...)de>有相同的语义.

de class="prism language-cpp">d">void instrumented() {}
d">void not_instrumented() {
    pragma(LDC_profile_instr, false);
}
pragma(LDC_profile_instr, false) {
    d">void not_instrumented_2() {}

    d">void instrumented2_override() {
        pragma(LDC_profile_instr, true);
    }

    pragma(LDC_profile_instr, true):
    d">void instrumented3() {  }
    d">void instrumented4() {  }
}

pragma(LDC_profile_instr, false)
d">struct Strukt {
    d">void not_instrumented() {}
    d">void instrumented_method() {
        pragma(LDC_profile_instr, true);
    }
}
de>

指令de>默认de>为de>打开de>状态.因此,对非常de>可选de>指令,需要在de>每个de>文件的开头放de>pragma(LDC_profile_instr,false):de>.
但即便如此,也会指令de>导入de>函数.如果有de>足够de>的需求,则很容易实现de>默认关闭de>指令的de>命令行开关de>,因此仅de>指令de>一组de>指定de>函数就不会那么麻烦了.

div> div> <div id="treeSkill">div> <div id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box">div>

http://www.niftyadmin.cn/n/229261.html

相关文章

Python数据结构-----leetcode用队列实现栈

目录 前言&#xff1a; 方法步骤 示例 ​编辑 2.出栈操作:先把queue_in 里面的数据依次出队然后放入queue_tem里面去暂时存着&#xff0c;然后直到queue_in 里面剩下最后一个数据 d &#xff0c;这时候对这个数据进行出队返回就行了. Python代码实现 225. 用队列实现栈 前…

【Linux基础】常用命令整理

ls命令 -a选项&#xff0c;可以展示隐藏的文件和文件夹-l选项&#xff0c;以列表形式展示内容-h&#xff0c;需要和-l搭配使用&#xff0c;可以展示文件的大小单位ls -lah等同于la -a -l -h cd命令&#xff08;change directory&#xff09; 语法&#xff1a;cd [Linux路径]…

SpringBoot之自动配置累的解析和过滤机制源码解析

1.提炼三句话 整体来讲Spring Boot是通过条件注解、条件评估器和自动配置导入器等机制来实现自动配置的。 条件评估器来判断是否需要加载某个自动配置类。条件评估器通常被定义在“org.springframework.boot.autoconfigure.condition”包中&#xff0c;例如&#xff0c;Class…

【安全与风险】密码安全和用户认证

密码安全和用户认证基本问题证明你是谁为什么要验证还需要什么基于口令的身份认证常用使用模式常用使用模式可惜的是社会工程悉尼大学 (绿化96)尴尬和记忆关于密码使用的3个主要问题UNIX形式的密码密码散列字典式攻击影子密码其他密码问题生物计量学多模式生物识别系统定义为什…

阿里数学竞赛决赛名单公布:北大人数是清华4倍 | 最小仅14岁

4月10日消息&#xff0c;第二届阿里巴巴全球数学竞赛决赛入围名单公布&#xff0c;全球12个国家516位选手晋级&#xff0c;晋级率仅有1&#xff05;。 根据参赛者填报信息&#xff0c;晋级选手80&#xff05;以上是90后&#xff0c;年纪最小的只有14岁。 入围人数最高的前20所高…

什么人适合报考自动化类专业?(高考志愿填报选专业)

自动化类专业 是指以自动控制理论和技术为核心&#xff0c;以电子、计算机、通信、机械、材料等学科为基础&#xff0c;研究用数字电子技术、传感器技术、控制理论和计算机技术控制和自动化各种物理量和工艺过程的学科&#xff0c;主要涉及机械、电气、计算机等多个领域&#x…

【C++基础】auto关键字(C++11)(auto的使用细则;auto不能推导的场景;auto的使用场景;基于范围的for循环)

九、auto关键字 9.1 auto简介 在早期C/C(C98)中auto的含义是&#xff1a;使用auto修饰的变量&#xff0c;是具有自动存储器的局部变量&#xff0c;但遗憾的是一直没有人去使用它。因为在函数内定义的变量默认就是局部变量。 C11中&#xff0c;标准委员会赋予了auto全新的含义…

GCC编译器的使用

源文件需要经过编译才能生成可执行文件。GCC是一款强大的程序编译软件&#xff0c;能够在多个平台中使用。 1. GCC编译过程 主要分为四个过程&#xff1a;预处理、编译、汇编、链接。 1.1 预处理 主要处理源代码文件中以#开头的预编译指令。 处理规则有&#xff1a; &…