编译器优化

第十一章多线程编程的硬件基础与Java内存模型

允我心安 提交于 2020-01-24 23:55:54
高速缓存内部结构示意图 缓存条目的结构 Data Block也被称为缓存行,它是高速缓存与主内存之间的数据交换最小单元,用于存储从主内存中读取或准备写往内存的数据。Tag则包含了与缓存行中数据相应的内存地址的部分信息(内存地址的高位部分比特)。Flag则用于表示响应缓存行的状态信息。 内存地址的解码结果包括tag、index以及offset三部分,index相当于桶号,tag相当于缓存条目的相对编号,offset是缓存行内的位置偏移。 MESI协议中一个缓存条目的Flag值有以下四种可能:Invalid(无效的,记为I)、shared(共享的,记为S),Exclusive(独占的,记为E)和Modified(更改过的,记为M)。 Processor 0读取数据S的实现 Processor 0写数据S的实现 写缓冲器 写缓冲器是处理器内部的一个容量比高速缓存还小的私有高速存储部件。一个处理器无法读取另外一个处理器的写缓冲器中的内容。 内存写操作的执行处理器在将写操作的相关数据写入写缓冲器之后便认为该写操作已经完成,一个处理器接收到其他处理器所回复的针对同一个缓存条目的所有Invalidate Acknowledge消息的时候,该处理器会将写缓冲器中针对相应地址的写操作的结果写入相应的缓冲行中。 无效化队列 引入无效化队列后

深入理解计算机系统(5.1)------优化程序性能

有些话、适合烂在心里 提交于 2020-01-24 04:56:09
  你能获得的对程序最大的加速比就是当你第一次让它工作起来的时候。   在讲解如何优化程序性能之前,我们首先要明确写程序最主要的目标就是使它在所有可能的情况下都能正常工作,一个运行的很快的程序但是却是错误的结果是没有任何用处的,所以我们在进行程序性能优化之前,首先要保证程序能正常运行,且结果是我们需要的。   而且在很多情况下,让程序跑的更快是我们必须要解决的问题。比如一个程序要实时处理视频帧或者网络包,那么一个运行的很慢的程序就不能解决此问题。再比如一个计算任务计算量非常大,需要数日或者数周,如果我们哪怕只是让它运行的快20%也会产生重大影响。 1、编写高效程序的切入点   ①、选择一组合适的算法和数据结构。   ②、编写出编译器能够有效优化以转换成高效可执行的源代码。   ③、多线程并行处理运算。   对于第一点,程序=数据结构+算法,选择合适的数据结构和算法无疑对于提高程序的运行效率有很大的影响。第二点对于编程者则需要理解编译器的优化能力以及局限性,编写程序看上去只是一点小小的改动,可能都会引起编译器优化方式很大的变化;第三点技术主要这对运算量特别大的运算,我们将一个大的任务分成多个小任务,这些任务又可以在多核和多处理器的某种组合上并行的计算,这里我们也需要知道,即使是利用并行性,每个并行的线程都要以最高性能的方式执行。 2、编译器的优化能力和局限性   正确性,正确性

内存模型

你说的曾经没有我的故事 提交于 2020-01-24 03:52:45
在 C++11 标准中,一个重大的更新就是引入了 C++ 多线程内存模型。本文的主要目的在于介绍 C++ 多线程内存模型涉及到的一些原理和概念,以帮助大家理解 C++ 多线程内存模型的作用和意义。 1. 顺序一致性模型 (Sequential Consistency) 在介绍 C++ 多线程模型之前,让我们先介绍一下最基本的顺序一致性模型。对多线程程序来说,最直观,最容易被理解的执行方式就是顺序一致性模型。顺序一致性的提出者 Lamport 给出的定义是: “… the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program.” 从这个定义中我们可以看出,顺序一致性主要约定了两件事情: (1). 从单个线程的角度来看,每个线程内部的指令都是按照程序规定的顺序 (program order) 来执行的 ; (2). 从整个多线程程序的角度来看

[你必须知道的.NET]第三十五回,判断dll是debug还是release,这是个问题

