函数尾调用优化(Tail-call Optimization)对DTrace return probe的影响

SPARC架构下的反汇编(一)——SPARC简介 1. 写作目的&个人水平 之前做过SPARC架构下的反汇编项目,但资料比较少,所以写一点笔记,结合已有的资料以及个人的经验以便于查阅。总体来说就是资料的阅读理解和实际操作的经验。因为水平有限,对于底层的基本看不懂,所以不涉及。 2.SPARC简介 “可扩充处理器结构(SPARC,Scalable Processor Architecture)是RISC微处理器架构之... 阅读详情

今天这个话题要从stackoverflow上的一个帖子(http://stackoverflow.com/questions/23254418/getaddrinfo-fails-to-resolve-address-in-hosts-file-when-using-mocha/23331397#23331397)谈起。帖子作者遇到的问题简单地说,就是DTrace输出的getaddrinfo的返回值不对:

pid$target::getaddrinfo:return
{
    printf("%d", arg1);
}

getaddrinfo的返回值应该是0或者-1,但是帖子的作者说输出了“some big number”。为了验证一下,小编做了个测试。小编用的是Solaris 10(SPARC处理器)的环境,结果输出果然是一些很大的数,看起来像是地址。会是什么地址呢?小编百思不得其解。于是就在dtrace-discuss的邮件讨论组里问了一下:http://www.listbox.com/member/archive/184261/2014/04/sort/time_rev/page/1/entry/0:15/20140425044157:7327DBF0-CC55-11E3-8545-F2C1F3063A1C/,得到的回复是和函数尾调用优化(Tail-call Optimization)有关,并让我参考这个链接:Tail-call Optimization(http://docs.oracle.com/cd/E19253-01/817-6223/chp-fbt-11/index.html)。

尾调用在维基百科里的解释是:“在计算机科学里,尾调用是指一个函数里的最后一个动作是一个函数调用的情形:即这个调用的返回值直接被当前函数返回的情形。”。也就是像下面这样:

return bar();
 

而尾调用优化则是:“由于当前函数帧上包含局部变量等等大部分的东西都不需要了,当前的函数帧经过适当的更动以后可以直接当作被尾调用的函数的帧使用,然后程序即可以跳到到被尾调用的函数。产生这种函数帧更动代码与 “jump”(而不是一般常规函数调用的代码)的过程称作尾调用消除(Tail Call Elimination)或尾调用优化(Tail Call Optimization, TCO)。”。通俗地讲,也就是如果一个函数(caller)的结尾是调用另一个函数(callee),或者以callee的返回值作为caller的返回值,或者什么都不返回。那么尾调用优化就可以让callee复用caller的堆栈,不用为callee再分配堆栈空间。关于尾调用优化,大家可参考stackowverflow上的一个帖子:http://stackoverflow.com/questions/13017516/how-is-tail-call-optimization-in-fpls-implemented-at-the-assembly-level。

在Tail-call Optimization(http://docs.oracle.com/cd/E19253-01/817-6223/chp-fbt-11/index.html)这篇文档里,介绍了如何判断是否发生了尾调用优化:

(1)因为arg0是函数返回时的指令地址,在return probe里打印arg0的值。

(2)通过mdb或者gdb工具检查函数的汇编代码。如果arg0指向的是一处函数调用,而不是类似return这样的指令,那就是发生了尾调用优化。

文档还以dup系统调用作为例子。dup的汇编代码:

# echo "dup::dis" | mdb -k
dup:                            sra       %o0, 0, %o0
dup+4:                          mov       %o7, %g1
dup+8:                          clr       %o2
dup+0xc:                        clr       %o1
dup+0x10:                       call      -0x1278       
 
  
dup+0x14:                       mov       %g1, %o7

 

用以下DTrace命令输出arg0:

# dtrace -q -n fbt::dup:return'{printf("%s+0x%x", probefunc, arg0);}'

结果是0x10,正好是“call -0x1278 <fcntl>”,所以发生了尾调用优化。


为了验证getaddrinfo是否也是属于尾调用优化这种情况,小编查看了一下getaddrinfo的汇编代码:

(gdb) disassemble getaddrinfo
Dump of assembler code for function getaddrinfo:
   0xff344834 <+0>: mov %o7, %g1
   0xff344838 <+4>: clr %o4
   0xff34483c <+8>: call 0xff3440f0 <_getaddrinfo>
   0xff344840 <+12>: mov %g1, %o7
End of assembler dump.

果然只是调用了_getaddrinfo这个函数,没有压栈,出栈这些操作(SPARC处理器压栈用save指令,出栈用ret,retl指令,具体可参考手册)。小编用下面的DTrace命令测试了一下:

pid$target::getaddrinfo:return
{
    printf("%d", arg0);
}

发现getaddrinfo函数返回时,指令的地址偏移是12,也就是对应的是“ mov %g1, %o7”这条指令,而不是“call 0xff3440f0 <_getaddrinfo>”。小编考虑会不会是由于fbt和pid这两个不同的provider导致的,所以小编又写了个简单的测试脚本,针对dup做个测试(fbt provider没有提供getaddrinfo这个函数):

#!/usr/sbin/dtrace -s
#pragma D option quiet

fbt::dup:return
{
    printf("fbt: %s+0x%x\n", probefunc, arg0);
}
pid$target::dup:return
{
    printf("pid: %s+0x%x\n", probefunc, arg0);
}

结果输出:

fbt: dup+0x10
pid: dup+0x14

说明的确如小编所推测的:对于不同provider,return probe所记录的函数return address是不同的。

综上所述,当遇到return probe记录的函数返回值不对时,需要考虑是不是发生了函数尾调用优化,具体的方法可以参考本文。

补充一下,要想深入地了解DTrace,对DTrace所运行的环境(包括操作系统,CPU体系结构等)可能都要有所了解。在这里,小编推荐两篇讲解SPARC处理器的文章:The SPARC Architecture(http://web.cecs.pdx.edu/~apt/cs577_2008/sparc_s.pdf)和 Understanding stacks and registers in the Sparc architecture(s)(http://www.sics.se/~psm/sparcstack.html)。

如果你对DTrace感兴趣,欢迎关注DTrace公众号(微信号:chinadtrace,博客地址:http://blog.segmentfault.com/chinadtrace),介绍关于DTrace的使用技巧,经验分享,话题讨论等等。也非常欢迎你转发给其它对DTrace感兴趣的朋友。

Understanding stacks and registers in the Sparc architecture.pdf Peter Magnusson的文章,英文版,9页 立即下载

相关推荐

Understanding stacks and registers in the Sparc architecture.doc

The Sparc architecture from Sun Microsystems has some "interesting" characteristics. After having to deal with both compiler, interpreter, OS emulator, and OS porting issues for the Sparc, I decided to gather notes and documentation in one place. If there are any issues you don't find addressed by this page, or if you know of any similar Net resources, let me know. This document is limited to the V8 version of the architecture.

Sparc汇编指令介绍

SPARC是CPU指令集架构的一种,其设计的目标是优化的编译和易用的流水线硬件执行。 SPARC指令集有以下主要特点:     1. 线性的32位地址空间     2. 精简的指令格式 所有指令都是32位宽和以32为分界对齐排列的。只有3个基本指令的格式--它们是非统一的操作数位置和寄存器地址域。特别要注意的是:只有load和store指令能访问memory和I/O。     3. 很少

Macross的专栏 1万+

深入理解JavaScript中的尾调用(Tail Call)

尾调用(Tail Call)是函数式编程的一个重要概念,下面这篇文章主要给大家深入的介绍了关于JavaScript中尾调用的相关资料,文中介绍的非常详细,相信对大家具有一定的参考价值,有需要的朋友们下面来一起看看吧。

尾调用优化 Tail Call optimizations

原文地址:http://www.ruanyifeng.com/blog/2015/04/tail-call.html 一、什么是尾调用? 尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。 function f(x){ return g(x); } 上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。 以下两种情况,都不属于尾调用。 ...

z2664836046的博客 567

FPGA以太网通信实战(一):实现MDIO接口驱动,掌控PHY芯片的钥匙

本文介绍了以太网通信技术及其核心组件。首先概述了以太网的发展历程,从标准以太网(10Mbps)到万兆以太网(10Gbps)的技术演进。重点分析了以太网接口的两大核心部件:MAC控制器负责数据链路层协议处理,PHY芯片负责物理信号转换和连接管理。文章详细解读了MDIO接口规范,包括帧格式和读写时序,并以YT8531 PHY芯片为例,介绍了其寄存器配置方法。最后设计了一个FPGA实现方案,通过MDIO接口完成PHY芯片的软复位和状态监测功能,并利用LED指示灯实时显示网络连接速率。

weixin_64402689的博客 1662

联想拯救者r7000p在ubuntu20.04未找到wifi适配器,安装rtl8852ae网卡驱动问题解决方案

新买的拯救者r7000p 2021款,装完ubuntu20.04之后显示未找到wifi适配器, 更换N次源之后还是只有一个显卡驱动,在网上找了很多方法,再自己折腾了一段时间后,总算是解决了这个问题。 1.设置bios 打开主板系统,将security boot设置为disenable,因为设计到修改内核配置,必须得关掉安全启动。 2.查询网卡状态 使用命令查询网卡(hardware of Internet)状态 lshw -C network 因为是双系统,在Windows下控制面板-设备管理器中可以

MCZ777的博客 1万+

在JavaScript中,什么是尾递归优化(tail call optimization)?

在JavaScript中,什么是尾递归优化(tail call optimization)?

商务合作欢迎私信我 2万+

VSCode+PlatformIO新建工程卡成狗?3步提速大法实测有效(附镜像源配置)

针对VSCode+PlatformIO新建工程时因依赖下载缓慢导致的加载慢问题,本文提供了三步核心提速方案。通过配置Python环境变量、修改PlatformIO插件设置以使用国内镜像源,并优化pip配置文件,实测可大幅缩短工程创建时间,有效解决创建工程卡顿的痛点。

delta的博客 713

[Golang]尾递归优化?

参考 尾调用详解 - 阮一峰 go&plan9 - 曹大 什么是尾调用 ``` func g(n int) { fmt.Println(n) } func f(m int) { m++ g(m) } 在f()函数内最后直接调用g() ``` 尾调用优化 我们把调用函数称作caller,被调用函数称作callee 在程序运行过程中,需要先保存caller现场在栈帧中,然后调用callee

2lovecode blog 1673

LaTeX小白必看:TeX Live+TeXstudio保姆级安装教程(附清华镜像加速)

本文为LaTeX新手提供了一份详尽的TeX Live和TeXstudio安装指南。通过清华大学镜像站实现高速下载,并详细讲解了从下载、定制化安装到配置优化的每一步,帮助用户快速搭建稳定高效的本地LaTeX写作环境,轻松处理学术文档排版。

weixin_29214559的博客 414

多GPU时代的虚拟内存革命:CUDA VMM API的跨设备协同设计哲学

本文深入探讨了NVIDIA CUDA VMM API在多GPU系统中的虚拟内存管理革命,解决了传统Peer Access的显存碎片化和同步开销问题。通过地址-内存解耦、按需映射和精细权限控制,VMM API为分布式训练提供了高效的内存协同方案,显著提升大模型训练性能。

weixin_29251337的博客 535

JavaScript的尾调用优化详解

尾调用优化

qq_21522331的博客 456

【离线OCR】微信离线实现图片OCR文本和表格识别

基于微信本地OCR引擎(由最新版微信自动安装)。通过Python对其官方调用逻辑进行完整翻译和封装,使开发者可以用简单的API调用其强大的OCR功能。

专注于医院数据分析技术与系统开发的创作与分享。 2625

尾调用优化

尾调用(Tail Call)是函数式编程的一个重要概念,本文介绍它的含义和用法。 一、什么是尾调用? 尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。 function f(x){ return g(x); } 上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。 以下两种情况,都不属于尾调用。 // 情况一 functio...

包磊磊的博客 831

基于深度学习的心律失常的自动分类

基于深度学习的心律失常的自动分类 作者:禅与计算机程序设计艺术 1. 背景介绍 1.1 心律失常的危害与检测的重要性 心律失常是一种常见的心血管疾病,严重威胁着人们的健康和生命。据统计,全球每年有数百万人因心律失

AI架构师小马 1146

高通Camx功能feature分析之一:remosaic功能导通

本文详细介绍了S5K3P9S传感器前置场景中SW Remosaic功能的实现流程。首先需在sensorxml中确认支持SW Remosaic类型,并集成remosaic相关库文件(libremosaic_wrapper.so等)。核心实现包括:初始化阶段调用InitFrontSamsungRemosaic();执行线程DeferFrontInitThread()读取校准数据;通过DoSamsungRemosaic()执行remosaic算法处理;最后在析构函数中调用DeinitFrontSamsungRem

1700

什么是尾调用优化?

ES6中的尾调用优化(Tail Call Optimization,TCO)是一种性能优化技术,旨在减少递归函数的内存消耗和执行时间。它允许在满足特定条件时,JavaScript引擎可以重用当前函数的调用栈帧,而不是创建新的栈帧。尾调用是指一个函数的最后一个操作是调用另一个函数,并且该调用返回的结果直接作为当前函数的返回值。在这个例子中,foo函数的最后一个操作是调用bar函数,并将其结果直接返回。尾调用优化是一种有效的性能优化技术,可以帮助减少递归函数的内存消耗和执行时间。

Front end development engineer 2万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

尾调用(Tail Call)优化

尾递归

JiMoKuangXiangQu的专栏 628

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

尾调用(Tail Call)

尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。function f(x){ return g(x); }上面代码中,函数 f 的最后一步是调用函数 g,这就叫尾调用。以下三种情况,都不属于尾调用。// 情况一 function f(x){ let y = g(x); return y; } // ...

文摘资讯 510

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

仓颉语言中的尾递归优化技术解析

尾递归优化(Tail Call Optimization, TCO)是函数式编程和现代编译器设计中的重要技术。它能将递归调用转换为迭代形式,避免栈溢出问题,同时保持代码的声明式风格。仓颉语言作为一门注重性能和安全性的系统编程语言,在编译器层面实现了强大的尾递归优化能力。本文将深入剖析仓颉的尾递归优化机制,并通过实践展示其技术价值。

didididididi007的博客 507

Lua中的尾调用消除(tail-call eliminat)

本文分享Lua中的尾调用消除(tail-call eliminat) 什么是尾调用 在日常Lua的使用中, 我们经常会在一个方法的执行过程中调用其它方法. 在这些方法中, 有一种特殊的形式值得大家注意, 可以做到一定程度上的优化. 这个形式也就是所谓的尾调用, 顾名思义就是一个方法最后的跳出点是一个方法(包括递归调用自己)的调用. 形如return func(args)的形式, 比如下面的例子: function test1() end function test2(xxx) end functio

木头圈 672

强力推荐:Python的尾调用优化解决方案 —— tco库

强力推荐:Python的尾调用优化解决方案 —— tco库 项目简介 在Python的世界里,由于解释器的设计,传统的递归和循环往往受限于栈溢出的风险。而tco库(版本1.2.1)正是为了解决这一痛点应运而生,它致力于实现在Python代码中的尾调用优化(Tail Call Optimization),允许开发者无惧栈深度限制地编写尾递归函数和采用延续传递风格编程。 通过内建的机制,tco库利用P...

gitblog_01159的博客 1021

linux sub减法指令出错,sparc的指令的一些总结

source html:http://linux.chinaunix.net/bbs/archiver/tid-914376.htmlSPARC是CPU指令集架构的一种,其设计的目标是优化的编译和易用的流水线硬件执行。SPARC指令集有以下主要特点:1. 线性的32位地址空间2. 精简的指令格式所有指令都是32位宽和以32为分界对齐排列的。只有3个基本指令的格式--它们是非统一的操作数位置和寄存器...

weixin_42516074的博客 1018

《理解 ES6》阅读整理:函数(Functions)(八)Tail Call Optimization

尾调用优化(Tail Call Optimization) 尾调用是指函数的最后一条语句是函数调用,比如下面的代码: function doSomething() { return doSomethingElse(); } 在ES5中,尾调用和其他形式的函数调用一样:脚本引擎创建一个新的函数栈帧并且压在当前调用的函数的栈帧上面。也就是说,在整个函数栈上,每一个函数栈帧都会...

weixin_34192732的博客 281

dtrace linux_将DTrace探针添加到您的应用程序

Solaris(包括OpenSolaris),FreeBSD和Mac OS X内置的动态跟踪(DTrace)功能为动态跟踪应用程序提供了简单的环境。 与调试不同,DTrace可以随意打开或关闭,并且您无需提供特殊的应用程序构建即可利用跟踪功能。 以上所有平台均支持使用标准DTrace探针。 涵盖了操作系统在代码内不同功能边界上公开的内容。 这些探针(称为功能边界跟踪(FBT))使您可以识别...

cusi77914的博客 1125
上一篇: An experience of fixing a memory-corruption bug (3)
下一篇: 取消gdb退出时提示
一个手艺人
博客等级 码龄16年 20粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值