DSP

dma传输与memcpy传输对比测试结果分析。。。

2019-07-13 17:06发布

本来拟定是想直接在x86的服务器上测试,但是发现执行时一直获取不到dma通道,只能在arm架构下尝试。
1.测试代码,如下,网上找的,驱动的环境搭建之前 /* * DMA test module * * Copyright (C) 2007 KEDACOM Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define XFER_TIMES 4000 #define XFER_LEN 1<<20 void *dma_src,*dma_dest; struct dma_chan *chan = NULL; static int __init dmatest_init(void) { int xfer_order = get_order(XFER_LEN); int i,ret ; dma_cap_mask_t mask; dma_cookie_t cookie; enum dma_status status; u64 j1,j2; dma_src = __get_free_pages(GFP_KERNEL | GFP_DMA, xfer_order); if (!dma_src) { printk(KERN_ALERT "dma_src :alloc memory fail.n"); ret = -ENOMEM; goto CLEAN; } dma_dest = __get_free_pages(GFP_KERNEL | GFP_DMA, xfer_order); if (!dma_dest) { printk(KERN_ALERT "dma_dest :alloc memory fail.n"); ret = -ENOMEM; goto CLEAN; } printk(KERN_NOTICE"dma_src=%#x,dma_dest=%#xn",dma_src,dma_dest); dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); chan = dma_request_channel(mask, NULL, NULL); if (chan) { printk(KERN_NOTICE "dma_request_channel ok,current channel is : %sn",dma_chan_name(chan)); }else { printk(KERN_NOTICE "dma_request_channel fail,no dma channel available.n"); ret = -1; goto CLEAN; } j1 = get_jiffies_64(); for(i =0;iif (dma_submit_error(cookie)) { printk(KERN_NOTICE"submit errorn"); ret = -1; goto CLEAN; } } dma_async_memcpy_issue_pending(chan); do { status = dma_async_memcpy_complete(chan, cookie, NULL, NULL); } while (status == DMA_IN_PROGRESS); if (status != DMA_SUCCESS) printk(KERN_NOTICE "dma xfer dont accomplish,status=%dn",status); j2 = get_jiffies_64(); printk(KERN_NOTICE"dma xfer time cost:%d ms.n",jiffies_to_msecs(j2-j1)); j1 = get_jiffies_64(); for(i =0;imemcpy(dma_dest, dma_src, XFER_LEN); } j2 = get_jiffies_64(); printk(KERN_NOTICE"memcpy time cost:%d ms.n",jiffies_to_msecs(j2-j1)); return 0; CLEAN: if (chan) dma_release_channel(chan); if (dma_src) free_pages(dma_src,xfer_order); if (dma_dest) free_pages(dma_dest,xfer_order); return ret; } /* when compiled-in wait for drivers to load first */ module_init(dmatest_init); static void __exit dmatest_exit(void) { if (chan) dma_release_channel(chan); if (dma_src) free_pages(dma_src,get_order(XFER_LEN)); if (dma_dest) free_pages(dma_dest,get_order(XFER_LEN)); } module_exit(dmatest_exit); MODULE_AUTHOR("ZhangZhuan "); MODULE_LICENSE("GPL v2"); [1]
从网上down了一份驱动测试代码 2.测试过程
初始执行结果:dma_request_channel fail, no dma channel available,n
(1)打开dma通道
使用hdparm命令,
执行:hdparm -d1 /dev/sda
其中d 1表示使能DMA,你可以将其加到rc.locl中以便每次启动时都硬盘都能使用DMA方式传输数据。
结果:HDIO_GET_DMA failed: Inappropriate ioctl for device
调试:
网上有类似的返回打印,
“通过dmesg | grep [^d]ata
[ 28.210551] libata version 3.00 loaded.
[ 28.476513] pata_amd 0000:00:06.0: version 0.3.10
[ 28.483189] scsi0 : pata_amd
[ 28.485133] scsi1 : pata_amd
[ 28.485809] ata1: PATA max UDMA/133 cmd 0x1f0 ctl 0x3f6 bmdma 0xf000 irq 14
[ 28.485813] ata2: PATA max UDMA/133 cmd 0x170 ctl 0x376 bmdma 0xf008 irq 15
[ 28.997204] ata1.00: ATA-6: ST340014A, 8.01, max UDMA/100
[ 28.997209] ata1.00: 78165360 sectors, multi 16: LBA48
[ 28.997229] ata1.01: ATAPI: TSSTcorpDVD-ROM TS-H352C, CH01, max UDMA/33
[ 29.013102] ata1.00: configured for UDMA/100
[ 29.200806] ata1.01: configured for UDMA/33
[ 29.200847] ata2: port disabled. ignoring.
[ 29.202076] sata_nv 0000:00:08.0: version 3.5
[ 29.203546] scsi2 : sata_nv
[ 29.204104] scsi3 : sata_nv
[ 29.204314] ata3: SATA max UDMA/133 cmd 0x9f0 ctl 0xbf0 bmdma 0xdc00 irq 19
[ 29.204318] ata4: SATA max UDMA/133 cmd 0x970 ctl 0xb70 bmdma 0xdc08 irq 19
[ 29.512437] ata3: SATA link down (SStatus 0 SControl 300)
[ 29.832255] ata4: SATA link down (SStatus 0 SControl 300)
pata是并口硬盘(即IDE硬盘),sata是串口硬盘,DMA只属于pata的概念,而不属于sata, 因此,如果系统中的硬盘是由sata驱动的pata硬盘(即IDE硬盘),那么用hdparm检测得出的 HDIO_GET_DMA failed: Inappropriate ioctl for devic 的信息完全是正常的。 我的硬盘是IDE的,但我网络安装的Ubuntu里面强行使用sata驱动,我也只能用它,如果想改变的话重新编译内核应该可以解决。虽然硬盘旧,但我的主板有sata接口,以后买新硬盘记住要买串口的”【2】 经过查看,本机上并不是IDE硬盘,又有另一种对于SATA硬盘: ------------------------------------------------------------------------------------------------------------------------- [root@anima lwg]# /sbin/hdparm -t /dev/sda /dev/sda: Timing buffered disk reads: 100 MB in 3.02 seconds = 33.11 MB/sec [root@anima lwg]# /sbin/hdparm -c 1 -d 1 /dev/sda /dev/sda: setting 32-bit IO_support flag to 1 HDIO_SET_32BIT failed: Invalid argument setting using_dma to 1 (on) HDIO_SET_DMA failed: Inappropriate ioctl for device IO_support = 0 (default 16-bit) [root@anima lwg]#sudo hdparm -i /dev/sda 查看UDMA使用模式,带*号的为正在使用的模式 查看控制器: --------------------------- [root@anima lwg]# /sbin/lspci -v | grep IDE 00:0f.0 IDE interface: VIA Technologies, Inc. VIA VT6420 SATA RAID Controller (rev 80) (prog-if 8f [Master SecP SecO PriP PriO]) 00:0f.1 IDE interface: VIA Technologies, Inc. VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06) (prog-if 8a [Master SecP PriP]) [root@anima lwg]# 打开内核的SATA选项,则不能使用SATA的DMA模式,否则使用/sbin/hdparm命令时会出错。 查看内核配置: [root@anima lwg]# cat /boot/config-2.6.9-42.0.10.EL | grep ATA # CONFIG_X86_MCE_NONFATAL is not set # ATA/ATAPI/MFM/RLL support # CONFIG_BLK_DEV_IDE_SATA is not set CONFIG_SCSI_SATA=y CONFIG_SCSI_SATA_AHCI=m CONFIG_SCSI_SATA_SVW=m CONFIG_SCSI_ATA_PIIX=m CONFIG_SCSI_SATA_MV=m CONFIG_SCSI_SATA_NV=m CONFIG_SCSI_SATA_QSTOR=m CONFIG_SCSI_SATA_PROMISE=m CONFIG_SCSI_SATA_SX4=m CONFIG_SCSI_SATA_SIL=m CONFIG_SCSI_SATA_SIL24=m CONFIG_SCSI_SATA_SIS=m CONFIG_SCSI_SATA_ULI=m CONFIG_SCSI_SATA_VIA=m CONFIG_SCSI_SATA_VITESSE=m CONFIG_SCSI_SATA_INTEL_COMBINED=y # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_ATALK is not set CONFIG_USB_STORAGE_DATAFAB=y # CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set # CONFIG_ATARI_PARTITION is not set [root@anima lwg]# 需要打开内核的如下两个选项:
CONFIG_SCSI_SATA=y
CONFIG_SCSI_ATA_PIIX=y
重新编译内核。 如果你的SATA为启动盘的话,可能需要把原来/boot/grub/grub.conf 和 /etc/fstab 中的hda更改为sda,其他的驱动器名称也可能需要进行更改。[3]
按照上述操作后的结果: CONFIG_SCSI_SAS_ATA=y # CONFIG_SCSI_EATA is not set 3.测试结论
dma一般用于内存和外设间的传输。arm下支持内存到内存的传输。x86下内存到内存不支持?
请教专家后得到的结论,前面看到的硬盘上的这种DMA都是在SATA总线控制器下,其DMA请求都是SATA Device向外主动发出的。而x86下目前没有看到单独的挂载在总线上的DMA芯片,所以也没有可以直接用来进行内存DDR到内存DDR的拷贝。但是arm架构下,所有的CPU,DDR芯片,SATA设备都是挂载L2总线上的,因此能够通过DMA芯片来完成多片或者内部DDR的DMA请求。 背景知识:
Q:
A:hdparm
-T perform cache read timings显示了不存取磁盘直接从Linux缓存读取数据的速度. 这项测量实际上标示了被测系统的处理器,缓存和内存的吞吐量. -t perform device read timings显示了不使用预先的数据缓冲, 标示了Linux下没有任何文件系统开销时磁盘可以支持多快的连续数据读取. 关于硬盘是否打开DMA等情况,请不要在使用hdparm -d查询,原因是系统将你的硬盘被认作了/dev/sda,那么就是内核使用libata来支持你的硬盘(实际是IDE接口)。btw:现在的libata已经做得非常好了。
如果你对于libata有些认识的话,上面提到的红字部分就不是问题了。
引用:
HDIO_SET_32BIT failed: Invalid argument libata不支持32bit操作,将来也许会支持,可能性不大.实际上也没有必要,具体可以查看相关知识以及 http://linux-ata.org
引用:
HDIO_SET_DMA failed: Inappropriate ioctl for device libata默认使用DMA来传输数据,对于一些新型的硬盘,特别是SATA控制器的硬盘,DMA是基本的要求。
所以libata是不会同意你去修改DMA设置的,尽管你想打开,但是如果你想关闭呢,想想看如果系统使用SATA控制器在没有DMA的情况下如何传输数据,性能将会是什么性能,甚至硬盘都无法工作。相信你也不会同意随意修改DMA,再一次尽管你是想打开他。 那么如何查看硬盘的工作状态,可以使用
代码:
sudo hdparm -i /dev/sda
查看硬盘摘要信息,注意里面关于DMA部分,比如我的
代码:
UDMA modes: udma0 udma1 udma2 udma3 udma4 *udma5 其中udma5前面的星号表示该硬盘工作于udma5模式。
或者使用
代码:
sudo hdparm -I /dev/sda
查看硬盘详细信息。 从某种程度上来说,libata支持的硬盘控制器基本告别hdparm了。 Q:request_dma和dma_reque_channel这套好像不太一样,request_dma参数中的dmanr是否会自动分配?
A:
1. 系统会不会自动分配?
不会,只有ISA接口卡才会使用request_dma来向系统申请dma通道,PCI以后的设备都不再使用系统dma通道。源码为证:
int request_dma(unsigned int dmanr, const char * device_id)
{
if (dmanr >= MAX_DMA_CHANNELS)
return -EINVAL; if (xchg(&dma_chan_busy[dmanr].lock, 1) != 0) return -EBUSY; dma_chan_busy[dmanr].device_id = device_id; /* old flag was 0, now contains 1 to indicate busy */ return 0; } /* request_dma */ 可以看出来,或者你指定的dma通道分配成功,或者失败,没有自动分配一说。问什么会失败,后面会讲
  1. 如何确定dma通道号这个参数?
    在ISA系统中,每个接口卡有一对DREQ/DACK,你查看硬件电路可以知道这对线和8237A的哪一对DREQ/DACK连在一起的,如果连接到8237A的通道0,这个参数就是0,如果是通道7,那这个参数就是7.软驱一般都是接到通道0,所以看软驱代码,申请的也是0号通道:
    drivers/acorn/block/fd1772.c
    if (request_dma(FLOPPY_DMA(0), “fd1772”)) {
    printk(“Unable to grab DMA%d for the floppy (1772) driver ”, FLOPPY_DMA);
    goto err_blkdev;
    };
  2. 为什么会分配冲突?
    ISA总线上可能会有多个slot,由于只有7个通道可用,如果两块卡不小心用了同一个dma通道,那么就会有一个设备的dma通道申请失败。
引文参考:
[1]http://www.ithao123.cn/content-8026108.html
[2]http://blog.chinaunix.net/uid-20587169-id-1919228.html
[3]http://blog.sina.com.cn/s/blog_59b0e3f30100ly7i.html