我有一个大学作业,我必须创建一个 RAM 磁盘。
我被告知然后制作一个 C 程序,该程序在 RAM Disk 内的文件上多次写入,然后在硬盘上的文件上执行相同的操作以比较写入速度。
为了创建 RAM 磁盘,我得到了以下脚本:
#!/bin/bash
# RAM Disk
ROOTUSER_NAME=root
MOUNTPT=/tmp/ramdisk
SIZE=2024 # 2K blocs
BLOCKSIZE=1024 # block size: 1K (1024 bytes)
DEVICE=/dev/ram0 # First RAM Disk
username=`id -nu`
[ "$username" != "$ROOTUSER_NAME" ] && echo "not authorised" && exit 1
[ ! -d "$MOUNTPT" ] && mkdir $MOUNTPT
dd if=/dev/zero of=$DEVICE count=$SIZE bs=$BLOCKSIZE
/sbin/mkfs -t ext4 $DEVICE
mount $DEVICE $MOUNTPT # the mount
chmod 777 $MOUNTPT
echo $MOUNTPT " ready"
exit 0
这里的问题是我的机器似乎没有/dev/ram0
在/dev
目录中;这是输出ls /dev
:
ferran@amsa:~/Desktop$ ls /dev
autofs lightnvm sda tty22 tty5 ttyS18 vcs3
block log sda1 tty23 tty50 ttyS19 vcs4
bsg loop0 sda2 tty24 tty51 ttyS2 vcs5
btrfs-control loop1 sda3 tty25 tty52 ttyS20 vcs6
bus loop2 sda5 tty26 tty53 ttyS21 vcsa
cdrom loop3 sg0 tty27 tty54 ttyS22 vcsa1
cdrw loop4 sg1 tty28 tty55 ttyS23 vcsa2
char loop5 shm tty29 tty56 ttyS24 vcsa3
console loop6 snapshot tty3 tty57 ttyS25 vcsa4
core loop7 snd tty30 tty58 ttyS26 vcsa5
cpu loop8 sr0 tty31 tty59 ttyS27 vcsa6
cpu_dma_latency loop9 stderr tty32 tty6 ttyS28 vcsu
cuse loop-control stdin tty33 tty60 ttyS29 vcsu1
disk mapper stdout tty34 tty61 ttyS3 vcsu2
dma_heap mcelog tty tty35 tty62 ttyS30 vcsu3
dmmidi mem tty0 tty36 tty63 ttyS31 vcsu4
dri midi tty1 tty37 tty7 ttyS4 vcsu5
dvd mqueue tty10 tty38 tty8 ttyS5 vcsu6
ecryptfs net tty11 tty39 tty9 ttyS6 vfio
fb0 null tty12 tty4 ttyprintk ttyS7 vga_arbiter
fd nvram tty13 tty40 ttyS0 ttyS8 vhci
full port tty14 tty41 ttyS1 ttyS9 vhost-net
fuse ppp tty15 tty42 ttyS10 udmabuf vhost-vsock
hidraw0 psaux tty16 tty43 ttyS11 uhid vmci
hpet ptmx tty17 tty44 ttyS12 uinput zero
hugepages pts tty18 tty45 ttyS13 urandom zfs
hwrng random tty19 tty46 ttyS14 userio
initctl rfkill tty2 tty47 ttyS15 vcs
input rtc tty20 tty48 ttyS16 vcs1
kmsg rtc0 tty21 tty49 ttyS17 vcs2
这是输出fdisk -l
:
ferran@amsa:~/Desktop$ sudo fdisk -l
[sudo] password for ferran:
Disk /dev/loop0: 4 KiB, 4096 bytes, 8 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop1: 55,45 MiB, 58130432 bytes, 113536 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop2: 65,22 MiB, 68378624 bytes, 133552 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop3: 55,51 MiB, 58191872 bytes, 113656 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop4: 65,1 MiB, 68259840 bytes, 133320 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop5: 50,98 MiB, 53432320 bytes, 104360 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop6: 32,3 MiB, 33865728 bytes, 66144 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/loop7: 32,45 MiB, 34017280 bytes, 66440 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk /dev/sda: 100 GiB, 107374182400 bytes, 209715200 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x70d3f840
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 117186559 117184512 55,9G 83 Linux
/dev/sda2 117188606 132810751 15622146 7,5G 5 Extended
/dev/sda3 132810752 132812799 2048 1M 82 Linux swap / Solaris
/dev/sda5 117188608 132810751 15622144 7,5G 82 Linux swap / Solaris
Partition table entries are not in disk order.
Disk /dev/loop8: 219 MiB, 229638144 bytes, 448512 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
对于写入速度测试,我使用以下 C 程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10000000
int main(int argc, char *argv[]){
char *c = /* This is compiled into one long string, with no newlines. */
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, "
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
"Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat. "
"Duis aute irure dolor in reprehenderit in voluptate velit esse "
"cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui "
"officia deserunt mollit anim id est laborum.";
FILE *fp;
fp = fopen(argv[1],"w");
for(int i=0; i < MAX; i++){
fputs(c,fp);
fseek(fp, 0, SEEK_SET);
}
fclose(fp);
}
我叫它两次:
./writeTest ~/Desktop/test
./writeTest /tmp/ramdisk/test
而且结果也不是很令人信服,因为RAM Disk文件需要8s,而硬盘文件需要11s,这似乎不是我应该得到的改进,对吧?
当我运行 bash 脚本时,/dev/ram0
它会被创建,但我不知道这是否应该发生并且写入速度的提高是否符合预期,或者我是否应该已经/dev/ram0
在我的/dev
目录中创建了一个。
任何帮助,将不胜感激。
编辑1:
我根据@user1686 所说的做了一些更改。首先我加载了需要的模块modprobe brd
,然后全部出现了。/dev/ram#
然后,我尝试改进我的 C 程序以减少seek
调用,即使我知道以这种方式测试写入速度仍然不是最好的主意,我被告知使用 C 程序来做(也许目标是只是我们在 RAM 而不是硬盘上写入时看到了改进,而不是我们知道写入速度的确切增量)。
为了减少seek
调用,我将 RAM Disk 做得更大(从 2 MB 变为 32 MB),然后我没有调用seek
循环的每次迭代,而是估计了写入近 32 MB 所需的循环次数,然后每次MAX
迭代我打电话seek
,最后重复外循环LOOPS
次数。
该程序如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LOOPS 50
#define MAX 70000
int main(int argc, char *argv[]){
char *c = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor inci";
FILE *fp;
fp = fopen(argv[1],"w");
for(int i=0; i < LOOPS; i++){
for(int i=0; i < MAX; i++){
fputs(c,fp);
}
fseek(fp, 0, SEEK_SET);
}
fclose(fp);
}
有了这个新版本,并且主硬盘和 RAM 磁盘都安装了该sync
选项,我设法提高了 30 倍的速度,并且随着我增加LOOPS
.
是也不是,但大多不是。
Linux 确实有一个可以提供
/dev/ram#
设备的“ramdisk”驱动程序,它可能在您的系统上可用,但默认情况下通常不加载,除非您先加载该驱动程序,否则这些设备节点将不存在。为此,插入brd.ko
内核模块,您应该得到 8 或 16 个ram
设备:如果未加载驱动程序,并且您的脚本盲目地使用 来创建 /dev/ram0
dd
,那么它并没有以这种方式创建 ramdisk - 它创建了一个文件。(您实际上应该在加载“brd”驱动程序之前删除它。)但是,幸运的是,即使 /dev/ram0 不可用,您的脚本最终仍能实现“更好的写入速度”的目标。这是因为在大多数 Linux 系统上,整个 /dev 并不存储在物理磁盘上,而是
tmpfs
挂载了一个文件系统1。“tmpfs”已经在内存中——它有点像使用 ramdisk,除了 ramdisk 是固定大小的并且需要与另一个文件系统组合,而 tmpfs 是动态大小的。
因此,您在 /dev 中创建的任何新文件 - 有时在 /tmp 中也是如此2 - 将完全存储在内存中。即使您的脚本没有建立一个真正的老式“ramdisk”,而只是创建了一个名为“/dev/ram0”的常规文件3,它存储在 tmpfs 上的事实意味着您仍然可以获得预期的速度提升。4
(但您也可以通过将 ./writeTest 程序直接指向 /dev/testfile 来实现这一点。)
所以简而言之,虽然 Linux 有 ramdisk,但 tmpfs 是几乎所有情况下 ramdisk 的现代替代品。你不需要决定它的大小,或者明确地“mkfs”一个文件系统——只要在你需要的地方挂载一个 tmpfs:
1(在当今大多数Linux 系统上,/dev 使用“devtmpfs”,这是一种特殊的 tmpfs 变体,其中设备节点会在驱动程序识别设备后立即自动出现;例如,一旦您加载“brd”驱动程序,/dev/ ram0 将完全独立出现。但除此之外,它的行为类似于常规 tmpfs。)
2(使用
findmnt
或mount
检查您的发行版是否确实在 /tmp 上安装了 tmpfs。)3(即使它是一个文件,您仍然可以像磁盘一样挂载它,因为该
mount
命令在 2011 年更新为自动设置“循环设备”而无需-o loop
指定。)您看到两个测试运行同样快的一个原因是写入缓冲在内存中 - 您的程序不会等待每个写入完全提交到磁盘,然后再继续下一个;相反,所有内容都在短时间内写入磁盘。
(并且由于您的程序会回溯到 0 并完全覆盖数据,因此可能不需要从缓冲区移动到磁盘的太多内容。)
您看到这两个测试运行速度很快的另一个原因是现代 HDD非常快,而 SSD 更是如此。同时,如果你的任务要求你设置一个 ramdisk,那让我认为它是在 1999 年编写的,期望磁盘速度达到数十 MB/s。