记一次 spinor flash 读速度优化
背景
某个项目使用的介质是 spinor
, 其 bootloader
需要从 flash
中加载 os
。
启动速度是一个关键指标,需要深入优化。其他部分的优化暂且略过,此篇主要记录对 nor
读速度的优化过程。
了解现状
接到启动速度优化的任务之后, 首先是了解情况。
当前的 bootloader
实测读速度只有约 4M/s
。
为了加快速度已经尝试过
spinor
驱动改为使用四线读命令读取数据。速度并没有明显改善。待确认改动是否生效。spinor
驱动改为使用dma
搬运数据。尚未修改成功。
计算上限
既然是要深入优化,那知道终点在哪还是很有必要的。
整个读取过程,数据主要是从 spinor
到达 soc
的 spi
控制器,再由 cpu
或 dma
搬运到 dram
中的目标位置。
spinor --> spi控制器 --> cpu/dma --> dram
先来考虑第一段的速度,这里比较好计算。针对当前的 soc
和 flash
的组合,从规格书可得到最高的 spi
时钟频率为 100M = 100 * 10^6
,且读数据可使用 4
线读取,即 soc
和 flash
之间有 4
根数据线在并行传输数据。那么简单算下 100 * 10^6 * 4bit = 400 * 10^6 bit/s = 47.68 MB/s
, 可知极限速度为 47.68 MB/s
。
当然较真一点,发送读命令给 flash
也需要时间,让我们来算下。
一般一个读命令需要 5 bytes
, 即 cmd + addr[3] + dummy
,所以实际的极限速度要考虑每发一次读命令后读取多少数据。读命令是单线传输的,数据是四线传输。假设发一次命令读 nbytes
数据,则命令和数据所占时间的比例为 5:(n/4)
, 那么实际用于传输数据的 clk
就只有 (n/4) / (5 + n/4) * 100M
。4
线传输的情况下每个 clk
可传输 4bit
,从 bit
换算成 byte
再除以 8
,于是速度公式为 (n/4) / (5 + n/4) * 100M * 4 / 8
, 这里要注意对于大小 1MB = 1024*1024 Byte
, 对于时钟 100M = 10^6
。
代入一些具体数据可得
每次读取bytes | 读速度 |
---|---|
64 | 36.33 MB/s |
256 | 44.23 MB/s |
1024 | 46.77 MB/s |
64k | 47.67 MB/s |
1M | 47.68 MB/s |
可以看出,如果每次读取数据量较小,那么发送读命令消耗的时间就不可忽视。每次读取的数据量越大,则读命令对速度造成的整体影响就越小。
后面的部分理论速度暂时没有很明确的计算方式,那暂时先知道完整的数据是这么流动的就可以了。
确认瓶颈
看了下驱动打印出来的确实是 80M
的 clk
和 4
线的读命令,虽然还没调到最高时钟 100M
,但当前 4M/s
也完全对不上,到底是谁出了问题呢?时钟不对?四线没配置成功?驱动存在 bug
? nor flash
物料的问题?
思考一下,要确认到底是谁的锅,最简单明了的方式还是量下波形,不管软件驱动上怎么写,控制器的寄存器怎么配,最终还是得反映在波形上才是最真实的传输效果。接上示波器或逻辑分析仪,看看 spi
线上的情况,是谁的问题就一目了然了。
首先量一下 spi clk
线,可以发现读数据的过程中,clk
的信号不是连续的,在有信号时其频率是正常的,但大部分时间 clk
线上却是没有信号的。再量量数据线,可以确认到确实使用了 4
线读。
问题很明显,spi
控制器是在间歇性读数据,所以虽然读 nor
的时候是 80M
的时钟频率进行读取,但把 spi
的空闲时间计算进去,均摊下来的总的速度就只有 4M/s
了。
那为什么 spi
控制器会间歇性读取而不是一直在读取呢? 这就涉及到刚刚所说的数据流了,spi
控制器本身的 fifo
是有限的,当从 spinor
读取的数据填满 fifo
之后,就必须等着 cpu/dma
把数据取走,腾出 fifo
空间来,才能继续发送指令从 nor
取数据。那么这段空闲时间,应该就是在等 cpu/dma
取数据了。
验证 CPU
有了怀疑方向,那就得看下代码了。目前驱动中使用的是 cpu
来搬运数据,正常读取过程中,cpu
在执行以下代码
while 待读取数据计数值大于0
if (查询spi寄存器,判断到fifo中存在数据)
读取spi fifo寄存器数据,写到dram的buffer中
待读取数据计数值减1
如果是这里成为了瓶颈,那就有两个地方比较有嫌疑,一是读取 spi
寄存器,而是写 dram
。
做点实验确认下
实验一,尝试下把写 dram
的操作去掉,使用如下操作,并由读取前后的 log
时间戳来判断耗时。
while 待读取数据计数值大于0
if (查询spi寄存器,判断到fifo中存在数据)
读取spi fifo寄存器数据
待读取数据计数值减1
重新测试下,发现速度没有明显变化。
实验二,尝试下减少读 spi
寄存器的操作
while 待读取数据计数值大于0
读取spi fifo寄存器数据
待读取数据计数值减1
重新测试下,发现读速度翻倍了,达到了 8M/s
,看来果然是这里成为了瓶颈。没想到 cpu
读个 spi
寄存器竟然这么耗时。
改用 DMA
cpu
太慢,那就指望 dma
了。
先来解决 dma
驱动异常问题,了解下情况,原来这个 dma
驱动的支持是从另一个分支上移植过来的,原本工作正常,到了这个分支就翻车了。
这就是一个找不同的问题了,先比较下两个分支的差异,再将可疑的地方 checkout/cherry-pick
到另一个分支来验证。很快找到了关键因素 dcache
。
这个分支上是默认打开了 dcache
的,可见旧文 记一个bootloader的cache问题,而这就导致了 dma
驱动工作异常。
简单点,关掉 dcache
试试,果然 dma
就正常了。测下速度,达到了 21M/s
。
再测试下不关 dcache
,在配置了 dma
描述符之后,刷一次 cache
再启动 dma
传输,也是正常的了。
优化配置
21M/s
的速度,看来瓶颈还是在 dma
这里。此时可以尝试将 spi clk
从 80M
提高到 100M
,可以发现整体读速度没有变化,这也可以佐证当前瓶颈仍然不在 nor
的读取速度上面。
测个波形看看,果然 clk
线上还是间歇性的,不过空闲时间比之前少了很多。
dma
的速度能不能改进呢? 这就涉及到具体的芯片了,需要深究下 dma
控制器和 spi
控制器的配置。
优化 dma
和 spi
控制器的配置后,dma
从 spi
控制器取数据的速度,终于超过了 80M
时钟下的 spinor
读取速度,将 spi clk
修改为 100M
,测得读速度约 36M/s
。
优化驱动
前面说到,发送读命令给 flash
也需要时间,在 os
中受限于 buffer
大小等,可能会限制每次读取和处理的数据量,但对于 bootloader
来说则完全可以一口气将所需的数据读入,无需分段。
另外可查看驱动中是否有无用的清空 buffer
之类的操作,一并优化掉。
提高时钟
驱动逻辑和寄存器上无法优化之后,还想提速,那么可以试试提高时钟。
提高 cpu
时钟和 dma
时钟,提高后测得速度约 47M/s
,基本就是理论极限了。
但具体能否提高时钟还是得谨慎评估,单个板子可以正常运行,不意味能够稳定量产。
压缩镜像
在读取速度无法进一步优化的情况下,要提高启动速度,那就得减少读入的数据量了。
可以评估下使用压缩的镜像来减少读入的数据量,只要多出的解压时间不长于节省掉的读取 flash
时间,那就是划算的。
是否压缩,选择哪种压缩算法,就跟 io
速度,cpu
解压速度直接相关了,最好经过实测确认,综合启动速度和 flash
占用来选择。
其他
如果是带压缩的镜像,那启动速度就是读取时间+解压时间。
读取时主要是 io
操作,解压则主要是 cpu
操作。那么是否有可能实现边读取边解压,使得总的启动时间进一步缩短呢?这个待研究
blog: https://www.cnblogs.com/zqb-all/p/12824908.html
公众号:https://sourl.cn/4X3jE7
记一次 spinor flash 读速度优化的更多相关文章
- 记一次cocos项目的加载速度优化
半个月前,我们用cosos creator做了一个简单的小游戏,也许算不上小游戏吧..一边学cocos,一边做,几经波折后终于上线了.然鹅,功能是实现了,但是加载速度十分感人(毕竟没经验嘛,无辜脸). ...
- Elasticsearch 调优之 搜索速度优化
本章讨论搜索速度优化:搜索速度与系统资源.数据索引方式.查询方式等多方面 1.为文件系统cache预留足够的内存 1)应用程序一般情况下,读写都会被操作系统“cache” 2)cache保存在物理内存 ...
- dWebpack编译速度优化实战
当你的应用的规模还很小时,你可能不会在乎Webpack的编译速度,无论使用3.X还是4.X版本,它都足够快,或者说至少没让你等得不耐烦.但随着业务的增多,嗖嗖嗖一下项目就有上百个组件了,也是件很简单的 ...
- 记一次针对excel导出的优化
最近发现我们系统导出excel文件时由于是导出百万级数据导出,速度过慢并且内存占用多,故进行了下面的一次优化. 我们使用apache的poi进行excel文件操作 主要耗时: 1.从数据库得到需要导出 ...
- [转]Asp.net mvc 网站之速度优化 -- 页面缓存
网站速度优化的一般方法 由于网站最重要的用户体验就是速度,特别是对于电子商务网站而言. 一般网站速度优化会涉及到几个方面: 1. 数据库优化 — 查询字段简历索引,使用数据库连接池和持久化,现在还有种 ...
- web访问速度优化分析
请求从发出到接收完成一共经历了DNS Lookup.Connecting.Blocking.Sending.Waiting和Receiving六个阶段,时间共计38ms.请求完成之后是DOM加载和页面 ...
- Tone Mapping算法系列二:一种自适应对数映射的高对比度图像显示技术及其速度优化。
办公室今天停电,幸好本本还有电,同事们好多都去打麻将去了,话说麻将这东西玩起来也还是有味的,不过我感觉我是输了不舒服,赢了替输的人不舒服,所以干脆拜别麻坛四五年了,在办公室一个人整理下好久前的一片论文 ...
- Mysql数据库写入数据速度优化
Mysql数据库写入数据速度优化 1)innodb_flush_log_at_trx_commit 默认值为1:设置为0,可以提高写入速度. 值为0:提升写入速度,但是安全方面较差,mysql服务器 ...
- (转)网站速度优化技巧:Nginx设置js、css过期时间
网站速度优化技巧:Nginx设置js.css过期时间 原文:http://www.webkaka.com/blog/archives/Nginx-set-the-expiration-time-for ...
随机推荐
- 【Jenkins】插件更改国内源
最近调试脚本,本机安装了Jenkins,但是安装插件时一直失败.更改升级站点也不生效,究其原因是因为default.json中插件下载地址还https://updates.jenkins.io,升级站 ...
- J - A strange lift
计院有一个bug电梯,可能是hyk造的,很多bug,电梯只有两个按钮,“上”和“下”,电梯每层都可以停,每层都有一个数字Ki(0<=Ki<=n),当你在一层楼,你按“上”键会到1+K1层, ...
- selenium获取多窗口句柄并一切换至原窗口句柄(三个窗口)
网上有很多是selenium基于python来获取两个窗口句柄与切换,本文实现用python+selenium获取多窗口句柄并一一切换至原窗口句柄(三个窗口),且在每个窗口下进行一个搜索或翻译,然后截 ...
- Linux学习笔记(二)文件操作命令
文件操作命令 touch stat cat more less head tail ln touch 英文原意: change file timestamps 功能: 修改文件的时间戳 语法: tou ...
- shift后门
shift快捷 Windows的粘滞键------C:\windows\system32\sethc.exe,它本是为不方便按组合键的人设计的 Windows系统按5下shift后,Windows就执 ...
- [php] 简单的实现一个错误接管类
自己弄的一个错误接管类: <?php //---------------------------------- // Leephp 错误接管类 // 2017-07-06 // Pengchon ...
- Redis 5.0.9 安装
目录 系统环境 系统版本 内核版本 安装步骤 安装 gcc 依赖 下载 Redis 解压 Redis 切换到 redis 解压目录下,执行编译 指定目录安装 启动 Redis 服务 最后 系统环境 系 ...
- python-Django收集主机信息json格式
Control: from django.conf.urls import patterns, include, url from django.contrib import admin admin. ...
- vue中解决时间在ios上显示NAN的问题
最近在用vue,遇到倒计时在ios上显示为NAN的问题. 因为做的是倒计时支付,思路是获取服务器时间和下单时间,再转成秒级时间戳做差值. 在网上找到说是ios 不支持例如2018-09-01 10:0 ...
- 手机app测试用例怎么写?手机app测试点有哪些?只有干货没有水分,错过绝对后悔!
一.前言 在当今竞争激烈的市场上一个APP的成功离不开一个可靠的测试工程师.因此,对功能和用户体验有特殊关注的App进行全面测试是必不可少的.如何做到测试用例的百分百覆盖一直是测试用例编写过程中 ...