SimpleScalar分析

摘要:
Sim-safe是simplescalar中的一个模拟器,它会在指令的执行时检查指令的齐整性,检查访存指令的合法性等一些安全性检查。Sim-bpred实现一个分支预测分析器。断点文件可被用于在程序运行中启动simplescalar模拟器。

1.编写测试程序

#include <stdio.h>

int main()

{

printf("Hello world!\n");

return 0;

}

2.编译程序

bin/sslittle-na-sstrix-gcc hello.c

含义:用simplescalar的编译器对hello.c进行编译,以生成能够在模拟器中运行的可执行文件,此条命令将hello.c编译成a.out.这种可执行文件并不是通常意义下的可执行文件,它的可执行性是相对于模拟器程序而已的。(在这里我们猜测生成的可执行文件默认为a.out,因为在下条指令中,我们试着把a.out改为其他的名字,都无法找到文件回答:是的a.out是默认生成的,bin/sslittle-na-sstrix-gcc hello_world.c -I/usr/include -o hello_world.out类似的命令是可以生成相应名字的out文件的。在一般的模拟器中,尤其是开源的,生成的文件名都是a.out,如NS-2

3.模拟运行

simplesim-3.0/sim-safe a.out

含义:用sim-safea.out进行模拟运行。Sim-safesimplescalar中的一个模拟器,它会在指令的执行时检查指令的齐整性,检查访存指令的合法性等一些安全性检查。

4.仿真结果

sim_num_insn 7942 # total number of instructions executed //执行的全部指令的条数

sim_num_refs 4337 # total number of loads and stores executed //执行的装载和存储的指令条数

sim_elapsed_time 1 # total simulation time in seconds //模拟时间

sim_inst_rate 7942.0000 # simulation speed (in insts/sec) //没秒钟执行的指令书,在这个测试程序中没有意义,因为指令数太少,大概可以达到每秒80万左右

ld_text_base 0x00400000 # program text (code) segment base //程序所在的代码段的基地址

ld_text_size 70128 # program text (code) size in bytes //原程序大小,byte为单位

ld_data_base 0x10000000 # program initialized data segment base //程序初始化时的数据段地址

ld_data_size 8304 # program init'ed `.data' and uninit'ed `.bs s' size in bytes //数据段大小

ld_stack_base 0x7fffc000 # program stack segment base (highest addres s in stack) //程序在堆栈段的基址

ld_stack_size 16384 # program initial stack size //程序所占用的堆栈段大小

ld_prog_entry 0x00400140 # program entry point (initial PC) //程序入口地址(初始化PC)

ld_environ_base 0x7fff8000 # program environment base address address

ld_target_big_endian 0 # target executable endian-ness, non-zero if big endian

mem.page_count 26 # total number of pages allocated //分配给程序的全部页数

mem.page_mem 104k # total size of memory pages allocated //分配个程序的全部内存页的大小

mem.ptab_misses 26 # total first level page table misses //未命中目录表总数

mem.ptab_accesses 488676 # total page table accesses //访问的目录表总数

mem.ptab_miss_rate 0.0001 # first level page table miss rate //页面失效率

5.交叉编译的概念

交叉编译:简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓平台,实际上包含两个概念:体系结构(Architecture)、操作系统(Operating System)。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。在进行嵌入式系统的开发时,运行程序的目标平台通常具限的存储空间和运算能力,比如常见的ARM平台,其一般的静态存储空间大概是16到32 MB,而CPU的主频大概在100MHz到500MHz之间。这种情况下,在ARM平台上进行本机编译就不太可能了,这是因为一般的编译工具链(compilation tool chain需要很大的存储空间,并需要很强的CPU运算能力。为了解决这个问题,交叉编译就应运而生了。通过交叉编译工具,我们就可以在CPU能力很强、存储控件足够的主机平台上(比如PC上编译出针对其他平台的可执行程序。

6.SimpleScalar几个工具的介绍

现以sim-fast工具为例,来介绍一下模拟程序的流程:

(1)Sim-fast

Sim-fast是执行速度最快,最不关心模拟过程细节信息的子模拟器程序。它采用顺序执行指令的方式,没有指令并行;不支持cache的使用,也不进行指令正确性检查,由程序员保证每条指令的正确性;不支持模拟器本身内嵌的Dlite!调试器(类似于gdb调试器)。为了模拟器的速度优化,在缺省情况下,sim-fast模拟器不进行时间统计,不对指令的有关信息(如指令总数及访存指令数目)进行统计。当然,可以修改模拟器源程序,通过改变其设置,使模拟器更加符合设计人员的需求。

(2)Sim-safe

在工具集中,是最简单的最友好的模拟器,检查所有的指令错误,不讲究速度。

3Sim-bpred

实现一个分支预测分析器。

4Sim-cache

这个工具实现cache模拟功能,为用户择的cache和快表设置生成cache统计,其中可能包含两级指令和数据cache,还有一级指令和数据快表,不会生成时间信息。

(5)Sim-eio

这个模拟器支持生成外部事件跟踪(EIO traces)和断点文件。外部事件跟踪俘获程序的执行,并且允许被打包到一个单独的文件,以备以后的再次执行。这个模拟器也提供在外部事件跟踪执行中在任意一点做断点。断点文件可被用于在程序运行中启动simplescalar模拟器。

6Sim-outorder

最完整的工具。支持依序和乱序执行,branch predictor,memory hierarchy,function unit个数等参数设定。这个模拟器追踪潜在的所有流水(pipeline)操作。

(7)Sim-profile

也叫functional simulation,但提供较完整的模拟参数,可依照使用者之设定,决定所要模拟之项目,如instruction classes and addresses、text symbols、memory accesses、branches and data segment symbols以方便使用者整理收集数据材料。

6.SimpleScalar Simulator模拟程序流程分析

SimpleScalar的仿真流程图:

模拟器初始化->执行模拟->结束处理

现以sim-fast工具为例,来介绍一下模拟程序的流程:

Sim-fast是执行速度最快,最不关心模拟过程细节信息的子模拟器程序。它采用顺序执行指令的方式,没指令并行;不支持cache的使用,也不进行指令正确性检查,由程序员保证每条指令的正确性;不支持模拟器本身内嵌的Dlite!调试器(类似于gdb调试器。为了模拟器的速度优化,在缺省情况下,sim-fast模拟器不进行时间统计,不对指令的相关关信息(如指令总数及访存指令数目进行统计)。当然,可以修改模拟器源程序,通过改变其设置,使模拟器更加符合设计人员的需求。

(1)模拟器初始化

模拟器执行的入口点是hello.c文件中定义的main(主函数)。当模拟器开始执行时,首先执行模拟器初始化工作,它主要包括:

1、显示版本信息;

2、处理用户对模拟器的配置项。simplescalar模拟器提供了许多项供用户设置,如配置cache的大小及结构、前瞻执行策略的选择等,从而方便用户得到关心的信息;

3、存储器的初始化。simplescalar模拟器提供了2GB的虚存空间,用来存放被模拟程序的指令段和数据段等。执行初始化后,被模拟程序的目标代码全部载入模拟器的内存中;

4、寄存器初始化。simplescalar提供了32个整数、32个单精度浮点和16个双精度浮点寄存器,另有六个控制寄存器。

5、相应子模拟器的初始化。五个子模拟器的初始化复杂程度不一,实现的功能也不尽相同。

(2)执行模拟

运行时模拟器的sim-main(函数):首先将被模拟程序的全部正文段译码,然后从程序的入口点处开始执行模拟。Sim_main(程序)是每个子模拟器运行的核心部分。Sim-fast中sim_main(函数)的主要工作是:

1、从模拟器的内存空间中取一条在前面主程序中存入的指令;

2、分析指令代码;

3、执行指令,并在执行过程中,依据用户的配置,将用户关心的信息进行统计;

4、循环执行步骤1到步骤3,直到被模拟的程序执行结束;

5、跳转返回到模拟器的主程序。

(3)结束处理

执行完毕后进行结束处理,并将模拟过程中依据用户的项配置记录的执行信息,如执行时间、各种类型指令的分类统计、前瞻执行的命中/不命中情况等结果输出。Sim-safe是Sim-fast的孪生兄弟,实现基本与sim-fast一致,但它们又是相互独立的。Sim-main(函数)流程与sim-fast中的sim-main(函数)大体相同,主要的区别在于在执行指令时,sim-safe进行指令的齐整性(Alignment)检查,对所的访存指令首先检查是否合法,而且sim-safe增加了访存指令的分析,并支持Dilte调试器。

7.分析sim-outorder的乱序流水线实现,并注意观察与五级单流水的不同点

五种很重要的功能单元支持sim_outorder对指令序列的乱序执行:保留站与重定序缓冲(RUU)、Load/Store队列(LSQ)、取指队列、输入输出相关链和寄存器忙闲表。它们在simplescalar中是通过五种数据结构来实现的。

RUU单元实现寄存器的同步和通讯功能,它将再定序缓冲和保留站统一起来,作为一个循环队列来管理。RUU队列记录了指令的操作类型、源操作数、数据效性标识。其中的数据项在指令发射时分配,在提交时回收;当寄存器数据和存储器数据相关性满足时,实现乱序流出;

Load/Store队列处理存储器的相关性问题。如果store操作是猜测执行的,其值就被放入队列中。当所之前的写入地址都已知之后,Load操作就可以访存。如果地址匹配,load操作可以在存储系统或者Load/Store队列中以前的store值的允许下进行。

取指队列是由取指段建立,在调度段译码并调度的指令队列;没被调度的指令仍留在其中。它是用一个结构数组来实现的。

输入输出相关链,是用来记录前一条指令的输出数据(结果操作数与后几条指令的输入数据(源操作数的相关性的链表。

寄存器忙闲表,是用来记录当前各个寄存器被哪一条指令占用的结构数组。

具体的乱序过程如下:

A.取指段:根据配置的各种参量的要求,从指令一级Cache里预取指令,加入到取指队列里。如果在一级cache里找不到指令,同时配置了二级cache,就试图从二级cache里再找,否则就从存储器里寻找。

1.根据分支预测的要求、cache容量的支持、事先配置的取指队列的大小,确定预取多少条指令。

2.在地址有效的条件下,取出指令,并根据指令一级CACHE的延时和指令一级TLB的延时计算出其取指延时的大小。

3.若是分支指令,则要根据事先配置的分支预测策略预测下一条指令地址;若不是,指令地址自加一。

4.把这一条指令加入取指队列里,更新取指队列。

B.调度段:从取指队列调度指令。指令首先被译码,然后为其分配RUU资源,判断是否存在数据相关性。如果不存在就可以发射出去,存在的话仍旧留在RUU队列里等待发射。若是访存指令则分配LSQ资源,最后更新输入输出的相关链。

C.发射执行段:检查从调度段发射出来的指令所需的功能部件是否可用(结构相关性,如果可用则将其发射执行。

1.查看指令所需数据、功能部件是否准备好;

2.如果是store指令,执行之。由于数据可先存在LSQ队列中,执行时间为零,实际的访存操作在ruu_commit()中执行。其他指令则需先查看无功能部件。

3.如果是load指令,要确定cache访问的延时,先扫描LSQ队列看其前无访存地址相同的store指令。如果,那么store指令存的数据就是load指令要取的数据,因而访存延时为一周期;如果没就并行访问数据cache和数据TLB,访存延时为二者中较大者。

4.如果是非访存指令,操作时间为其功能部件的执行时间;不需功能部件的指令,操作时间为一个周期。如果是空指令操作时间为零。

D.LSQ队列更新:此过程是找出下一条数据相关性被满足了的指令,并将其发射。而这是通过检查LSQ队列,查找存储器阻塞的情况来实现的。

E.写回段:完成把功能部件的输出数据(结果操作数写入RUU(register update unit的任务。就这点来说,模拟器根据正在完成的指令的输出数据,确定取指队列中的后续指令是否输入数据与其相关,如果是这样,将把这条指令从取指队列中调度出来进行发射。

F.提交段:这个阶段把已经完成的结果从RUU和LSQ提交到寄存器文件中,并且LSQ中的store指令将把其存储数据提交到数据cache中。

1. RUU和LSQ中结果可提交,就执行提交。

2.让LSQ中的store指令把其存储数据提交到数据cache中并计算其操作时间,其中要考虑TLB的延时。

3.按序把已经完成的结果从RUU和LSQ提交到寄存器文件中,并更新RUU和LSQ。

五级流水线分别为取指、译码、执行、存储和回写五个阶段,而乱序过程比五级流水线多了一个提交段。。。。。。。

8.发射队列的引入

为了实现在一个时钟周期内能够发射多条指令,必须要有一种单元,能够保留满足了数据相关性要求并且可以在一个时钟内发射的若干条指令。这样,执行单元直接从这种发射单元中获取可以发射的指令。执行单元执行完某条指令后,所有因为这条指令相关而暂停的指令,能够及时的加入这种发射单元,继续执行。为此,我们引入了发射队列的机制。所谓发射队列(ready queue)就是在调度段(dispatch)通过数据相关性检查,准备在发射段发射执行的指令队列。没有被发射段发射执行的指令仍将留在其中。

9.数据相关性的处理策略

发射队列的长度由人为来设定,比如我们要想每次发射四条指令,就可以将发射队列设置为容纳四条可发射指令的长度。

Dispatch段将指令从取指队列调度指令到发射队列时,将尽可能的将发射队列充满,同时进行数据相关性检测工作:

1.从取指队列里依次读出各条指令;

2.为读出的指令分配RUU资源,若是访存指令还要分配LSQ资源,更新输入输出的相关链;

3.对于非访存指令只需判断所需的源操作数寄存器是否准备好,准备好就将其加入可发射队列;

4.对于访存指令,分为两步作,第一步计算访存地址;第二步访问存贮器,这一步分两种情况,若是store指令,只要访存地址准备好就可把其加入发射队列;若是load指令,留待LSQ更新时解决;

5.每调度一条指令到发射队列,就创建数据输入输出相关性链表,并更新寄存器忙闲表,为调度后续的指令做准备;

6.若是分支指令,更新BTB表。更新各种状态,统计相关参数。

发射执行段的处理策略与原来的非超标量结构基本相同,只是对于多条发射来的指令,各个功能部件要同时处理,分别计算它们的操作时间和访问cache的延时。

Load/Store操作执行完进行LSQ更新时,再次进行数据相关性检测:

1.依次扫描LSQ队列,

2.如果有访存地址未知的store指令,则停止扫描。

3.如果有访存数据未知的store指令,并且store指令的访存地址就是其后的load指令的访存地址,则发生数据写后读相关,这些load指令不能加入发射队列。

4.对于其它情形,LOAD指令正常发射。注意,由LSQ队列的作用,对于下面这种读后写相关,LOAD指令仍可以继续发射:

STORER1,#0010

LOAD#110A,R1;STORE指令要先读R1,由于R1已经在LSQ中备份,解除了数据相关,这条LOAD指令可以发射。

writeback段进行第三次数据相关性检测工作:

根据正在完成的指令的输出数据,把与其相关的指令的相应输入数据设为准备好状态,并将这些指令加入可发射队列,更新RUU单元。

结构相关的处理策略及指令发射条件

这一部分工作主要在issue段进行。在把发射队列里的指令真正发射出去之前,要检测这些指令所需的功能部件是否空闲,即结构相关性。如果空闲,则立即可以发射执行;否则这些指令仍将留在发射队列里暂时等待。

因此,由于结构相关性的存在,造成发射队列中的某些指令暂时无法发射。这样,每个时钟周期的发射流量不一定都能够达到最大的宽度.

10.数据写回处理和指令提交策略

写回段要把功能部件的运算结果写回到RUU,这时,已经完成的指令的输出数据必然可以满足取指队列中某些指令的需要。对于这样的指令,应该把它们依次加入可发射队列,等待下一个时钟周期发射。

超标量结构中的写回处理应该完成以下动作:

1)依次扫描本周期已完成的指令序列;

2)根据分支条件的计算结果,如果遇到错误预测的分支,则复原RUU,恢复到未执行前的状态;

3)根据正在完成的指令的输出数据,把与其相关的指令的相应输入数据设为准备好状态;

4)把输入数据都准备好的指令加入可发射队列,更新RUU。

提交段主要把运算结果从RUU和LSQ提交到寄存器文件中,LSQ中的store指令将把其存储数据提交到数据cache中。这一过程同非超标量结构是一样的。

转自http://blog.chinaunix.net/uid-8867796-id-358782.html

免责声明:文章转载自《SimpleScalar分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Vigenère 密码NOIP 2012 提高组 第一天 第一题极致 Web 性能 —— SPA 性能指南下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ARM寄存器

ARM寄存器 ARM处理器模式用户模式(User):ARM处理器正常的程序执行状态;快速中断模式(FIQ):用于高速数据传输或通道处理;外部中断模式(IRQ):用于通用的中断处理;管理模式(Supervisor):操作系统使用的保护模式;数据访问终止模式(Abort):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护;系统模式(System):运...

X86/X64处理器体系结构及寻址模式

由8086/8088、x86、Pentium发展到core系列短短40多年间,处理器的时钟频率差点儿已接近极限。尽管如此,自从86年Intel推出386至今除了添加一些有关流媒体的指令如mmx/sse之外。其它新增的大多数指令都能够从最初的指令集中组合实现相同的功能,整个编程模型维持了约有20多年。 1. 处理器体系结构 1.1. 处理器简要结构 我们都...

STM32 USART整理说明(转)

  该接口通过3个引脚连接到另外的外部设备上。    任何USART双向通信都至少需要两个引脚:接收数据输入RX和发送数据输出TX。    当发送器禁能时输出引脚恢复到I/O端口配置。当发送器使能时且无数据发送,TX引脚为高电平。     字长可以通过设置USART_CR1寄存器中的M位来选择是8位还是9位。    TX引脚在起始位期间为低,停止位期间为高...

linux 应用程序直接读写寄存器或物理内存

1.程序说明: 调试驱动程序时,经常遇到候需要查看或设置寄存器的情况,但是直接更改内核代码又不方便。 这里提供一个应用程序源码能在应用层访问底层寄存器。(网上找到的,进行过更改)。 这里只提供4字节数据的访问,如果需要其他字节宽度则需要更改代码。 line40 增加了O_DSYNC标志,防止cache导致数据写入不及时。 2.应用程序源码 1 #incl...

深入理解计算机系统1

第一章 计算机系统漫游 代码段的生命周期 hello.c #include <stdio.h> int main() { printf("hello world! "); return 0; } 1.1 前序 源程序(源文件)实际上就是一个由0和1组成的位(又成比特bit)序列,8个位被组组成一组,称为字节。每个字节表...

Intel Core Microarchitecture Pipeline

Intel微处理器近20年从Pentium发展到Skylake,得益于制作工艺上的巨大发展,处理器的性能得到了非常大的增强,功能模块增多,不过其指令处理pipeline的主干部分算不上有特别大的变化,更多的是为了提高指令的处理速度添加一些模块以及各模块的增强与优化。 本文会以Intel Core微处理器架构为例去了解Intel微处理器pipeline的各个...