Profile 分析 Erlang 虚拟机源码时要注意的一个问题
最近用 Intel Vtune 剖析 Erlang 虚拟机的运行,想看看那些函数和语句耗时最多,遇到一个小问题,那就是 Vtune 给出的源码和汇编码对应有问题。这个问题在 profile 或 debug 其他程序的时候也有可能会碰到的。
看下面的例子,运行 dialyzer 的时候用 Vtune 进行采样,然后看结果:

很自然,process_main 函数耗时最多,是 CPU 主要利用者,因为整个 Erlang 虚拟机的指令执行引擎都在这个函数中。那么双击这个函数,进去看详细的源代码的耗时信息,会看到奇怪的现象:

可以看到第 12 行的注释和下面的 #include 指令竟然耗时间了,更神奇的是,这些源码行还输出了汇编,比如第 12 行对应右边的 mov 指令。还有下图中,第 38 行的 #include 生成这么多汇编码也是不可能的:

这会不会是和宏展开相关呢?会不会是和编译器的优化相关呢?会不会是编译器弄错了呢?
以上问题的答案都是否定的。因为这个文件(beam_emu.c)宏展开也不会在第 12 行有代码。而且编译器不会这么笨的。优化也不可能,因为我没开优化,为了详细观察语句(对应指令)执行耗时情况,关闭了优化(-O0),而且请求编译器包含最丰富的调试信息(-g3)。也不太可能是编译器弄错了,因为 gcc 和 Intel 的 icc 都出现了这个现象,而且都是在同样的位置。假设真的是编译器弄错了,那么完全不同的编译器也不太可能会错成一样,所以感觉这里肯定是有确定性原因的。
那到底是怎么回事呢?用 objdump -S 导出目标文件 beam_emu.o 的源码和汇编码信息,可以看出编译器是很忠诚的,没有奇怪的问题,而且很显然那些注释和 #include 指令那些地方是没有输出汇编代码的,编译器既然能在目标文件中内嵌正确的源码信息,那就不太可能会弄错行号。那就看看第 12 行对应的汇编码到底对应的源码是什么。下图中框出来的 3 条汇编指令是 NextPF 宏生成的,中间那一条就是之前图中在 0x5d7e6c 处对应第 12 行的那条汇编。

那就找这几行源代码在 beam_emu.c 中对应的位置应该就可以看出究竟了。有趣的是,在 beam_emu.c 中其实找不到这几行代码。beam_emu.c 把一些热门指令的代码单独放在 beam_hot.h 文件中了,这个文件是在 build 过程中自动生成的。果然,在这个文件中看到了这段代码:

哈,找到原因了。调用 NextPF 宏的刚好是第 12 行,原来编译器记录的是被包含文件中的行数。当然这并不是编译器的处理方式不对,而是这种将源代码 #include 到另一个源代码文件中的做法本身不是一个好的编程习惯,但是鉴于 process_main 的特殊性,这有助于保持代码的简洁(尽管这样 process_main 还是有好几千行)。
注意,这里的代码映射错误的问题并不是 Vtune 的问题,Vtune 只是忠实地反映出目标文件中调试信息里面的内容,而调试信息是编译器生成的。
那么为了能在 profile 过程中准确对应到源码行,我们手工把 beam_hot.h 文件的内容(还有 beam_cold.h,对应冷门指令)拷贝到 beam_emu.c 中对应的位置并重新 build 即可。再次运行 profile,可以看出代码映射完全正确了:

对右侧的汇编指令的耗时排序:

