从汇编层看64位程序运行——likely提示编译器的优化案例和底层实现分析

news2024/11/27 18:44:06

大纲

  • 代码
  • 分析
    • with_attributes::pow
    • no_attributes::pow
    • 分析

我们在《Modern C++——使用分支预测优化代码性能》一文中介绍了likely提示编译器进行编译优化,但是我们又讲了最终优化不是对分支顺序的调换,那么它到底做了什么样的优化,让整体性能提升20%呢?

代码

我们先回顾下代码

#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <random>
#include <functional>
 
namespace with_attributes {
    constexpr double pow(double x, long long n) noexcept {
        if (n <= 0) [[unlikely]]
            return 1;
        else [[likely]]
            return x * pow(x, n - 1);
    }
} // namespace with_attributes
 
namespace no_attributes {
    constexpr double pow(double x, long long n) noexcept {
        if (n <= 0)
            return 1;
        else
            return x * pow(x, n - 1);
    }
} // namespace no_attributes

double calc(double x, std::function<double(double, long long)> f) noexcept {
    constexpr long long precision{16LL};
    double y{};
    for (auto n{0LL}; n < precision; n += 2LL)
        y += f(x, n);
    return y;
}

double gen_random() noexcept {
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_real_distribution<double> dis(-1.0, 1.0);
    return dis(gen);
}
 
volatile double sink{}; // ensures a side effect
 
int main() {
    auto benchmark = [](auto fun, auto rem)
    {
        const auto start = std::chrono::high_resolution_clock::now();
        for (auto y{1ULL}; y != 500'000'000ULL; ++y)
            sink = calc(gen_random(), fun);
        const std::chrono::duration<double> diff =
            std::chrono::high_resolution_clock::now() - start;
        std::cout << "Time: " << std::fixed << std::setprecision(6) << diff.count()
                  << " sec " << rem << std::endl; 
    };
 
    benchmark(with_attributes::pow, "(with attributes)");
    benchmark(no_attributes::pow, "(without attributes)");
    benchmark(with_attributes::pow, "(with attributes)");
    benchmark(no_attributes::pow, "(without attributes)");
    benchmark(with_attributes::pow, "(with attributes)");
    benchmark(no_attributes::pow, "(without attributes)");
}

以及执行效果
在这里插入图片描述

分析

现在我们开始探究性能提升的本质原因。

常言道:代码之前了无秘密。但是对于C++的程序,这个“代码”指的是汇编代码。所以我们需要查看with_attributes::pow和no_attributes::pow的底层实现。

with_attributes::pow

在这里插入图片描述

no_attributes::pow

在这里插入图片描述

分析

我们看到with_attributes::pow和no_attributes::pow在汇编层的实现结构是类似的,但是它们并没有遵从C++代码的结构。因为完全按照C++代码结构进行编译,其结构应该类似于

test   %rdi,%rdi
jle XXXXX_RET_ADDRESS
sub    $0x1,%rdi
movsd  %xmm0,0x8(%rsp)
call pow
……

由于我们开启了o3等级编译优化,所以编译器对with_attributes::pow和no_attributes::pow都进行了优化。

我们分析no_attributes::pow的优化方案:

  • test %rdi,%rdi检测n
  • jle 0x555555555c20 <_ZN13no_attributes3powEdx+112>如果n小于等于0,则跳转到+112位置,即返回1。
  • movapd %xmm0,%xmm1如果n大于0,则将x值放入xmm1寄存器。
  • cmp $0x1,%rdi对比n是否等于1。
  • je 0x555555555c1c <_ZN13no_attributes3powEdx+108>如果n是1,则运行+108位置,即返回x的值。因为pow(x,1)=x* pow(x,0)= x。
  • cmp $0x2,%rdi对比x是否等于2。
  • je 0x555555555c18 <_ZN13no_attributes3powEdx+104>如果n是2,则运行+104位置。它会执行一次x*x(mulsd %xmm1,%xmm0)。这是因为pow(x,2)=x * pow(x,1)= x * x * pow(x, 0) = x * x * 1 = x * x。