拥有回忆 提交于 2020-01-21 02:17:07
问题的提出 晚上翻着群里的聊天,发现一个有趣的问题:如何通过编码方式来判断一个dll或者exe为debug build还是release build?由于没有太多的讨论,所以我只好自己找点儿办法,试图解决这个问题,为夜生活带点刺激。于是,便有了本文的探索和分析。 当然,为了充分的调动起大家的主意,省去不必要的google操作,我觉得有必要对Debug和Release两种模式的异同进行一点提纲挈领式的分析,从而为接下来的解决方案打好基础。 Debug & Release 我们应用Visual Studio对代码文件进行F5操作(Build)时,实际是发生了一系列语法检查、词法检查和编译过程,通常情况下我们有两种Build模式,这就是常说的Debug Build和Release Build。望文知意,Debug Build模式通常应用于开发时,便于调试反馈;而Release Build则应用于部署时,这是因为Release模式下,编译器做了很多的优化操作(代码冗余、循环优化等),省去了对调试信息的记录。因此,两种Build模式是各不相同的,我们对其二者进行一点总结如下: Debug用于开发时,Release用于部署时。 Debug模式下,将产生pdb文件,用于保存状态信息和调试信息;Release模式下,不产生调试信息,也没有pdb文件。 Debug模式下,System

C/C++中volatile关键字详解

拥有回忆 提交于 2020-01-17 05:18:36
1. 为什么用volatile? C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier 。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明: A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided. volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法: int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如: 1 volatile int i=10; 2 int a = i; 3 ... 4 // 其他代码,并未明确告诉编译器,对 i

volatile的使用

微笑、不失礼 提交于 2020-01-16 06:51:12
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去预先假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地 重新 读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 1). 一个参数既可以是const还可以是volatile吗?解释为什么。 2). 一个指针可以是volatile 吗?解释为什么。 3). 下面的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; } 下面是答案: 1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变

C++中的volatile关键字

本小妞迷上赌 提交于 2020-01-16 04:32:21
原文: http://www.cnblogs.com/Chase/archive/2010/07/05/1771700.html volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。 volatile的本意是“易变的”,不过翻译成“直接存取原始内存地址”更为合适。“易变”是因为外在因素引起的,象多线程,中断等,并不是因为用volatile修饰了的变量就是“易变”了,假如没有外因,即使用volatile定义,它也不会变化。 使用该关键字的例子如下: int volatile nVint;//当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 对于这样的代码: volatile int i = 10; int a = i; ... //其他代码,并未明确告诉编译器,对i进行过操作 int b = i; volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取

volatile的作用

柔情痞子 提交于 2020-01-14 08:51:29
[转] http://blog.21ic.com/user1/2949/archives/2007/35599.html   一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 1). 一个参数既可以是const还可以是volatile吗?解释为什么。 2). 一个指针可以是volatile 吗?解释为什么。 3). 下面的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; }

GCC,LLVM,Clang编译器对比

被刻印的时光 ゝ 提交于 2020-01-14 08:03:09
本文转载自 https://www.cnblogs.com/qoakzmxncb/archive/2013/04/18/3029105.html 在XCode中,我们经常会看到这些编译选项(如下图),有些人可能会有些茫然,本文将对GCC4.2、LLVM GCC 4.2、LLVM compliler 2.0三个编译选项进行一个详细的介绍。 GCC GCC(GNU Compiler Collection,GNU 编译器 套装),是一套由 GNU 开发的编程语言编译器。它是一套以 GPL 及 LGPL 许可证所发行的自由软件,也是 GNU计划的关键部分,亦是自由的类Unix及苹果电脑 Mac OS X 操作系统 的标准编译器。 GCC 原名为 GNU C 语言编译器,因为它原本只能处理 C语言。GCC 很快地扩展,变得可处理 C++。之后也变得可处理 Fortran、Pascal、 Objective-C 、Java, 以及 Ada与其他语言。 LLVM LLVM 是 Low Level Virtual Machine 的简称,这个库提供了与编译器相关的支持,能够进行程序语言的编译期优化、链接优化、在线编译优化、代码生成。简而言之,可以作为多种语言编译器的后台来使用。如果这样还比较抽象的话,介绍下 Clang 就知道了:Clang 是一个 C++ 编写、基于 LLVM、发布于 LLVM

volatile的作用

淺唱寂寞╮ 提交于 2020-01-13 09:48:31
volatile的作用 标签: 生活 2010-09-17 10:29 星期五   volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。   使用该关键字的例子如下:   int volatile nVint;   >>>>当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。   例如:   volatile int i=10;   int a = i;   ...   //其他代码,并未明确告诉编译器,对i进行过操作   int b = i;   >>>>volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。   >>>>注意,在vc6中,一般调试模式没有进行代码优化