LINUX系统写速度问题解决过程

问题描述:

linux系统下写速度只有2GB/s左右,无法支持2.5G采样率连续采集,达不到预期的性能。而同样的代码在windows系统下,却可以支持2.5G采样率连续采集,因此这里需要解决Linux系统的写速度问题。

尝试一:

刚开始以为是API的问题,查看资料发现大部分说法是mmap写文件最快,实际测试下来发现效果一般,没有特别惊艳的表现。加上使用不太方便,否定了这个解决方案。

尝试二:

由于用测速软件测试时,在两个系统里硬盘的顺序读写速度都是7~8GB/s,所以一开始我在Windows系统下对硬盘做了实际的测试,没有用测速软件,而是纯用writefile函数在写,发现读写在6GB/s左右。而且打开”FILE_FLAG_NOBUFFRING”标志位后才有这样的速度,不开的话会慢。如图:

可以看出写速度约为5GB/s,读速度约为6GB/s。

然而我换到Linux系统后,也不用测速软件,纯用write函数,发现它的写速度只有2GB/s,但是读速度却在7GB/s。这让我十分怀疑是否是写操作有什么设置没有打开。一番实验查找之后,我发现Windows的raid卡的写策略是启动了写缓存,如图:

但是我在Linux系统中却没有找到这样的设置或查询。不过在查看内核打印有一句"Write cache disabled,read cache enabled",如图:

可以看出正好是说写缓存关闭而读缓存打开,跟目前测试出来的情况一致。我一度以为已经找到了问题所在,但是使用hdparm磁盘管理工具却没办法查询或设置raid卡的写缓存。

而且这句话是否是描述raid卡的也存疑,在尝试了另外一些设置硬盘写缓存的方法无效后,我放弃了这个解决办法。后来我也确定这句话描述的是另外一个硬盘,而不是我们用的raid卡。

尝试三:

于是我又回到了测试速度的工具上。linux下我用测速软件测得磁盘流盘速度为7000M左右。但是我用另一个linux下很常用的dd命令来测速时却和上个软件相差如此之大,如图:

我想是否是dd命令有一些关于写速度的参数设置,于是仔细研究了dd命令的参数设置后发现:

这些参数其中direct和nonblock跟我们在windows上采用的“FILE_FLAG_NOBUFFING”,即不使用缓冲区直接操作磁盘的方式相似。于是我对这两个做了测试之后,发现在用dd命令时,加上direct参数,跳过系统缓存,直接写到硬盘,在大量数据连续存储时可以提高性能。查资料后发现direct 模式是把写入请求直接封装成 I/O 指令发到磁盘,非 direct 模式只是把数据写入到系统缓存就认为 I/O 成功,并由操作系统决定缓存中的数据什么时候被写入磁盘。

结论:

因此我们可以得出这样一个结论,在linux系统中,IO写入的基本过程

a. 定位用户数据

b. 将用户数据拷贝至内核中(page cache)

先解释一下page cache。page cache是文件在内存中的缓存,打开文件时,先要把文件加载进pache cache,写入时也是一样,先写入page cache,再由page cache刷入磁盘。一般来说,page cache中的数据也是文件的一部分,所以如果数据写入了page cache,就可以认为io操作已安全完成。

上述的过程是一个非常简化的版本,实际的一些api比如fwrite()的实现可能是这样的

---用户层---

a. 定位用户数据

b. 将用户数据拷贝至函数的缓存中(函数调用返回)

---vfs层(即虚拟文件系统)---

c. 将函数缓存拷贝至内核缓存(page cache) (显式或隐式调用fflush() )

d. 将page cache中的脏数据写入磁盘数据区(调用硬盘驱动)

e. 将inode cache中的脏数据写入磁盘inode区(调用硬盘驱动)

---存储控制器层---

到目前为止,写入基本完成,数据被存储控制器接管,由于存储控制器自带板载电容,因此可以认为数据已固化

f. 从板载cache(比如ssd raid 卡)中读取数据

g. 将数据写入磁盘介质

对于linux的write()函数来说,调用在c步就返回了。而对于fwrite()这种经过一次封装的函数来说,它在write之上增加了一层缓冲,也就是说调用fwrite会在b步返回,为了保证数据写入文件,使用fwrite时,可以调用fflush()函数来保证调用到第c步。如果认为此时存储于操作系统的page cache仍不安全,可以继续调用fsync()来保证调用到第e步。(如果到了这里仍然觉得数据不够安全,可以将存储控制器的模式更改为write through,这样可以保证第g步完成后才返回)。

如果打开文件时采用了direct io的方式,可以绕开对于page cache的操作,就是绕过了d步,但是,e步并没有被绕过,因此,使用direct io方式时,为了保证数据的绝对安全,依旧需要调用fsync()来保证文件的元数据(inode等信息)写入磁盘(可以在open时增加O_SYNC,但这样会严重影响效率)。

