SSDsim是一个针对SSD进行模拟仿真的软件系统,所以针对已经使用过的SSD也需要进行一定程度的模拟,因为SSD存在着磨损耐性的问题。在SSD上存储的数据,除了无法进行覆盖写操作之外,其擦除数据的操作也是对块级block为单位进行整块擦除的,因此每一个block都会有一个对应的擦除上限。一旦该block的擦除次数达到了 earse_limit,则该block便无法像正常的block一样能够保证数据的存储正确率。也就是说虽然此时可以继续写入数据,但是这种状态下的block下无法保证数据的正确率。因此,不同的SSD具有不同的磨损程度。这篇博文我们先简单介绍下关于SSD的存储原理以及存储单元的物理特性,接着介绍下SSDsim中针对磨损程度进行的模拟函数make_aged。

SSD存储原理

而今常见的SSD为基于Flash介质的SSD,所有类型的ROM和Flash芯片都使用了一种名为“浮动门场效应晶体管”的基本存储介质。与传统的HDD使用磁性介质不同,这种晶体管(也称为cell)是使用了电荷来标识数据的存储情况。在计算机中的数据只有0和1这两种状态,所以传统的磁盘介质是使用了一块磁粒子区来保存1或者0,而SSD的cell当充电时表示状态0,放电后表示状态1。cell是一个逻辑电路,这个电路通过被二氧化硅绝缘层包裹着,通过外部的门电路进行控制,在Word_line(即字线)上抬高电荷电势产生一个电场,这个电场就被这个绝缘层所填充,由于电势的抬高,电子从这一电极流向另一个源电极,在其流动中具有足够动能的电子便会穿过该绝缘层到达浮动门。在这个充电过程中电子便会存储在这个浮动门中,而且由于绝缘层的物理特性,在字线恢复电势后控制门便会断开电场,此时电子可以保存在被绝缘层包裹的浮动门中长达数年之久。这就是SSD的存储介质的存储原理。下面是关于浮动门的相关图解:

而cell主要有两种类型:MLC(Multi Level Cell)和SLC(Single Level Cell),其中SLC的cell可以保存1B的数据,而MLC可以保存2B的数据。所以MLC容量是SLC的两倍,但是SLC的IO速度却比MLC要快得多。而且无论是SLC还是MLC都需要有一个额外的区域ECC作为存储校验信息。

至此我们可以了解到,Cell是通过浮动门中的充电情况来判断是存储1或0的。以上的cell存储情况便是SLC的cell,而MLC的cell则是通过让cell具备4个阀值,其中每个阀值都表示了一种状态。每次充电时都利用特定电路控制充电程度,充电至一定阀值之上而低于特定的某一阀值。这样可以用MLC的cell表示4中状态分别是00、01、10、11.
如下图所示是cell 的阵列示意图。我们可以看到每一个cell串都是由多个cell串联而成,每一次读/写时只能在一个cell串中读写其中的某一个cell,而多个cell串并联就可以实现同时并行读写多位数据。所以SSD读写的基本单元是page,故每一个page中的所有bit都会位于一个cell串中相同的位置上,从而形成了字线的长度。字线便是将每个cell串上属于同一个page的所有cell串联起来的导线,而将每个cell串中所有cell串联起来的称为位线。

在SSD的数据写入过程中,待写入的数据必须经过ECC校验后才可以和校验完成后的ECC数据一齐写入存储芯片中,而读取数据过程中,数据则会和ECC信息一起读出同时做校验,只有校验成功后才会通过外部总线发送出去。因此ECC校验计算有一个专用的运算器,这个会定制在SSD的内部处理器中。而SSD会有一块很大容量的DRAM。并且还有专属于自己的CPU操作代码和体系。

旧化模拟函数make_aged

从上面关于SSD存储原理的介绍我们可以了解到浮动门电路的物理存储特性,对于整个block的page上所有浮动门电路来说,都会有一个最大的充放电次数的限制。因此SSD的耐性通常比HDD要差很多就是因为这种物理特性。

SSDsim提供了一个模拟函数make_aged进行旧化率的模拟,主要的功能是模拟真实使用过一段时间的SSD,此时的SSD中有部分物理特性参数会发生改变,这个函数便是通过输入的SSD结构体,进行结构体成员变量的逐一设置,所以实质上便是对SSD结构体的各个参数进行一个对应的重新设置参数。