可以看出跳转指令的开销还是不小的,因为虚拟机每执行下一条指令都是一个跳转。所以 Erlang 虚拟机中的指令数目也非常多,每一条都尽量完成尽可能多的工作,以减少指令分发的次数。
Profile 分析 Erlang 虚拟机源码时要注意的一个问题的更多相关文章
- 分析jQuery源码时记录的一点感悟
分析jQuery源码时记录的一点感悟 1. 链式写法 这是jQuery语法上的最大特色,也许该改改POJO里的set方法,和其他的非get方法什么的,可以把多行代码合并,减去每次 ...
- IDEA查看源码时提示:Library source does not match the bytecode for class的问题分析
通过Maven查看依赖的源码时,通常是Maven自动下载JAR包附属的source包,但是会出现一个问题,由于使用lombok插件会造成编写的Java文件和编译后的class上有差别,所以IDEA打开 ...
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- [Erlang 0119] Erlang OTP 源码阅读指引
上周Erlang讨论群里面提到lists的++实现,争论大多基于猜测,其实打开代码看一下就都明了.贴出代码截图后有同学问这代码是哪里找的? "代码去哪里找?",关于Erla ...
- Android5.1.1 - APK签名校验分析和修改源码绕过签名校验
Android5.1.1 - APK签名校验分析和修改源码绕过签名校验 作者:寻禹@阿里聚安全 APK签名校验分析 找到PackageParser类,该类在文件“frameworks/base/cor ...
- JPEG概述和头分析(C源码)
原创文章,转载请注明:JPEG概述和头分析(C源码) By Lucio.Yang 部分内容来自:w285868925,JPEG压缩标准 1.JPEG概述 JPEG是一个压缩标准,又可分为标准 JPE ...
- [strongswan][autoconf][automake][cento] 在CentOS上编译strongswan git源码时遇到的autoconf问题
编译strongswan的git源码问题 1. 概述 首先,我们想要通过源码编译strongswan.当满足以下条件时,通常你会遇见此问题: 源码时通过git clone的得来的,而不是官网下载的源码 ...
- Cesium专栏-填挖方分析(附源码下载)
Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精度,渲染质量以 ...
- Proxy Server源码及分析(TCP Proxy源码 Socket实现端口映射)
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u014530704/article/de ...
随机推荐
- 为什么NOLOCK查询提示是个不明智的想法
一些人总当NOLOCK查询提示是SQL Server里的加速器,因为它避免了大量的死锁情景.在这篇文章里,我想向你展示下为什么NOLOCK查询提示是个不好的想法. 脏读(Dirty Reads) NO ...
- C语言中的经典例题用javascript怎么解?(一)
C语言中的经典例题用javascript怎么解?(一) 一.1+2+3+……+100=? <script type="text/javascript"> ...
- 二元查找树转变成排序的双向链表之C#算法实现
此题为July在CSDN发布的微软编程面试100题中的第一题,觉得蛮有趣的,今天也拿过来玩玩,July的代码用的是C++实现,可能因为有指针的原因吧,感觉看起来相对比较容易理解整个的实现过程,而我,试 ...
- Spring基础—— SpEL
一.SpEL:Spring 表达式语言,在使用的时候类似于 EL 表达式,但是需要注意的是,SpEL 使用在 Spring Config 文件中. 二.格式:使用 #{} 作为界定符,所有在大括号中的 ...
- android 获取当前位置
1. Android开发位置感知应用程序方式:1. GPS 定位 精确度高,仅适用于户外,严重消耗电量.如果手机内置GPS接受模块,即使手机处于信号盲区,依然可以获取位置信息. 2. NETW ...
- 重构第12天 分解依赖(Break Dependencies)
理解:“分解依赖” 是指对部分不满足我们要求的类和方法进行依赖分解,通过装饰器来达到我们需要的功能. 详解:今天我们所讲的这个重构方法对于单元测试是非常有用的.如果你要在你的代码中加入单元测试但有一部 ...
- .Net实现微信公众平台开发接口(三) 之 “信息回复”
对于每一个POST请求,开发者在响应包(Get)中返回特定XML结构,对该消息进行响应(现支持回复文本.图片.图文.语音.视频.音乐).请注意,回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器 ...
- 从零开始学习Linux (cd命令)
上一篇博客中提到,我们学习命令大多都要参考 --help 这个选项.但是cd命令并没有这个选项. 我们可以通过 help cd 来查看cd的使用方式.其实cd命令挺简单的,它的作用是进入文件夹,也就是 ...
- [moka同学笔记]yii2.0小物件的简单使用(第一种方法)
这是第一种方法,还有另一种方法,其实都差不多. 1.在创建widgets\HelloWiget.php <?php /** * Created by PhpStorm. * User: Admi ...
- Afinal
1.注解功能 1)继承:FinalActivity ( 需要复制 afinal_0.5.1_bin.jar到lib下) 2)@ViewInject() public class AfinalActiv ...