后面逻辑以此类推。
在这里插入图片描述

但是当n大于等于5时,逻辑会发生变动:它会递归调用pow(x, n-5),取到结果后再与x进行5次连乘。
在这里插入图片描述

可以发现,这段代码的优化方案是:使用直接操作替代递归调用

再看likely优化后的代码,可以发现它们的结构是一致的。那么为什么likely为什么比没标记过的代码快20%呢?

这是因为likely版本采用了"x的8连乘",这比未标记版本的"x的5连乘"要减少更多的递归调用。
在这里插入图片描述
所以,总结下:本案例中,likely标记版提示编译器做了深度更深的优化,采用直接操作,减少递归调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2099962.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

个人旅游网(5)——功能详解——购物车功能

文章目录 一、设计购物车二、购物车对redis的一系列操作三、购物车3.1、接口详解3.1.1、addCart&#xff08;将当前旅游路线加入到购物车中&#xff09;3.1.2、showCartItem&#xff08;显示刚刚加入购物车的商品&#xff09;3.1.3、findAll&#xff08;将购物车里的所有旅游路…

骨灵冷火!Solon Cloud Gateway 照面发布

骨灵冷火&#xff0c;是练药的好火哟。极冷&#xff0c;又极热。在冰冻中被烧死&#xff1a;&#xff09; 1、认识 Solon Cloud Gateway Solon Cloud Gateway 是基于 Solon Cloud、Vert.X 和 Solon Rx(reactive-streams) 接口实现。小特点&#xff1a; 纯响应式的接口体验流…

KAN学习Day1——模型框架解析及HelloKAN

说明 最近了解到了一个新东西——KAN&#xff0c;我的毕设导师给推荐的船新框架。我看过很多剖析其原理的文章&#xff0c;发现大家对其持有的观点都各不相同&#xff0c;有的说可以颠覆传统MLP&#xff0c;有的说可以和Transformer同等地位&#xff0c;但是也有人说它训练速度…

YoloV8改进策略:IoU改进|Unified-IoU用于高质量对象检测

摘要 Unified-Unified-IoU&#xff08;UIoU&#xff09;是一种新的边界框回归损失函数&#xff0c;旨在改进目标检测任务中的预测框质量&#xff0c;特别是在高IoU阈值和IoU&#xff08;UIoU&#xff09;是一种新的边界框回归损失函数&#xff0c;旨在改进目标检测任务中的预测…

nginx的基本使用示例(负载均衡,虚拟主机,动静分离)的详细配置过程

文章目录 前言前置工作httpd主机tomcat主机 nginx主机配置负载均衡配置过程效果展示 虚拟主机配置过程效果展示 动静分离配置过程 排除思路 前言 本篇博客展示nginx的基本使用案例&#xff0c;后端由httpdtomcat组成&#xff0c;linux版本: rocky9.2 虚拟机ipnginx192.168.10…

安防监控视频打手机检测算法核心技术打手机检测算法源码、模型简介

在数字化的今天&#xff0c;智能手机几乎已成为人们生活中不可或缺的一部分。然而&#xff0c;手机的广泛使用也带来了一些挑战&#xff0c;比如在公共场所、教育机构和工作环境中的手机干扰。为了解决这些问题&#xff0c;打手机检测算法应运而生&#xff0c;成为管理人员和机…

hive学习(六)

一、函数 1.单行函数 特点&#xff1a;输入一行&#xff0c;输出一行&#xff08;一进一出&#xff09; 可分为日期函数&#xff0c;字符串函数&#xff0c;集合函数&#xff0c;数学函数和流程控制函数等 1&#xff09;算术运算函数 2&#xff09;数值函数 --round函数 …

机器学习如何用于音频分析?

机器学习如何用于音频分析&#xff1f; 一、说明 近十年来&#xff0c;机器学习越来越受欢迎。事实上&#xff0c;它被用于医疗保健、农业和制造业等众多行业。随着技术和计算能力的进步&#xff0c;机器学习有很多潜在的应用正在被创造出来。由于数据以多种格式大量可用&…