我们先看一下这个旧化函数的函数流程图:

以下是源码注解:

struct ssd_info *make_aged(struct ssd_info *ssd)
{unsigned int i,j,k,l,m,n,ppn;int threshould,flag=0;if (ssd->parameter->aged==1)        //判断ssd是否是aged,值为1则是aged状态的,需要进行旧化模拟{//threshold表示一个plane中有多少页需要提前置为失效(分组失效页数量计算如下所示),aged_ratio是旧化率threshould=(int)(ssd->parameter->block_plane*ssd->parameter->page_block*ssd->parameter->aged_ratio); //for (i=0;i<ssd->parameter->channel_number;i++)for (j=0;j<ssd->parameter->chip_channel[i];j++)for (k=0;k<ssd->parameter->die_chip;k++)for (l=0;l<ssd->parameter->plane_die;l++){  flag=0;for (m=0;m<ssd->parameter->block_plane;m++){  if (flag>=threshould)   //此处的判断语句的作用是判断plane中失效页是否为0亦或者更低,如果没有失效页则直接break退出上面的for循环{                       //所以此处的判断是为了筛选出那些失效页数量大于0的分组,进行下面操作break;}for (n=0;n<(ssd->parameter->page_block*ssd->parameter->aged_ratio+1);n++)   //此处的循环判断上限是指每一个块中失效页的数量{  //若该分组中有存在失效页则进行相应旧化操作ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].blk_head[m].page_head[n].valid_state=0;        //表示某一页失效,同时标记valid和free状态都为0ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].blk_head[m].page_head[n].free_state=0;         //表示某一页失效,同时标记valid和free状态都为0ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].blk_head[m].page_head[n].lpn=0;  //把valid_state free_state lpn都置为0表示页失效,检测的时候三项都检测,单独lpn=0可以是有效页ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].blk_head[m].free_page_num--;        //某一页失效后,自然要将空闲页数量-1,此处的free_page_num代表块中的free页数ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].blk_head[m].invalid_page_num++; //失效页数量+1ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].blk_head[m].last_write_page++;      //由于失效页+1所以要将此失效页标记后并执行写操作,代表该页不可写ssd->channel_head[i].chip_head[j].die_head[k].plane_head[l].free_page--;        //此处的free_page代表的是一个plane中的free页数,必须一起标记flag++;         //flag代表了该块下当前旧化操作后失效页的统计量,也相当于是分组中已被旧化模拟的失效页数量                                                             ppn=find_ppn(ssd,i,j,k,l,m,n);//返回该失效页对应的物理页号}} }    }  else{return ssd;}return ssd;
}

通过上述源码我们可以看到,这个make_aged主要调用了一个find_ppn()函数进行一个失效物理页号的查找过程,这个函数的功能是根据参数channel,chip,die,plane,block,page,找到该物理页号。其中会计算出每一个层级所包含的总物理页数量,如channel总页数,chip总页数,die总页数等等,这些会用于后面定位具体物理页号计算公式,可以根据闪存SSD的内部结构并行性画出简图便于理解这个寻址物理页号的过程。这个函数的返回值就是这个对应的物理页号。

以下是find_ppn()源码注解:

unsigned int find_ppn(struct ssd_info * ssd,unsigned int channel,unsigned int chip,unsigned int die,unsigned int plane,unsigned int block,unsigned int page)
{unsigned int ppn=0;unsigned int i=0;int page_plane=0,page_die=0,page_chip=0;int page_channel[100];                  /*这个数组存放的是每个channel的page数目*/#ifdef DEBUG    //设置debug固定页位置测试断点printf("enter find_ppn,channel:%d, chip:%d, die:%d, plane:%d, block:%d, page:%d\n",channel,chip,die,plane,block,page);
#endif/**********************************************计算出plane,die,chip,channel中的page的数目**********************************************/page_plane=ssd->parameter->page_block*ssd->parameter->block_plane;page_die=page_plane*ssd->parameter->plane_die;page_chip=page_die*ssd->parameter->die_chip;while(i<ssd->parameter->channel_number) //计算出每一个条通道中page的页数量{page_channel[i]=ssd->parameter->chip_channel[i]*page_chip;i++;}/*****************************************************************************计算物理页号ppn,ppn是channel,chip,die,plane,block,page中page个数的总和*****************************************************************************/i=0;while(i<channel)    //channel函数参数代表了当前的通道编号,也就是第channel个通道{ppn=ppn+page_channel[i];    //从0号物理页开始累加,一直计算到索引目标物理页所在的通道起始位置的物理页号处i++;}ppn=ppn+page_chip*chip+page_die*die+page_plane*plane+block*ssd->parameter->page_block+page;//while循环结束后ppn便是当前该通道下起始位置开始的物理页号,此时再根据其他相关参数计算具体的物理页号//这道计算公式的原理在于:根据通道起始位置处的物理页号,在通道channel之下的所有层级中的根据函数传递参数定位具体的物理页号,由于SSD内部结构的并行性所以必须要先计算出所有层级所含页数量的数值return ppn;
}

