本文介绍: 这里为了说明效果我们编译时候,并没有采用优化编译优化,确实可以提高程序运行的效率,但是过高的编译优化等级会有一定的副作用,另外编译器优化也具有一定的局限性,高效的代码仍然应该我们追求的目标)。我们知道这里判断一直是0。这样的机器语言由纯粹的0和1构成,十分复杂,不方便阅读修改,也容易产生错误。所以有些情况下,当我们根据实际的情况可以判断出哪条分支可能性更高的时候,我们就可以站在上帝视角给予一定的提示,这样就可以降低分支预测错误,减少CPU的无用功了,从而可以有效的提高性能,同时也节省了功耗。

一.引言

性能优化”,从计算机诞生之初就一直伴随着计算机技术发展,直到现在。将来也必定不会消失。这是因为每个人都会追求性价比,花最少的钱,办最多的事。生活中也一样,就比如说泡茶,但凡有点常识的人都不会先洗茶杯,再去烧水,而是先去烧水,在等水开的过程中,去做洗茶杯等工作。这也是一种优化。

二.访问寄存器代替内存引用

我们先看一个例子

有这么两个程序:它们的目的就是将数组x中的数,按照下标累加到数组y中,最后在把数组y中的数据累加到一个dest里面。为了验证效果,我们将这个过程重复10000遍。

Prog 1 Prog2

两个程序区别就在Prog2中红框里面内容。那么哪个程序运行的更快呢?

话不多说,我们看实际的结果

这里为了说明效果,我们编译时候,并没有采用优化(编译优化,确实可以提高程序运行的效率,但是过高的编译优化等级会有一定的副作用,另外编译器优化也具有一定的局限性,高效的代码仍然应该是我们追求的目标)。可以看到,Prog2要明显比Prog1快。

要想理解上面的例子,我们必须先介绍一下寄存器汇编代码相关知识

1.寄存器

CPU内部用来存放数据的一些小型存储区域, 注意寄存器是在CPU内部,受限于CPU的物理尺寸寄存器数量不会太多。我们只需要记住两点:

1) 寄存器和CPU的L1 cache相比,速度虽然还在一个数量级,但是L1 cache访问速度还是要慢几倍。具体的数据见下文表2

2) CPU只能从寄存器直接取数据或者指令,如果取不到,获取顺序是L1->L2->L3->主存->磁盘

从下文表2中可以看出,如果cpucache访问miss了,性能损失还是很大的。如果内存里面miss了,那对性能来说不亚于一场灾难了。

计算机访问速度分级:

表1 时间单位

以3.3GHz的CPU为例

表2 系统的各种延时

正如你所见,CPU周期的时间非常短,这段时间,光的速度大约只能走0.5米。想象一下,是不是非常震撼?

x86-64 CPU的整数寄存器

我们无需刻意去记住这些寄存器名称,不同架构寄存器的数量和名称也不一样,我们只要知道他们cpu内部的效率极高的存储单元即可

回到前面例子为什么Prog2要比Prog1快,是因为Prog2里面用DEST这个局部变量代替了*dest。DEST是一个局部变量,在汇编指令里是直接访问存器,而*dest需要访问内存cache

2.汇编代码简介

说到汇编语言的产生,首先要讲一下机器语言机器语言机器指令集合。机器指令展开来讲就是一台机器可以正确执行命令电子计算机的机器指令是一列二进制数字计算机将之转变为一列高低电平,以使计算机的电子器件受到驱动,进行运算

上面所说的计算机指的是可以执行机器指令,进行运算的机器。这是早期计算机的概念。在我们常用的PC机中,有一个芯片来完成上面所说的计算机的功能。这个芯片就是我们常说的CPU(Central Processing Unit,中央处理单元)。每一种微处理器,由于硬件设计和内部结构的不同,就需要用不同的电平脉冲来控制,使它工作。所以每一种微处理器都有自己的机器指令集,也就是机器语言

早期的程序设计使用机器语言程序员们将用0, 1数字编成的程序代码打在纸带或卡片上,1打孔,0不打孔,再将程序通过纸带机或卡片输入计算机,进行运算。这样的机器语言由纯粹的0和1构成,十分复杂,不方便阅读修改,也容易产生错误。

程序员们很快就发现了使用机器语言带来的麻烦(何止是麻烦,简直令人发狂),它们难于辨别和记忆,给整个产业发展带来了障碍,于是汇编语言产生了。

汇编语言主体汇编指令汇编指令和机器指令的差别在于指令的表示方法上。汇编指令是机器指令便于记忆的书写格式

我们举个例子看下:

源代码

汇编代码和机器码:

可以看到汇编代码,好歹还有几个能猜出意思的单词

有没有觉得现在的程序员还是挺幸福的。

  资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

3.汇编指令简介

