Java NIO-09-零拷贝之 DMA

DMA 的好处

在介绍DMA之前我想问大家:我们为什么要引入DMA,DMA对我们有什么好处那?

计算机系统中各种常用的数据输入/输出方法有查询方式(包括无条件及条件传送方式)和中断方式,这些方式适用于CPU与慢速及中速外设之间的数据交换。

但当高速外设要与系统内存或者要在系统内存的不同区域之间进行大量数据的快速传送时,就在一定程度上限制了数据传送的速率。

直接存储器存取(DMA)就是为解决这个问题提出的,采用DMA方式,在一定时间段内,由DMA控制器取代CPU,获得总线控制权,来实现内存与外设或者内存的不同区域之间大量数据的快速传送。

同时很重要的一点是当DMA传输数据时,并不占用CPU资源,在这个时候CPU可以空出手来做其他的事情。

这样我们既可以做大量数据的高速传输又可以让CPU有时间和资源去做其他的事情。

DMA 芯片的实现

上面介绍了什么是DMA,也介绍了DMA的重要性。那么我们就要看看我们芯片中的DMA了。

在S3C2440A中,我们集成了DMA模块,可以用来传递高速传输数据。既然是数据传输那么我又要问了,我们知道数据传输三要素:源,目的,长度。这是我们数据传输时要知道的。那么在S3C2440A中,源,目的,长度是怎么表示的那?

ps: 硬件知识,暂时不做研究。

DMA映射

基本原理

DMA映射主要为在设备与主存之间建立DMA数据传输通道时,在主存中为该DMA通道分配内存空间的行为,该内存空间也称为DMA缓冲区。

这个任务原本可以很简单,但是由于现代处理器cache的存在,使得事情变得复杂。

RAM与cache内容的一致性问题

出现问题原因

现代处理器为了提升系统性能,在CPU与RAM之间加入了高速缓存cache,所以当在RAM中为一个DMA通道建立一段缓冲区时,必须仔细考虑RAM与cache内容的一致性问题。

具体分析

如果RAM与Device之间的一次数据交换改变了RAM中DMA缓冲区的内容,而cache中缓存了DMA缓冲区对应的RAM中一段内存块。

如果没有机制保护cache中的内容被新的DMA缓冲区数据更新(或者无效),那么cache和他对应的RAM中的一段内存块在内容上出现了不一致,此时如果CPU去读取device传到RAM的DMA缓冲区中的数据,它将直接从cache获得数据,这些数据显然不是它所期望的,因为cache对应的RAM中的数据已经更新了。

解决问题

就cache一致性问题,不同的体系架构有不同的策略,有些是在硬件层面予以保证(x86平台)有些没有硬件支持而需要软件的参与(ARM品台)。

Linux内核中的通用DMA尽力为设备驱动程序提供统一的接口来处理cache缓存一致性的问题,

而将大量品台相关的代码对设备驱动程序隐藏起来。

DMA 的映射方式

1. 一致性DMA映射

linux内核DMA层为一致性DMA映射提供的接口函数为dma_alloc_coherent()

一致性所获得的DMA缓冲区的大小都是页面的整数倍,如果驱动程序需要更小的DMA一致性的DMA缓冲区,则应该使用内核提供的DMA池(pool)机制

对于一致性DMA映射,在分配DMA缓冲区时各平台相关代码已经从根本上解决了cache一致性问题.

但是,一致性映射也会遇到无法克服的困难,主要是指驱动程序中使用的DMA缓冲区并非由驱动程序分配,

大专栏  Java NIO-09-零拷贝之 DMA是来自其他模块(如网络设备驱动程序中用于数据包传输的skb->data所指向的缓冲区),此时需要流式DMA映射。

2. 流式DMA映射

流式DMA映射的特点是DMA传输通道使用的缓冲区不是由当前驱动程序自身分配的,而且往往对每次DMA传输都会重新建立一个流式映射的缓冲区,所以使用流式DMA映射时,
设备驱动程序必须小心负责处理可能出现的cache一致性。

linux内核DMA层为设备驱动提供的建立流式DMA映射的函数—dma_map_single

3. 分散/聚集DMA映射

分散/聚集DMA映射通过将虚拟地址上分散的DMA缓冲区通过一个struct scatterlist的数组或链表组织起来,然后通过一次的DMA传输操作在主存RAM与设备之间传输数据。

分散/聚集DMA映射本质上是通过一次DMA操作把内存中分散的数据块在主存与设备之间进行传输,对于其中的每个数据块内核都会建立对应的一个流式DMA映射。

需要设备的支持。

回弹缓冲区

如果CPU侧虚拟地址对应的物理地址不适合设备的DMA操作,那么需要建立回弹缓冲区,相当于一个 中转站,把数据往设备传输时,驱动程序需要把CPU给的数据拷贝到回弹缓冲区,然后再启动DMA操作。

DMA池

由于DMA映射所建立的缓冲区是单个页面的整数倍,如果驱动程序需要更小的一致性映射的DMA缓冲区,可以使用内核提供的DMA池机制(非常类似于Linux内存管理中的slab机制).