因此对于写文件时要不要缓冲区这个事情,要从具体的应用角度去看。在需要频繁读取写入数据,并且数据的量不是很大时,通过缓存机制可以有效的提升读写数据的速度,因为当你要读取数据时,系统会先查看你要的数据是否在缓存里,如果在缓存中则直接提取,由于数据还没有真正的刷入硬盘中,因此这个操作是电子层面而非IO层面,速度要快的多。当缓存中的数据多到一定程度,系统才会将不常用的数据真正的写入磁盘。

而这种应用情景,大量数据需要快速的写入硬盘中,全部写完后,用户才有可能会继续回放文件等之类的操作,因此绕开缓存机制,直接以合适的block size循环的写入硬盘,则比用缓存的机制,让系统决定什么时候写入磁盘要快很多。

最后,direct方式是以扇区为单位操作磁盘,因此执行一次写入操作的最小单位是512 Bytes。而且direct方式不常用,在使用时要加一下宏定义_GNU_SOURCE或其他的,否则找不到“O_DIRECT”这个参数,它操作的内存也不能使用平常的定义数组的方式,应该要用mmap或malloc去申请内存,具体使用详情自行百度关键字。

最终的测试结果如图;

以下为测试源码:

#define _GNU_SOURCE 1#define __USE_GNU 1#include <stdio.h>#include <assert.h>#include <fcntl.h>#include <getopt.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <time.h>#include <sys/mman.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>static void *mmap_control(int fd,long mapsize){void *vir_addr;vir_addr = mmap(NULL, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);return vir_addr;}void* pvAllocMemPageAligned (uint64_t qwBytes){void* pvTmp;int fd = open ("/dev/zero", O_RDONLY);pvTmp = (void*) mmap (NULL, qwBytes, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);// set everything to zero to get memory allocated in physical memif (pvTmp != MAP_FAILED)memset (pvTmp, 0, qwBytes);elsepvTmp = NULL;close (fd);return (pvTmp);}// ***********************************************************************void vFreeMemPageAligned (void* pvAdr, uint64_t qwBytes){munmap (pvAdr, qwBytes);}static void timespec_sub(struct timespec *t1, const struct timespec *t2);int main(){printf("CLOCKPERSEC=%ld\n",CLOCKS_PER_SEC);char filename[64] = "/home/sample/SampleData/testspeed_rcv.bin";int file_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC|O_DIRECT, 0666);if(file_fd<0){perror("rcv file err:");}int rc;int size=2*1024*1024;//char buffer[4*1024*1024]={0};void *buffer=NULL;buffer=pvAllocMemPageAligned(4*1024*1024);/*void* control_base;control_base=mmap_control(file_fd,size);if(control_base=NULL||control_base==(void*) -1){printf("映射失败\n");close(file_fd);return -1;}*/struct timespec ts_start, ts_end;clock_gettime(CLOCK_MONOTONIC, &ts_start);clock_t start1,end1;start1=clock();printf("flag1\n");int times=1000;for(int i=0;i<times;i++){//memcpy(control_base,buffer,size);rc= write(file_fd, buffer, size);if(rc!=size){perror("write error:");return -1;}}end1=clock();printf("flag2\n");clock_gettime(CLOCK_MONOTONIC, &ts_end);float dur1=(float)(end1-start1);printf("Cost Time=%f\n",(dur1/CLOCKS_PER_SEC));printf("rc=%d\n",rc);timespec_sub(&ts_end, &ts_start);printf("Cost %ld.%09ld seconds (total) for transfer \n",ts_end.tv_sec, ts_end.tv_nsec);printf("Write Speed=%f\n",(float)(size/1024/1024*times)/(ts_end.tv_sec+ts_end.tv_nsec/1e9));/*if(munmap(control_base,size)==-1){printf("munmap error!\n");}*/close(file_fd);file_fd=open(filename,O_RDWR|O_DIRECT);if(file_fd<0){perror("rcv file err:");}start1=clock();clock_gettime(CLOCK_MONOTONIC, &ts_start);for(int i=0;i<times;i++){//memcpy(control_base,buffer,size);rc= read(file_fd, buffer, size);if(rc!=size){printf("rc=%d\n",rc);}}clock_gettime(CLOCK_MONOTONIC, &ts_end);end1=clock();dur1=(float)(end1-start1);printf("\n\nCost Time=%f\n",(dur1/CLOCKS_PER_SEC));printf("rc=%d\n",rc);timespec_sub(&ts_end, &ts_start);printf("Cost %ld.%09ld seconds (total) for transfer \n",ts_end.tv_sec, ts_end.tv_nsec);printf("Read Speed=%f\n",(float)(size/1024/1024*times)/(ts_end.tv_sec+ts_end.tv_nsec/1e9));close(file_fd);vFreeMemPageAligned(buffer,4*1024*1024);}static void timespec_sub(struct timespec *t1, const struct timespec *t2){assert(t1->tv_nsec >= 0);assert(t1->tv_nsec < 1000000000);assert(t2->tv_nsec >= 0);assert(t2->tv_nsec < 1000000000);t1->tv_sec -= t2->tv_sec;t1->tv_nsec -= t2->tv_nsec;if (t1->tv_nsec >= 1000000000){t1->tv_sec++;t1->tv_nsec -= 1000000000;}else if (t1->tv_nsec < 0){t1->tv_sec--;t1->tv_nsec += 1000000000;}}