汇编语言是计算机语言的一种,是一种低级语言。相比高级语言,汇编语言更接近底层硬件,使用更加直接,效率更高。但相对而言,汇编语言更加复杂语法更加严格

大多数指令有一个多个操作数,指示出执行一个操作中要使用的源数据值。

操作数一般可以分为三类:

立即数

存器

内存引用

  • 数据传送指令:

最频繁使用的指令,负责将数据从一个位置复制到另一个位置

例如

mov %rbx, %rax : 将rbx存器的值移动到rax存器

mov %rbx, (%rax) : 将rbx存器的值移动到rax存器表示内存地址

以及mov指令的一些扩展指令: movb, movw, movl, movq等等

将数据压入程序栈中,以及从程序栈中弹出数据。

push %rbp : 将%rbp存器的值压入程序指针指向位置

pop %rbp : 将栈指针指向的数据弹出,放入%rbp寄存

导致执行切换程序中一个全新的位置

jmp %rax寄存器%rax中的值作为跳转目标

jmp是无条件跳转,还有一些条件跳转指令,有兴趣的同学可以查一下资料

比较指令CMP,只设置条件码,不更新目的寄存器,其余的行为和SUB指令一致

测试指令TEST,只设置条件码,不更新目的寄存器,其余的行为和ADD指令一致

更多详细的内容,可以通过相关书籍进行系统性的了解,鉴于篇幅,就不多介绍了。

让我们回到刚才的例子,可以看到由于把内存引用替换成了访问寄存器,程序性能就有了明显的提升。

三.帮助提高CPU分支跳转的正确

我们还是先看一个例子:

看上面的两个函数,它们都是calloc一个全零数组x(这里不能直接用数组赋值,否则编译器会足够聪明进行自动的优化),遍历x中的每个数,如果等于0,执行分支A,否则执行分支B。

唯一的不同就是在分支判断时候prog2.c加了likely。我们先看下实际的结果如何

可以看出,加了likelyprog2,明显用时变短。原因何在?

为了理解上面的例子,我们先介绍CPU流水线相关知识:

3.1. CPU流水线简介

CPU流水线是一种使用多级缓存提高处理器性能技术。它是指将CPU操作分为多个阶段每个阶段单独完成一个操作,然后结果传递给下一个阶段,以此类推。每个阶段都有一个独立部件,并且所有部件都能同时处理不同的指令。现代CPU都会采用这种技术来提高CPU的运行效率。

CPU流水线通常包括以下五个阶段

1)取指令(Instruction fetch):从存储器读取指令。

2)指令译码(Instruction decode):将指令转换为可执行的指令。

3)执行指令(Instruction execute):执行指令的操作。

4)写回(Write back):将执行指令得到的结果写回内存中。

5)更新程序计数器(Update program counter):将程序计数器加1,使它指向下一个指令。

举个简单的例子:

我们假设每一个步骤执行时间都是一个时钟周期,那么一条指令执行需要3个时钟周期

CPU 执行指令的3个时钟周期里,取值单元只在第一个时钟周期里工作,其余两个时钟周期都处于空闲状态,其它两个执行单元也是如此,效率太低了。

解决方法就是引入流水线,引入流水线工作模式后可以看到,除了刚开始第一个时钟周期大家还可以偷懒外,其余的时间都不会闲着

CPU流水线的优点是可以同时执行多个指令,从而提高了处理器的效率。但它也存在一些问题例如数据相关性(Data dependency)和控制相关性(Control dependency),这些问题可能导致流水线停滞,降低CPU的性能

执行的程序指令如果是顺序结构,没有中断或跳转,流水线确实可以提高执行效率。但是当程序指令中存在跳转、分支结构时,下面预取的指令可能就要全部丢掉了,需要到要跳转的地方重新取指令执行。一般来说分支预测错误的处罚大约是19个时钟周期。(具体计算方法这里不做详细介绍了)。

我们看下前面提到的例子汇编出来的结果

prog2,这里汇编是”jne”,意思是如果判断结果不为0,就跳转到地址 800 的地方执行。我们知道这里的判断一直是0。所以,cpu指令顺序向下执行,并不会发生预判错误,预取的指令也不会丢弃。这样就不会遭到分支预测错误的惩罚,效率会提高。

所以有些情况下,当我们根据实际的情况可以判断出哪条分支的可能性更高的时候,我们就可以站在上帝视角给予一定的提示,这样就可以降低分支预测错误,减少CPU的无用功了,从而可以有效的提高性能,同时也节省了功耗。

四.总结

从计算机系统的角度来看,性能优化的几个思考方向

1. 尽可能高效的获取数据

2. 尽可能减少CPU的无用功。

3. 尽可能在有限时间内,让CPU干更多的有效的事情。

4. 完成同样的工作任务,尽可能的让CPU少做事。

原文作者内核工匠

原文地址:https://blog.csdn.net/youzhangjing_/article/details/134753910

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_26802.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注