【转】浅谈编译器优化

news/2024/5/18 23:40:28 标签: 编译器, 优化, signal, 汇编, gcc, 多线程

     “memory”比较特殊,可能是内嵌汇编中最难懂部分。为解释清楚它,先介绍一下编译器优化知识,再看C关键字volatile。最后去看该描述符。 
1、编译器优化介绍 
      内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度,以上是硬件级别的优化。再看软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。对常规内存进行优化的时候,这些优化是透明的,而且效率很好。由编译器优化或者硬件重新排序引起的问题的解决办法是在从硬件(或者其他处理器)的角度看必须以特定顺序执行的操作之间设置内存屏障(memory barrier),linux 提供了一个宏解决编译器的执行顺序问题。 
void Barrier(void)
     这个函数通知编译器插入一个内存屏障,但对硬件无效,编译后的代码会把当前CPU寄存器中的所有修改过的数值存入内存,需要这些数据的时候再重新从内存中读出。 


2、C语言关键字volatile 
     C语言关键字volatile(注意它是用来修饰变量而不是上面介绍的__volatile__)表明某个变量的值可能在外部被改变,因此对这些变量的存取不能缓存到寄存器,每次使用时需要重新存取。该关键字在多线程环境下经常使用,因为在编写多线程的程序时,同一个变量可能被多个线程修改,而程序通过该变量同步各个线程,例如: 
DWORD __stdcall threadFunc(LPVOID signal)
{
      int* intSignal=reinterpret_cast<int*>(signal);
      *intSignal=2;
      while(*intSignal!=1)
      sleep(1000);
      return 0;
}
       该线程启动时将intSignal 置为2,然后循环等待直到intSignal 为1 时退出。显然intSignal的值必须在外部被改变,否则该线程不会退出。但是实际运行的时候该线程却不会退出,即使在外部将它的值改为1,看一下对应的伪汇编代码就明白了: 
mov ax,signal    //已经缓冲到寄存器,而寄存器中的值外部线程是无法改变的
label:
if(ax!=1)
goto label
        对于C编译器来说,它并不知道这个值会被其他线程修改。自然就把它cache在寄存器里面。记住,C 编译器是没有线程概念的!这时候就需要用到volatile。volatile 的本意是指:这个值可能会在当前线程外部被改变。也就是说,我们要在threadFunc中的intSignal前面加上volatile关键字,这时候,编译器知道该变量的值会在外部改变,因此每次访问该变量时会重新读取,所作的循环变为如下面伪码所示: 
label:
mov ax,signal  //每次重新从内存读取到寄存器
if(ax!=1)
goto label


3、Memory 
      有了上面的知识就不难理解Memory修改描述符了,Memory描述符告知GCC: 
1)不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕 ;---执行串行化
2)不要将变量缓存到寄存器,因为这段代码可能会用到内存变量,而这些内存变量会以不可预知的方式发生改变,因此GCC插入必要的代码先将缓存到寄存器的变量值写回内存,如果后面又访问这些变量,需要重新访问内存。
     如果汇编指令修改了内存,但是GCC 本身却察觉不到,因为在输出部分没有描述,此时就需要在修改描述部分增加“memory”,告诉GCC 内存已经被修改,GCC 得知这个信息后,就会在这段指令之前,插入必要的指令将前面因为优化Cache 到寄存器中的变量值先写回内存,如果以后又要使用这些变量再重新读取。 
     使用“volatile”也可以达到这个目的,但是我们在每个变量前增加该关键字,不如使用“memory”方便。


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

相关文章

从汇编看函数

一、简介 CPU 中央处理器&#xff0c;内部主要包括寄存器、运算器、控制器。 寄存器&#xff1a;存储数据运算器&#xff1a;处理数据控制器&#xff1a;控制硬件IO口的高低电平x0、x1&#xff1a;存放参数的寄存器w0、w1&#xff1a;是寄存器x0、x1的低32位&#xff0c;使用…

debugserver+lldb使用

一、概述 debugserver、lldb是协同工作的&#xff0c;debugserver依附在APP上&#xff0c;时刻监听APP的运行状态&#xff0c;并有控制APP执行的能力&#xff1b;lldb是在APP外部的&#xff0c;可以和debugserver建立连接&#xff0c;通过debugserver获取APP运行状态&#xff…

状态寄存器

概述 状态寄存器又称cpsr&#xff0c;是cpu运算器的一部分。主要存放两类信息&#xff1a; 1、存放当前指令执行结果的各种状态或条件码&#xff0c;结果是否为负、是否为0、是否进位、是否溢出&#xff1b; 2、存放控制信息&#xff0c;有终端标志位、跟踪标志位。 cpsr寄存器…

java中的Volatile

from:http://blog.sina.com.cn/s/blog_4e736eea01009ira.html Volatile 比同步更简单&#xff0c;只适合于控制对基本变量&#xff08;整数、布尔变量等&#xff09;的单个实例的访问。 当一个变量被声明成 volatile&#xff0c;任何对该变量的写操作都会绕过高速缓存&#xf…

c语言中的宏定义技巧

from:http://blog.21ic.com/user1/2949/archives/2007/35550.html 1&#xff0c;防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2&#xff0c;重新定义一些类型&#xff0c;防止由于各种平台和编译器的不同&#xff0c;而产生的…

合理设置apache httpd的最大连接数

来自&#xff1a;http://hi.baidu.com/rainchen/blog/item/095f0a551fa802c5b645ae46.html 手头有一个网站在线人数增多&#xff0c;访问时很慢。初步认为是服务器资源不足了&#xff0c;但经反复测试&#xff0c;一旦连接上&#xff0c;不断点击同一个页面上不同的链接&#x…

ATT 汇编 (ATT ASM) 参考

AT&TASM开发一个OS&#xff0c;尽管绝大部分代码只需要用C/C等高级语言就可以了&#xff0c;但至少和硬件相关部分的代码需要使用汇编语言&#xff0c;另外&#xff0c;由于启动部分的代码有大小限制&#xff0c;使用精练的汇 编可以缩小目标代码的尺寸。另外&#xff0c;对…

Linux汇编语言开发指南

级别: 初级 肖文鹏 北京理工大学计算机系硕士研究生, 2003 年 7 月 03 日 汇 编语言的优点是速度快&#xff0c;可以直接对硬件进行操作&#xff0c;这对诸如图形处理等关键应用是非常重要的。Linux 是一个用 C 语言开发的操作系统&#xff0c;这使得很多程序员开始忘记在 Li…