个人收获

参考资料

嵌入式Linux——DMA:在内核中简单使用DMA实现内存中数据传递

Linux内核中DMA分析

Linux DMA驱动构架分析

https://www.xuebuyuan.com/3235513.html

https://www.cnblogs.com/lihuidashen/p/4470678.html

  • DMA

    • DMA 的好处
  • DMA 芯片的实现
  • DMA映射
    • 基本原理
    • RAM与cache内容的一致性问题
      • 出现问题原因
      • 具体分析
    • 解决问题
  • DMA 的映射方式
    • 1. 一致性DMA映射
    • 2. 流式DMA映射
    • 3. 分散/聚集DMA映射
  • 回弹缓冲区
  • DMA池
  • 个人收获
  • 参考资料

原文地址:https://www.cnblogs.com/lijianming180/p/12251308.html

时间: 2024-10-10 20:02:54

Java NIO-09-零拷贝之 DMA的相关文章

Java IO和Java NIO在文件拷贝上的性能差异分析 (转)

1.       在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取 到用户空间的缓冲区.参看read(byte b[])方法的源码,可知,它会在内部再调用readBytes(b, 0, b.length)方法,而且readBytes(b, 0, b.length)方法是一个native方法(即本地方法),最终通过这个本地方法来发起一次系统调用,即调用系统内核的read()

7. NIO与零拷贝

一.零拷贝 1.介绍 零拷贝描述的是CPU不执行拷贝数据从一个存储区域到另一个存储区域的任务,这通常用于通过网络传输一个文件时以减少CPU周期和内存带宽. 优点: 减少甚至完全避免不必要的CPU拷贝,从而让CPU解脱出来去执行其他的任务 减少内存带宽的占用 通常零拷贝技术还能够减少用户空间和操作系统内核空间之间的上下文切换 2.传统copy机制 Java 传统 IO 和 网络编程的一段代码: 1 File file = new File("test.txt"); 2 RandomAcc

Java IO和Java NIO在文件拷贝上的性能差异分析

1.  在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区.参看read(byte b[])方法的源码,可知,它会在内部再调用readBytes(b, 0, b.length)方法,而且readBytes(b, 0, b.length)方法是一个native方法(即本地方法),最终通过这个本地方法来发起一次系统调用,即调用系统内核的read()方法,内核从

Java零拷贝

1.摘要 java 的zero copy多在网络应用程序中使用.Java的libaries在linux和unix中支持zero copy,关键的api是java.nio.channel.FileChannel的transferTo(),transferFrom()方法.我们可以用这两个方法来把bytes直接从调用它的channel传输到另一个writable byte channel,中间不会使data经过应用程序,以便提高数据转移的效率. 2.介绍 java 的zero copy多在网络应用程

零拷贝Zero copy-linux and java

背景-几种拷贝方式 方式1:Copying in Two Sample System Calls read(file, tmp_buf, len); write(socket, tmp_buf, len); 首先,调用read时,文件A copy到了kernel模式: 之后,CPU控制将kernel模式数据copy到user模式下: 调用write时,先将user模式下的内容copy到kernel模式下的socket的buffer中: 最后将kernel模式下的socket buffer的数据c

java的零拷贝机制

转:https://blog.csdn.net/zhouhao88410234/article/details/77574689?fps=1&locationNum=9 为何要懂零拷贝原理?因为rocketmq存储核心使用的就是零拷贝原理. io读写的方式 中断 DMA 中断方式 中断方式的流程图如下: 用户进程发起数据读取请求 系统调度为该进程分配cpu cpu向io控制器(ide,scsi)发送io请求 用户进程等待io完成,让出cpu 系统调度cpu执行其他任务 数据写入至io控制器的缓冲

Java NIO.2 —— 文件或目录拷贝操作

拷贝整个文件树是可以递归每个目录和文件调用 Files.copy()方法.在使用的时候有一下注意事项. 在往目录拷贝文件之前,首先要保证目录已经存在.拷贝源目录(不论是否为空)都会生成目标目录.整个任务一定在preVisitDirectory()方法中执行. visitFile()方式用来拷贝每个文件最佳的方法. 在你拷贝目录或文件时,你需要决定是否要使用REPLACE_EXISTING 和COPY_ATTRIBUTES 选项. 如果你想保存要拷贝的目录的属性,你需要在postVisitDire

从rocketMQ到零拷贝

rocketMQ是阿里的开源MQ,号称很强大很强大 rocketMQ的网络实现是依赖netty http://my.oschina.net/plucury/blog/192577 这篇文章中描述了netty的零拷贝实现: 根据文中的描述,"Linux中的sendfile()以及Java NIO中的FileChannel.transferTo()方法都实现了零拷贝的功能",似乎"FileChannel.transferTo()和sendfile()是同一层的实现",n

java nio使用方法(转)

最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下,顺便写点东西,就当是自己学习 Java NIO的笔记了.本文为NIO使用及原理分析的第一篇,将会介绍NIO中几个重要的概念. 在Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,面向流的I/O速度