pre_process_page()
从本篇博文开始,我们将会对SSDsim中最核心的部分进行详细的分析和注解,SSDsim仿真器最核心的部分在于三大函数:
pre_preocess_page()页读请求预处理函数
simmulate()核心模拟函数
statistic_output()统计输出信息函数
其中最为重要和庞大的函数当属simmulate()核心模拟函数,这个函数主要是负责整个SSD功能的模拟,我们会在后面的篇幅中将其展开详细描述并且加以解析;而本篇博文先解析pre_preocess_page()函数的主要功能和详细的作用,这其中会涉及到很多SSDsim的工作原理以及架构方面的知识,可以结合程序源码及解析进行分析。
pre_process_page()主要作用与功能
Pre_process_page()读请求预处理函数,主要功能是当读请求所读的页page内没有数据时需要该函数往page内先写入data以完成读操作。同时也是因为要将tracefile中所有的读请求IO全部先进行优先处理.
函数首先会定义一些相关的参数,其中包括了一个长度为200char的buf缓冲区,并且调用fopen()以只读方式打开tracefile文件,若打开失败(文件不存在或者文件名有误等情况)则直接返回出错。
若读取tracefile成功,程序会先置full_page即子页屏蔽码为1(初始屏蔽码默认每一个page下的所有subpage的状态都是为1),计算:
largest_lsn最大的逻辑扇区号 =( SSD的chip数量 × 每个chip下的die数量 × 每个die下的plane数量 × 每个plane下的block数量 × 每个block下的page数量 × 每个page下的subpage数量) × 预留空间OP比率。
注:SSD都会有一个OP预留空间的概念,这个OP预留空间可以很大程度上提高SSD的性能。
随后程序会调用fget()逐行打开tracefile中的所有IOtrace信息到buf缓冲区中,每次最多读取一行200个char;
在打开读取trace的过程中,程序利用了sscanf()函数按照:
time(long long型) device(int型) lsn(int型) size(int型) ope(int型)。
这样的固定trace格式逐行读取IOtrace数据,读完后便统计fl也就是IO数量计数,并且每次读完一个IOtrace都需要调用trace_assert()函数进行IO的正确性判断。
随后初始化add_size即该IO已完成的size计数为0,判断ope操作数:
若ope为0则说明是写请求,但是由于这个pre_process_page只是服务于读请求,所以程序流会忽略写请求直接继续调用fget()读取下一个IOtrace进行读请求的操作。
而当ope为1时说明IO为读请求,程序会判断已完成的IO长度add_size是否小于IO长度size,若大于或等于size说明读IO已经处理完毕继续下一IO的读取;否则说明该IO读尚未处理完毕,要继续下面的步骤:
首先程序会调整lsn(防止lsn比最大的lsn还大),然后计算sub_size即lsn所在的page中实际IO需要操作的长度:
这部分长度 = page子页数量 - lsn在page中的起始子页位置;
随后判断已经处理的IO长度add_size和当前page中的实际操作长度sub_size之和是否超过该IOtrace的长度size:
若已经超过说明sub_size实际上的长度需要调整(实际上不可能超过IOtrace所规定的size,否则就是错误操作,而这里的sub_size主要是针对首次的lsn和最后一次的lsn,因为其余中间部分的lsn基本上都会是从page页的起始位置开始,操作的长度都会是整个page大小)
所以通常是最后一页的lsn可能需要进行sub_size的调整,此时
sub_size = IO长度size - 已经处理完毕的长度add_size
同时更新已经处理完毕的长度add_size令其加上调整后的sub_size;
若判断中未超过时说明此时处理的长度尚未到达最后一页,那么可以直接跳过上述调整步骤直接判断sub_size的合法性(即是否超过page大小)和已经处理完毕的长度add_size是否合理(即是否超过了该IOtrace的长度size)
如果非法的话则打印sub_size的信息;同时程序会继续统计当前lsn所在的lpn,并判断该lpn在内存dram中的映射表项map_entry[lpn]的相关子页映射是否有效:
若map_entry[lpn].state不为0则说明此时该lpn的子页映射可能有效,可能存在有直接可用的子页,程序会接着判断state是否>0.
若不成立只能说明此时state<0也就是子页映射全部有效(这里是因为map_entry[lpn].state是一个int类型,默认下应该是个有符号的整型取值范围,因此若state<0那么换算成二进制数值便是全1的情况,此时所有子页都是有效置位)
此时可以直接跳过以下步骤进行lsn和add_size的更新。
而如果