电赛2024年H题智能小车基于MSPM0G3507主控MCU(利用8路灰度加上MPU6050的解决方式)

一.前言 前段时间&#xff0c;激烈的电赛刚刚结束&#xff0c;很荣幸啊&#xff0c;也是十分的不甘心&#xff0c;本次的湖北赛区H题只拿到了一个省二&#xff0c;看最终的排名&#xff0c;在H题中我们离省一也就差几名。但是整个比赛已经过去了&#xff0c;现在不甘与不舍&…

浏览器按F12进入开发者模式后频繁因为异常而暂停导致无法分析页面xpath

在分析某个内部页面xpath时&#xff0c;遇到一个问题&#xff0c;因为频繁异常而自动暂停导致无法分析页面xpath&#xff0c;如下图&#xff1a; 折腾良久发现把下图右侧的两个抛出异常自动暂停的开关 取消勾选就可以了

微信小程序接入客服功能

前言 用户可使用小程序客服消息功能&#xff0c;与小程序的客服人员进行沟通。客服功能主要用于在小程序内 用户与客服直接沟通用&#xff0c;本篇介绍客服功能的基础开发以及进阶功能的使用&#xff0c;另外介绍多种客服的对接方式。 更多介绍请查看客服消息使用指南 客服视…

2.4 堆栈

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

数据结构——排序【下】

目录 一、计数排序 二、快速排序 三、归并排序 四、八大排序时间复杂度及其稳定性 一、计数排序 计数排序是一个非基于比较的排序算法&#xff0c;元素从未排序状态变为已排序状态的过程&#xff0c;是由额外空间的辅助和元素本身的值决定的。该算法于1954年由 Harold H. S…

Github 2024-09-03 Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-09-03统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10HCL项目1JavaScript项目1Payloads All The Things - 有用的Web应用程序安全负载和绕过列表 创建周期:2639 天开发语言:Python协议…

Go语言?IDEA能支持吗?增删查走起?

序&#xff1a; 最近突然身边突然开始冒出关于go语言的只言片语&#xff0c;很好奇这个go语言是怎么样的&#xff1f;这几天有空就会去网上浏览一遍各位大咖的简介。这边主要是已学习为目的&#xff0c;关键人家都说它好这边记录一下学习过程的进坑和爬坑过程供大家娱乐一下。…

echarts3D地图:旋转、添加纹理图片(vue3)

首先安装echarts和echarts-gl依赖&#xff0c;注意的是&#xff0c;echarts-gl版本需安装低版本&#xff0c;且与echarts5版本不兼容&#xff0c;需要单独安装4版本&#xff0c;这里我安装的4.2.1版本。 $ npm install echarts4npm:echarts4.2.1 echarts-gl1.1.0npm可以安装ec…

帧中继了解

定义 帧中继工作在OSI参考模型的数据链路层&#xff0c;是数据链路层使用简化的方法传送和交换数据单元的一种方式。 帧中继的重要特点之一是将X.25分组交换网中分组节点的差错控制、确认重传、流量控制、拥塞避免等处理过程进行简化&#xff0c;缩短了处理时间&#xff0c;这…

论文速读|通过人类远程操作的深度模仿学习框架:人型机器人的行走操纵技能

项目地址&#xff1a;Deep Imitation Learning for Humanoid Loco-manipulation through Human Teleoperation 本文详细介绍了 TRILL&#xff08;Teleoperation and Imitation Learning for Loco-manipulation&#xff09;框架&#xff0c;它是一个用于人型机器人行走操纵技能训…

华为OD机试真题 - 中文分词模拟器(Python/JS/C/C++ 2024 D卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

Spark-Yarn模式如何配置历史服务器

在Spark程序结束之后我们也想看到运行过程怎么办&#xff1f; Yarn模式下&#xff0c;通过以下步骤配置历史服务器即可: mv spark-defaults.conf.template spark-defaults.conf修改spark-default.conf 文件&#xff0c;配置日志存储路径 spark.eventLog.enabled true spark.…