精华内容
下载资源
问答
  • 个指令执行被分成:取指、译码、访存、执行、写回等若干个阶段。然后,多条指令可以同时存在于流水线中,同时被执行。 指令流水线并不是串行,并不会因为个耗时很长指令在“执行”阶段耗时很长时间,而...


    先附上思维导图,本篇重点介绍指令重排序,主要为了下篇的as-if-serial和happens-before规则。
    在这里插入图片描述

    1 为什么需要指令重排序?

    现在的CPU一般采用流水线来执行指令。一个指令的执行被分成:取指、译码、访存、执行、写回等若干个阶段。然后,多条指令可以同时存在于流水线中,同时被执行。
    指令流水线并不是串行的,并不会因为一个耗时很长的指令在“执行”阶段耗时很长时间,而导致后续的指令都卡在“执行”之前的阶段上。我们编写的程序都要经过优化后(编译器和处理器会对我们的程序进行优化以提高运行效率)才会被运行,优化分为很多种,其中有一种优化叫做重排序,重排序需要遵守as-if-serial规则和happens-before规则,重排序的目的是为了提升性能

    2 重排序的分类

    1. 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序;
    2. 指令级并行的重排序。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序;
    3. 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行的。

    3 重排序的过程

    在这里插入图片描述如图,1属于编译器重排序,而2和3统称为处理器重排序。这些重排序会导致线程安全的问题,一个很经典的例子就是DCL(双重检验锁)问题,这个在以后的文章中会具体去聊。针对编译器重排序,Java内存模型(JMM)的编译器重排序规则会禁止一些特定类型的编译器重排序;针对处理器重排序,编译器在生成指令序列的时候会通过插入内存屏障指令来禁止某些特殊的处理器重排序

    4 重排序对多线程的影响

    先看以下一段代码:

    /**
     * @author Carson
     * @date 2020/5/28 20:07
     */
    public class ReorderService {
        private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("ReorderService-%d").build();
    
        private static ExecutorService executorService = new ThreadPoolExecutor(5, 20, 1000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
    
        public static void main(String[] args) {
            final ReorderModel model = new ReorderModel();
            int counter=5;
            for (int i = 0; i < counter; i++) {
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        model.writer();
                    }
                });
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        model.reader();
                    }
                });
            }
        }
    }
    
    class ReorderModel {
        private int a = 0;
        private boolean flag = false;
    
        void writer() {
            //操作1
            a = 1;
            //操作2
            flag = true;
        }
    
        void reader() {
            //操作3
            if (flag) {
                //操作4
                int i = a * a;
                System.out.println(i);
            } else {
                System.out.println("少侠露飞");
            }
        }
    }
    

    flag为标志位,表示a有没有被写入,当A线程执行 writer 方法,B线程执行 reader 方法,线程B在执行4操作的时候,能否看到线程A对a的写入操作?少侠先不做出回答,实践才是检验真理的唯一标准,让我们跑起代码看看结果。
    我们进行了五次循环输出,结果每次都不尽相同,这里贴出其中一次的运行结果:

    1
    1
    1
    少侠露飞
    1

    所以对于上述问题,答案已经很明显了。但这是为什么呢?
    实际上由于操作1和操作2没有数据依赖关系,编译器和处理器可以对这两个操作重排序
    如果操作1和操作2做了重排序,程序执行时,线程A首先写标记变量 flag,随后线程 B 读这个变量。由于条件判断为真,线程 B 将读取变量a。此时,变量 a 还根本没有被线程 A 写入,在这里多线程程序的语义被重排序破坏了!

    5 数据依赖性

    如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。数据依赖分下列三种类型:

    名称 代码示例 说明
    写后读 a = 1;b = a; 写一个变量之后,再读这个变量。
    写后写 a = 1;a = 2; 写一个变量之后,再写这个变量。
    读后写 a = b;b = 1; 读一个变量之后,再写这个变量。

    注意,这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

    点点关注,不会迷路

    展开全文
  • 指令流出Notes2

    2020-05-25 12:07:50
    超标量结构对程序员透明,处理机自动检测下一条指令能否流出 2.即使没有经过编译器优化也能运行代码,但效果不好。 静态调度多指令流出技术: 指令按序流出,流出时进行冲突检测、结构冒险等。 在当前指令序列...

    多指令流出技术【Notes2】

    两种风格:
      超标量 和 VLIW/EPIC
      1.超标量结构对程序员透明,处理机自动检测下一条指令能否流出
      2.即使没有经过编译器优化也能运行代码,但效果不好。
    
    静态调度的多指令流出技术:
     指令按序流出,流出时进行冲突检测、结构冒险等。
     在当前指令序列中对比已经在执行的指令进行检测,操作较复杂 
     一般分两个阶段:1.对于序列内检测。2.对于序列外检测。
     限制因素:1.Load指令  2.分支延迟
    
    动态多指令流出技术:

    性能受3个因素影响:

    1. 整数部件和浮点部件工作负载不平衡
    2. 每个循环迭代中控制开销大
    3. 控制相关使得处理器等到分支指令执行完之后才能开始下一条Load指令的执行。

    Memory hieraychy

    虚拟存储器优点:1效率高,2 可运行占内存大的程序,3运行速度快
    分层的存储器,cache等

    展开全文
  • Linux 存储管理3——地址映射全过程

    千次阅读 2013-05-20 19:46:02
    假定一条程序已经运行,整个映射机制都已建立好,并且cpu正在执行main()中:call 08048368 这条指令,要转移到虚拟地址0x08048368去。接下来我们分析整个地址映射过程: 首先是段式映射阶段。由于地址0x...

    假定一条程序已经运行,整个映射机制都已建立好,并且cpu正在执行main()中的:call 08048368 这条指令,要转移到虚拟地址0x08048368去。接下来我们分析整个地址映射的过程:

    首先是段式映射阶段。由于地址0x08048368是一个程序的入口,更重要的是在执行的过程中是由cpu中的“指令指针寄存器(用于存储下次将要执行的指令在代码段中的偏移量)”EIP所指向的代码段中。因此i386 CPU使用代码段寄存器CS的当前值来作为段式映射的“选择码”,也就是用它作为在段描述表中的下标。

    什么是段描述表呢?什么是全局段描述表GDT?什么是局部段描述表LDT?

    我们先回顾一下保护模式下段寄存器的格式:


    也就是说,bit2(TI=Table Indicator:指示器)为0时表示用GDT,为1时表示用LDT。intel的设计意图是内核用GDT而各个进程都用其自己的LDT,最后两位RPL为所要求的特权级别,分为4个级别,0为最高级。(一般内核为0级,用户未3级)

    现在可以来看看CS的内容了,内核在建立一个进程时都要将其段寄存器设置好,有关代码如下:


    这里reg->xds 是段寄存器DS的映像,一次类推,这里可以看到一个有趣的事,就是除了CS被置成USER_CS之外,其他所有的段寄存器都设置成USER_DS,你看,比如堆栈寄存器SS,也被设置成了USER_DS,这说明了什么呢?这说明:虽然Intel的意图是将一个进程映像分成代码段、数据段、和堆栈段,但是,linux内核却并不买这个帐,在linux中堆栈段和数据段式不分的。

    上面说寄存器的映像,被设置成了USER_CS和USER_DS到底是什么:


    也就是说,Linux内核中只使用四种不同的段寄存器数值,两种用于内核本身,两种用于所有的进程。现在我们讲这四种数值用二进制展开并与段寄存器的格式相对照:


    首先TI都是0,也就是说全部使用GDT。这就与Intel的设计意图不一致了。实际上,在Linux内核中基本上不使用局部段描述表LDT。LDT只是在VM86模式中运行wine以及其它在Linux上模拟Windows软件或DOS软件的程序中才使用。

    再看RPL,只用了0和3两级,内核为0级而用户(进程)为3级。

    回到我们的程序中。我们的程序显然不是内核程序,所以在进程的用户空间运行,内核在调度该进程进入运行时,把CS设置成_USER_CS即0x23。所以,CPU以4为下标,从全局扫描表GDT中找对应的段描述项








    展开全文
  • 计算机系统漫游 1、并发和并行 并发:指一同时具有多活动的系统 并行:指的是用并发来使一系统运行的更快。 2、计算机三层次实现并发和并行 (1)线程级并发 (2)指令级并行 ...允许一条指令产生多...

    计算机系统漫游

    1、并发和并行
    并发:指一个同时具有多个活动的系统
    并行:指的是用并发来使一个系统运行的更快。

    2、计算机三个层次实现并发和并行
    (1)线程级并发
    (2)指令级并行
    通过借助于流水线(pipelining)技术,将执行一个指令所需要的活动划分为不同的步骤,将处理器的硬件组织成一系列的阶段,每一个阶段执行一个步骤,这些阶段可以并性地操作。
    (3)单指令、多数据并行
    允许一条指令产生多个可以并行执行的操作
    3、抽象概念很核心
    抽象使人不需要关注计算机底层的硬件和操作系统的复杂性。文件是对IO设备的抽象表示,虚拟内存是对主存和磁盘IO设备的抽象表示,进程是对处理器、主存和IO设备的抽象表示。
    4、局部性原理
    包括时间局部性和空间局部性,如果写的代码能够符合局部性原理,则执行效率也能提升不少,下面给一个体现空间局部性的例子。

    写代码的时候,很多时候优化措施就是利用了局部性原理,只是没有明确地用这个概念来说,比如加缓存就是利用了局部性原理。

    	public class SolutionTest {
    
        public static void main(String[] args) {
            int size = 10000;
            int[][] arr = new int[size][size];
    
            int sum = 0;
            long start = System.currentTimeMillis();
            for(int i = 0; i < size; i++) {
                for(int j = 0; j < size; j++) {
                    sum += arr[i][j];
                }
            }
            // 按行遍历二维数组花费110ms
            System.out.println((System.currentTimeMillis() - start));
    
            sum = 0;
            start = System.currentTimeMillis();
            for(int i = 0; i < size; i++) {
                for(int j = 0; j < size; j++) {
                    sum += arr[j][i];
                }
            }
            // 按列遍历花费实现2100ms
            System.out.println((System.currentTimeMillis() - start));
        }
    
    }
    

    手动跑上面的程序,可见按行遍历的时间明显比按列遍历花费的时间少的多。因为对于多维数组,在内存中数组是按行顺序存储的,按行遍历明显符合空间局部性。

    5、随机访问存储器
    (1)SRAM(静态随机访问存储器)
    常用与计算机的高速缓存部分,是非易失性的存储器,只要有点,它就会永远保持它的值。
    (2)DRAM(动态随机访问存储器)
    易失性,数据需要周期性的通过读出,重写来刷新内存的每一位,SRAM单元比DRA单元需要更多的晶体管。
    (3)增强型的DRAM

    • 快页模式DRAM(Fast Page Mode DRAM,FPM DRAM)
      对同一行的连续访问可以直接从行缓存区得到服务
    • 扩展数据输出DRAM(Extended Data Out DRAM, EDO DRAM)
      和FPM DRAM类似,只是让CAS信号在时间上更紧密些
    • 同步DRAM(Synchronous DRAM, SDRAM)
    • 双倍数据速率同步DRAM(Double Data-Rate Synchronous DRAM, DDR SDRAM)
      是对SDRAM的一种增强,通过使用两个时钟沿作为控制信号,从而使DRAM的速度翻倍,后面还有DDR、DDR2、DDR3、DDR4等(用提高有效带宽的很小的预取缓存区的大小来划分的)。

    6、磁盘存储
    (1)磁盘构造

    • 盘片
    • 表面(每个盘片有两个表面)
    • 磁道(每个表面上有非常多的磁道)
    • 扇区(每个磁道又可以划分为非常多的扇区)

    每个磁道上的扇区数是相同的,而每个扇区数存放的位数也是相同的,这样计算总的存储非常方便

    展开全文
  • 有这样一条指令: <code>os/src/interrupt/interrupt.asm</code></p> <pre><code> mv sp, a0 </code></pre> 这是从<code>handle_interrupt</code> 中返回值<code>a0中读取<code>sp</code>,而...
  • 深入理解计算机系统

    2019-09-17 21:57:17
    从程序计数器PC指向存储器读取指令,解释指令中位,执行指令指示简单操作,然后更新指向新程序计数器一条指令 3.CPU在指令要求下可能会执行这些操作 3.上下文 操作系统保存进程运行所需...
  • 入门学习Linux常用必会60命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    hda1中“1”代表hda一个硬盘分区 (partition),hda2代表hda第二主分区,第一个逻辑分区从hda5开始,依此类推。此外,可以直接检查 /var/log/messages文件,在该文件中可以找到计算机开机后系统已辨认出来...
  • 为建立一名为commandbctest广播传输,之后输入内容,以\n为一条完整指令,转发到所有监听广播连接 sendcmdbc commandbctest 1234567890test 为给名为commandbctest广播发送单条指令 内容为 1234567890test,...
  • 本节书摘来自华章社区...1.3.1 程序(指令序列)在硬件上的运行过程任何一条指令的执行过程都可以分为以下三个阶段:1)取指令阶段(类似于理想厨房通过三条传送带到冰箱中取一个加工步骤):控制单元负责根据PC...
  • 个阶段发展迅速,互联网应用趋于多样化,其中变化最大是由web 1.0网站创造内容时代变为由用户创造内容web 2.0时代。 在web 2.0应用中,博客(Blog)是web 2.0核心应用中最典型、最流行代表之,也是web ...
  • 6 流水线处理器题库

    千次阅读 2019-02-17 11:16:24
    1、MIPS五级流水线结构中,计算访存地址是在哪个...指定运行一段5条指令的代码,在流水线不停顿情况下,需要 9ns 参考: 需要5+(5-1)=9时钟周期 每秒有1G时钟周期 9时钟周期需要 9 * 1/1G =...
  • 一般说来,数字系统中运行的电信号,其大小往往并不改变,但在实践分布上 却有着严格的要求,这是数字电路的一个特点。 2 系统的总体设计: 2.1 原理设计 本频率计的设计以AT89S52 单片机为核心,利用它内部的定时/...
  • 说明 : 指定在一个共享服务器环境中可同时运行的共享服务器进程的最大数量。 值范围: 根据操作系统而定。 默认值 : 20 dispatchers: 说明 : 为设置使用共享服务器的共享环境而设置调度程序的数量和类型。可以为该...
  • c语言编写单片机技巧

    2009-04-19 12:15:17
    而汇编语言,一条指令就对应一机器码,每一步执行什幺动作都很清楚,并且程序大小和堆栈调用情况都容易控制,调试起来也比较方便。所以在单片机开发中,我们还是建议采用汇编语言比较好。 如果对单片机C语言有...
  • 初学MMX与SIMD

    2012-12-24 17:29:34
    因项目需要,本学期继学习和应用了cuda和openMP... 简单来说,Intrinsic将MMX和SSE,SSE2,SSE3,SSE4的一条或多条汇编指令封装成C/C++函数格式,即通过函数调用和参数传递实现我们想要功能。在编译阶段,这些Intrin
  • C#微软培训教材(高清PDF)

    千次下载 热门讨论 2009-07-30 08:51:17
    C#--微软.NET语言 本书着重介绍语言本身,比较少涉及应用,不错入门书,从头讲起,不怕不明白。 <<page 1>> page begin==================== 目 目目 目 录 录录 录 第部分 C#语言概述.4 ...
  • C#微软培训资料

    2014-01-22 14:10:17
    一个一 一个可 可可 可 以互相交换组件地方 以互相交换组件地方以互相交换组件地方 以互相交换组件地方 比尔 比尔比尔 比尔.盖茨 盖茨盖茨 盖茨 在本章中你将了解 Microsoft.NET ...
  • 2-16 已知x、y两变量,写一条简单if语句,把较小的的值赋给原本值较大变量。 解: if (x > y) x = y; else // y > x || y == x y = x; 2-17 修改下面这程序中错误,改正后它的运行结果是什么? #include ...
  • (26) 下面不属于软件工程的3个要素的是______。(D) A. 工具 B. 过程 C. 方法 D. 环境 (27) 程序流程图(PFD)中的箭头代表的是______。(B) A. 数据流 B. 控制流 C. 调用关系 D. 组成关系 (28) 在数据管理技术的发展...
  • 软件测试规范

    2018-04-23 09:16:12
    .概述 ............................................................................................................................................................ 1 二 软件测试理论 ....................
  • 而在章内部,项大功能被分解成许多小步骤,通过完成每步骤,读者可以不断获得阶段成果,从而让整个开发过程变得轻松并且有趣。 本书适合各类程序员、程序开发爱好者阅读,也可作为高等院校操作...
  • 而在章内部,项大功能被分解成许多小步骤,通过完成每步骤,读者可以不断获得阶段成果,从而让整个开发过程变得轻松并且有趣。 本书适合各类程序员、程序开发爱好者阅读,也可作为高等院校操作...
  • asp.net知识库

    2015-06-18 08:45:45
    .NET关于string转换的一个小Bug Regular Expressions 完整在.net后台执行javascript脚本集合 ASP.NET 中正则表达式 常用匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎...
  • 搭建集群方式(3主3从,3个主机搭起主服务集群,3个从机防止,主服务挂掉,从服务顶上) 注意,修改 redis.conf 配置和单点唯一区别是下图部分,其余还是常规这几项: port 9001(每个节点端口号) daemonize ...
  • 嵌入式软件测试工具--LOGISCOPE

    热门讨论 2008-10-13 00:23:49
    表示约定(如:每行一条指令); 限制(如:不能用GOTO 语句,不能修改循环体中计数器等)。用户可以从这些规则中选择,也可以用Tcl 、脚本和编程语言定义新规则。此外,还提供50 面向安全-关键系统编程规则...
  • (26) 下面不属于软件工程的3个要素的是(D) 注:P62 A. 工具 B. 过程 C. 方法 D. 环境 (27) 程序流程图(PFD)中的箭头代表的是(B) 注:P81 A. 数据流 B. 控制流 C. 调用关系 D. 组成关系 (28) 在数据管理技术的发展...
  • 数控车床仿真模拟软件

    热门讨论 2011-08-18 14:05:15
    在使用了刀偏后的第一条指令请勿省略参数。 2.刀具轨迹显示功能是以红色线代表,如果要显示刀具必须关闭此项功能。 3. 在代码的运行的过程中尽量不要使程序刷新画面,否则可能会影响工件的加工。 4. 在手动点动...
  • 会计理论考试题

    2012-03-07 21:04:40
    A、计算机病毒通常是段可运行的程序 B、反病毒软件可清除所有病毒 C、加装防病毒卡的微机不会感染病毒 D、病毒不会通过网络传染 14.在Windows98中,如果删除了软盘上的文件,则该文件在Windows98中___A____。 A、...
  • iPhone开发秘籍(第2版)--源代码

    热门讨论 2012-12-11 13:51:22
    8.2 秘诀:添加一个简单直观操作界面 240 8.3 秘诀:限制移动 241 8.4 秘诀:测试触摸 242 8.5 秘诀:测试位图上触摸 243 8.6 秘诀:向直接操作界面添加持久性 246 8.6.1 存储状态 246 8.6.2 恢复状态 ...

空空如也

空空如也

1 2 3
收藏数 46
精华内容 18
关键字:

一条指令运行的3个阶段