同时关于该find_ppn函数在后续源码中具有重要的意义,后续的博文会在相关功能调用时讲到。

SSDsim源码分析之make_aged相关推荐

  1. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  2. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  3. SpringBoot-web开发(二): 页面和图标定制(源码分析)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) 目录 一.首页 1. 源码分析 2. 访问首页测试 二.动态页面 1. 动态资源目录t ...

  4. SpringBoot-web开发(一): 静态资源的导入(源码分析)

    目录 方式一:通过WebJars 1. 什么是webjars? 2. webjars的使用 3. webjars结构 4. 解析源码 5. 测试访问 方式二:放入静态资源目录 1. 源码分析 2. 测 ...

  5. Yolov3Yolov4网络结构与源码分析

    Yolov3&Yolov4网络结构与源码分析 从2018年Yolov3年提出的两年后,在原作者声名放弃更新Yolo算法后,俄罗斯的Alexey大神扛起了Yolov4的大旗. 文章目录 论文汇总 ...

  6. ViewGroup的Touch事件分发(源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,View的touch事件分发相对比较简单,可参考 View的Touch事件分发(一.初步了解) View的Touch事 ...

  7. View的Touch事件分发(二.源码分析)

    Android中Touch事件的分发又分为View和ViewGroup的事件分发,先来看简单的View的touch事件分发. 主要分析View的dispatchTouchEvent()方法和onTou ...

  8. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: Java代码   String res ...

  9. [转]slf4j + log4j原理实现及源码分析

    slf4j + log4j原理实现及源码分析 转载于:https://www.cnblogs.com/jasonzeng888/p/6051080.html

最新文章

  1. 你为什么“啃不动”你手中的技术书?
  2. | ^ ~ 按位运算符
  3. 多彩投网站动态爬取[python+selenium]
  4. Map Reduce和流处理
  5. 【转】想象5年后的你
  6. Android 系统(167)----OTA升级常见问题
  7. 【PostgreSQL-9.6.3】触发器实例
  8. ASP.NET网站还是ASP.NET Web应用程序?
  9. android如何隐藏imageview,Android编程实现切换imageView的方法分析
  10. Chrome 87 发布,获多年来最大性能提升
  11. 气象数据产品下载网址汇总
  12. matlab 中常用的日期格式转换
  13. 《明解c语言 入门篇》柴田望洋/著 205段代码
  14. adb下载安装教程(已安装Android studio)
  15. Linux基础知识-命令行
  16. python进程池apply与apply_async的区别
  17. OpenCV剪切图片圆形区域
  18. unity如何插入图片_unity 图片导入及其使用方法
  19. .NET Core 开源工具 IPTools - 快速查询 IP 地理位置、经纬度信息
  20. 栈的基础与基本操作实现

热门文章

  1. 重启tomcat报错 Tomcat7“At least one JAR was scanned for TLDs yet contained no TLDs”
  2. 8、接口与面向接口编程
  3. 如何正确使用移动硬盘
  4. 使用Selenium WebDriver进行闪存测试
  5. 什么是iu组装服务器,华硕迷你IU机架服务器RS100-E4/PI2全新上市
  6. C#数据结构(4) 稀疏矩阵与稀疏方阵
  7. This application has requested the Runtime to terminate it in an unusual way.
  8. docker配置HTTP/HTTPS代理访问外网
  9. 【离散数学】集合与关系
  10. 某211大学生保研思路分享【写给所有怀揣远大梦想的你们】