linux系统提升硬盘写速度的方法相关推荐

  1. linux多硬盘损坏,Linux裁剪系统时硬盘损坏的解决方法

    Linux裁剪系统时硬盘损坏的解决方法 在进行系统裁剪时,为了减少等待时间,一般会选择将宿主机挂起并直接运行目标系统,然而过于频繁的操作,往往会造成硬盘无法及时同步,造成硬盘分区损坏,从而造成目标系统 ...

  2. 安装Ubuntu Linux系统时硬盘分区最合理的方法

    无论是安装Windows还是Linux操作系统,硬盘分区都是整个系统安装过程中最为棘手的环节,网上的一些Ubuntu Linux安装教程一般都是自动分区,给初学者带来很大的不便,下面我就根据多年来在装 ...

  3. linux 系统迁移到固态硬盘,windows 和 Linux 系统 从硬盘迁移到SSD

    windows 和 Linux 系统 从硬盘迁移到SSD 1. Windows 实验室这次搞了几块三星的ssd,型号是:三星(SAMSUNG) 850 EVO 250G SATA3 固态硬盘 三星有个 ...

  4. linux测试自动化,一种基于Linux系统下自动化测试RoCE性能的方法及系统与流程

    本发明涉及自动化测试的技术领域,特别涉及一种基于Linux系统下自动化测试roce性能的方法及其系统. 背景技术: 现在迅速发展的服务器行业,对网络服务性能提出了越来越高的要求.特别是在互联网行业以及 ...

  5. 怎样大幅度地提升硬盘的速度

    (1)提高读写速度    如果能够减少电磁感应所需要耗费的时间,就能够大幅度提升硬盘内部的读写速度,从而提高硬盘工作状态下的表现,大幅度提升硬盘速度.       但是无论是磁性材料的选择还是磁头的设 ...

  6. linux的常用备份方法,Linux系统下常用的数据备份方法

    Linux系统下常用的数据备份方法 发布时间:2009-10-28 15:11:36来源:红联作者:szlfeng Linux系统下常用的数据备份方法 1.本机上数据的手工备份 Linux系统上配有功 ...

  7. linux服务器视频转换,Linux系统下视频转换软件使用方法

    Linux系统下视频转换软件使用方法 Linux下的视频转换:mencoder 制作适合在智能手机和PDA上观看的mpeg4视频. Linux上有一个很强大的视频音频转换软件,就是Mplayer自带的 ...

  8. Linux系统下锐捷客户端连接方法

    Linux系统下锐捷客户端连接方法 近来学习Linux,但是学校的网络是锐捷的很蛋疼,不想买无线的校园网,只好插上网线看看锐捷的Linux客户端是怎么用的. 百度一波之后找到了一堆教程,然后差不多是挨 ...

  9. Linux系统编程之查看文件大小的方法(lseek_fseek_stat)

    Linux系统编程之查看文件大小的方法(lseek.fseek.stat)三种方法: #include <stdio.h> #include <fcntl.h> #includ ...

最新文章

  1. BZOJ 4665: 小w的喜糖
  2. Python SSH爆破以及Python3线程池控制线程数
  3. 玩转Mixly – 3、Arduino AVR编程 之 控制
  4. 恢复VMware vSphere已孤立的虚拟机
  5. 转:让 ThinkPad 的中键加小红帽模拟鼠标滚轮
  6. 定界符在php中,php定界符如何使用
  7. with grant option 与with admin option的区别
  8. maven 打包报错,target无法删除Failed to clean project: Failed to delete D:\*\target
  9. Win7专业版 下安装ArcGIS desktop 9.3总结
  10. java大量数据导出到Excel
  11. kaggle:NBA球员投篮数据分析与可视化
  12. 嵩天老师python123测验7: 文件和数据格式化 (第7周)
  13. Linux第二课 文件系统目录结构
  14. 使用opencv和C++实现多焦距图像合成
  15. word2vec的参数选择及原理简介
  16. python爬虫学习笔记(三)——淘宝商品比价实战(爬取成功)
  17. C++ 不要忘记指针变量的初始化
  18. vivado 基于cordic IP核的波形发生器
  19. 骑鹤下江南 mysql 安装及配置
  20. 文件夹下的图片名字进行重命名--批量操作

热门文章

  1. 云服务器怎么恢复初始设置
  2. 阿尔法c语言程序设计考试题,计算机考试习题
  3. 计算机10进制化2进制在线,二进制转十进制
  4. java 庖丁解牛api_重磅|庖丁解牛之——Flutter for Web
  5. 用python爬取全国和全球疫情数据,并进行可视化分析(过程详细代码可运行)
  6. [2022 强网杯] devnull 复现
  7. 商人必看的20大电影
  8. zto中通电子面单cpcl打印指令实例
  9. 王者荣耀转系统服务器繁忙,换手机党的福音,王者荣耀开启跨系统角色转移,但这些问题要注意...
  10. AT24C256读取数据