Linux framebuffer deferred io机制
一、总体框架
deferred io机制主要用于驱动没有实现自刷新同时应用层又不想调用FBIOPAN_DISPLAY的一个折中方案, 使用ioctrl FBIOPAN_DISPLAY好处是节能, 驱动不用盲目的刷数据(尤其是一静态帧数据), 数据的更新是由应用程序操作的,
所以应用程序当然知道何时刷数据, 最理想的情况是应用程序一更新数据立马调用FBIOPAN_DISPLAY, 但也有缺点, 一是要应用层显示调用FBIOPAN_DISPLAY,二是画面更新频率高的话, FBIOPAN_DISPLAY带来的系统调用开支也不小;
使用驱动自刷新当然解放应用, 应用不用关心数据显示问题, 直接操作显存, 所写即所见。
二、源码分析
代码具体在linux/drivers/video/fb_defio.c, 如下演示刷图穿插该框架的实现代码:
1. fb_defio 自己实现一个mmap(), 没有将用户空间虚拟地址和物理帧缓存进行页表映射, 倒是提供了缺页异常处理函数
void fb_deferred_io_init(struct fb_info *info)
{
struct fb_deferred_io *fbdefio = info->fbdefio; BUG_ON(!fbdefio);
mutex_init(&fbdefio->lock);
info->fbops->fb_mmap = fb_deferred_io_mmap;
INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
INIT_LIST_HEAD(&fbdefio->pagelist);
if (fbdefio->delay == ) /* set a default of 1 s */
fbdefio->delay = HZ;
}
EXPORT_SYMBOL_GPL(fb_deferred_io_init); static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
vma->vm_ops = &fb_deferred_io_vm_ops;
vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
if (!(info->flags & FBINFO_VIRTFB))
vma->vm_flags |= VM_IO;
vma->vm_private_data = info;
return ;
} static const struct vm_operations_struct fb_deferred_io_vm_ops = {
.fault = fb_deferred_io_fault,
.page_mkwrite = fb_deferred_io_mkwrite,
};
2. 应用程序通过mmap(), 获得一块帧缓存的虚拟地址, 但没有对应的实际物理内存
3. 应用程序操作内存(write), 由于页表没有对应物理内存导致缺页异常
do_page_fault()
-> __do_page_fault()
-> handle_mm_fault()
-> __handle_mm_fault()
-> handle_pte_fault():
if (vma->vm_ops) {
if (likely(vma->vm_ops->fault))
return do_linear_fault(mm, vma, address, pte, pmd, flags, entry);
}
-> __do_fault():
vma->vm_ops->fault(vma, &vmf);
vma->vm_ops->page_mkwrite(vma, &vmf);
从上面流程可以看出, 当vm_ops且fault有效时, 会走自定义的fault实现, 同时如果操作时write行为, 还会调用page_mkwrite(有效的话)
4. fb_defio提供了缺页异常的处理函数fb_deferred_io_fault(), 分配物理页跟虚拟地址对应起来, 并把该物理页挂到fbdefio->pagelist(即将被刷新数据), 然后启动工作队列延迟delay后执行这个工作项fb_deferred_io_work()
static int fb_deferred_io_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
unsigned long offset;
struct page *page;
struct fb_info *info = vma->vm_private_data; offset = vmf->pgoff << PAGE_SHIFT;
if (offset >= info->fix.smem_len)
return VM_FAULT_SIGBUS; page = fb_deferred_io_page(info, offset);
if (!page)
return VM_FAULT_SIGBUS; get_page(page); if (vma->vm_file)
page->mapping = vma->vm_file->f_mapping;
else
printk(KERN_ERR "no mapping available\n"); BUG_ON(!page->mapping);
page->index = vmf->pgoff; vmf->page = page;
return ;
} static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs)
{
void *screen_base = (void __force *) info->screen_base;
struct page *page; if (is_vmalloc_addr(screen_base + offs))
page = vmalloc_to_page(screen_base + offs);
else
page = pfn_to_page((info->fix.smem_start + offs) >> PAGE_SHIFT); return page;
} /* 需要注意的是帧缓存是一开始fb驱动就应该分配好的, 同时赋值给fb_info->screen_base, fb_info->fix.smem_start
* 而fb_deferred_io_fault()-> fb_deferred_io_page()分配内存只是找出并返回此次缺页异常页虚拟地址对应的物理地址,
* 好填充页表, 这样应用程序就可以正常write数据到缓存, 整个过程对应用程序是透明的。
*/
5. fb_deferred_io_work() 最核心就是调用函数指针fbdefio->deferred_io(驱动要实现的刷数据函数), 并调用page_mkclean()将之前虚拟地址和帧物理页的映射清除, 使得下次操作这块虚拟地址又能重新触发缺页机制
二、fb驱动示例
static void lcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
{
struct page *cur;
struct fb_deferred_io *fbdefio = info->fbdefio; /* pagelist存放的都是被更新的脏页, 由于我驱动用SPI DMA搬数据,会存在cache不一致, 所以要把cache的缓存刷回内存 */
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
flush_dcache_page(cur);
} /* 虽然pagelist存放都是脏页,我懒得对这些页在帧的位置进行排布分析, 直接一整帧都刷
也即哪怕应用程序改动一个page, 驱动都会整帧刷*/
info->fbops->fb_pan_display(&info->var , info);
} static struct fb_deferred_io gen_lcd_fb_defio = {
.delay = HZ / ,
.deferred_io = lcd_fb_deferred_io,
}; static void lcd_defio_init(struct fb_info *info, struct fb_deferred_io *fbdefio)
{
info->fbdefio = fbdefio;
fb_deferred_io_init(info);
} static void lcd_defio_cleanup(struct fb_info *info)
{
if (info->fbdefio != NULL) {
fb_deferred_io_cleanup(info);
info->fbdefio = NULL;
}
} ==========================================
lcd_defio_init(fb_dev, gen_lcd_fb_defio)
lcd_defio_cleanup(fb_dev)
三、其他
1. 要使能deferred io机制, 要打开CONFIG_FB_DEFERRED_IO配置
2. 这里没有帧率说法, 只跟应用刷图有关
3. 缺页异常会被调用多次, 但fb_deferred_io_work()只会被最后页调用一次, 比如应用要刷,2个page, 第一个page导致fb_deferred_io_mkwrite()添加到pagelist, 然后调用schedule_delayed_work()启动延迟1/8s的工作项fb_deferred_io_work(),
接着引发第二页缺页异常会被继续添加到pagelist, schedule_delayed_work再次被执行, 但只是重新更新延迟时间为1/8s
4. 我感觉page_mkclean() 这里有个bug, 它是把物理页所有的映射都清除, 包括kernel空间的虚拟地址, 那下次缺页异常时fb_deferred_io_page() -> vmalloc_to_page(screen_base + offs), 就会有问题, 因为页表被清除掉了, 所以该框架目前应该只支持连续的帧缓存
Linux framebuffer deferred io机制的更多相关文章
- Linux framebuffer deferred io机制【转】
转自:https://www.cnblogs.com/vedic/p/10722514.html 一.总体框架 deferred io机制主要用于驱动没有实现自刷新同时应用层又不想调用FBIOPAN_ ...
- Linux的io机制
Linux的io机制 Buffered-IO 和Direct-IO Linux磁盘I/O分为Buffered IO和Direct IO,这两者有何区别呢? 对于Buffered IO: 当应用程序尝试 ...
- linux下epoll实现机制
linux下epoll实现机制 原作者:陶辉 链接:http://blog.csdn.net/russell_tao/article/details/7160071 先简单回顾下如何使用C库封装的se ...
- 深入理解JAVA I/O系列六:Linux中的IO模型
IO模型 linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段. 这张图大致描述了数据从外部磁盘向运行中程序的内存中移动的过程. 用户空间.内核空间 现在操作系统都是采用虚拟存储器, ...
- Linux优化之IO子系统监控与调优
Linux优化之IO子系统 作为服务器主机来讲,最大的两个IO类型 : 1.磁盘IO 2.网络IO 这是我们调整最多的两个部分所在 磁盘IO是如何实现的 在内存调优中,一直在讲到为了加速性能,linu ...
- Linux SCSI回调IO的分析
本文转载自:http://blog.csdn.net/xushiyan/article/details/6941640,如需参考,请访问原始链接地址. 没找到如何转载的入口,只好全文copy了. -- ...
- 深入理解JAVA I/O系列六:Linux中的IO模型(转载的文章非常值得学习)
From:http://www.cnblogs.com/dongguacai/p/5770287.html IO模型 linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段. 这张图大 ...
- [转载] Linux五种IO模型
转载:http://blog.csdn.net/jay900323/article/details/18141217 Linux五种IO模型性能分析 目录(?)[-] 概念理解 Lin ...
- Linux Framebuffer驱动剖析之一—软件需求
嵌入式企鹅圈将以本文作为2015年的终结篇,以回应第一篇<Linux字符设备驱动剖析>.嵌入式企鹅圈一直专注于嵌入式Linux和物联网IOT两方面的原创技术分享,稍后会发布嵌入式企鹅圈的2 ...
随机推荐
- BZOJ_1579_[Usaco2009 Feb]Revamping Trails 道路升级_分层图最短路
BZOJ_1579_[Usaco2009 Feb]Revamping Trails 道路升级_分层图最短路 Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M ...
- 记一次logback传输日志到logstash根据自定义设置动态创建ElasticSearch索引
先说背景,由于本人工作需要创建很多小应用程序,而且在微服务的大环境下,服务越来越多,然后就导致日志四分五裂,到处都有,然后就有的elk,那么问题来了 不能每个小应用都配置一个 logstash 服务来 ...
- Python任务调度模块 – APScheduler,实现定时任务
1.安装 pip install apscheduler 安装完毕 2. 简单任务 首先,来个最简单的例子,看看它的威力. # coding:utf-8 from apscheduler.schedu ...
- QTimer在QThread环境中失效的问题
QTimer在非QThread的环境下能正常工作.但在QThread环境下,需要做一些改动才能正常工作. 创建Qt的线程有两种方式: 1. 子例化QThread 可以在虚函数run中启动定时器,大致的 ...
- 隐马尔可夫模型(HMM)总结
摘要: 1.算法概述 2.算法推导 3.算法特性及优缺点 4.注意事项(算法过程,调参等注意事项) 5.实现和具体例子 6.适用场合 内容: 1.算法概述 隐马尔科夫模型(Hidden Markov ...
- 作为一个零基础的新手,如何系统的自学Java和JavaEE开发技术?
其实这个问题很简单,我用最简单的语言给大家描述一下,学习一样东西就要了解这样东西学完了要干什么事情,有什么作用.然后就是应该学习哪些必要的内容,该如何运用得当的方法进行有效率的学习不至于自己摸不着头脑 ...
- 从壹开始 [ Nuxt.js ] 之二 || 项目搭建 与 接口API
前言 哈喽大家周一好,今天的内容比较多,主要就是包括:把前端页面的展示页给搭出来,然后调通接口API,可以添加数据,这两天我也一直在开发,本来想一篇一篇的写,发现可能会比较简单,就索性把项目搭建的过程 ...
- MySQL 复制 - 性能与扩展性的基石 2:部署及其配置
正所谓理论造航母,现实小帆船.单有理论,不动手实践,学到的知识犹如空中楼阁.接下来,我们一起来看下如何一步步进行 MySQL Replication 的配置. 为 MySQL 服务器配置复制非常简单. ...
- 死磕 java集合之PriorityQueue源码分析
问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...
- C#采用vony.Html.AIO插件批量爬MM网站图片
一.创建项目 1.创建一个.netframework的控制台项目命名为Crawler 2.安装nuget包搜索名称Ivony.Html.AIO,使用该类库什么方便类似jqury的选择器可以根据类名或者 ...