#import "template/module.typ": * #show: default.with( title: "Memory and Storage System - HW1 FIO", authors: (( name: "Yi-Ting Shih (111550013)", affiliation: "National Yang Ming Chaio Tung University", email: "ytshih@cs.nycu.edu.tw", ),), ) = Specifications All the read operations except bonus are tested on ssd. \ Model: Micron CT1000P3PSSD8@ct1000p3pssd8 (Crucial P3 Plus) All the write operations are tested on disk files, which are in a RAID 1 btrfs@btrfs filesystem. The tested operating system was Arch Linux@archlinux, which was running Linux kernel 6.14.2.arch1-1. = Questions == Q0. Example === Result #code(read("code/q0.output")) == Q1. Read vs. Randread === Result #code(read("code/q1.output")) === Question Is there any significant difference between read and randread? Why or why not? Please justify your answer in brief. === Answer _read_ is significantly faster than _randread_. The SSD controller might be optimized for sequential access, such as leveraging internal parallelism more effectively, or have lower command overheader perunit of data for sequential reads. == Q2. Write vs. Randwrite === Result #code(read("code/q2.output")) === Question Is there any significant difference between write and randwrite? Why or why not? Please justify your answer in brief. === Answer There is no significant difference between _write_ and _randwrite_. The SSD controller will go through the page / block translation process no matter there is write or random write access. Therefore there is no significant difference. Also, I use disk file to test the write operation, which is on a btrfs filesystem. There are cache on btrfs@btrfs or page cache so the data might not be actually write to the SSD. == Q3. Forward write vs. Backward write === Result #code(read("code/q3.output")) === Question Is there any significant difference between forward and backward write? Why or why not? Please justify your answer in brief. === Answer There is no significant difference between _forward write_ and _backward write_. The reason is same as the previous question. == Q4. Buffered read vs. Nonbuffered read === Result #code(read("code/q4.output")) === Question + Is there any significant difference between buffered and nonbuffered sequential read? Why or why not? Please justify your answer in brief. + Replace sequential read with random read. Is there any significant difference between buffered and nonbuffered random read? Why or why not? Please justify your answer in brief. === Answer - _buffered sequential read_ is significantly faster than _non-buffered sequential read_. - There is no significant difference between _buffered random read_ and _non-buffered random read_. The data can be buffered by _read-ahead_ for sequential read operation. This cannot be done for random read operation, because the next read operation cannot be predicted. == Q5. LBA === Result #code(read("code/q5.output")) === Question Is there any bandwidth trend between these jobs? Why or why not? Please justify your answer in brief. You can also experiment with the size of the file. === Answer The job where `offset=80%` is faster than `offset=60%`, and `offset=60%` is faster than the rest of the jobs. The identified response presents an analysis of experimental results; the underlying theoretical framework remains unclear, necessitating further investigation. == Q6. Blocksize === Result #code(read("code/q6.output")) === Question + Is there any significant difference between 4k and 1k read? Why or why not? Please justify your answer in brief. + If you want to achieve the best performance in the condition above, how would you modify `blocksize`? Explain it briefly. === Answer - _4k read_ is significantly faster than _1k read_ in terms of bandwidth and latency. - The bandwidth can be increased by changing `blocksize` to up to `8m`. Larger `blocksize` might be useful when doing large sequential read. == Q7. Fastest nonbuffered read === Result #code(read("code/q7.output")) === Question Please explain how you achieve the fastest 1G nonbuffered read in brief. === Answer According to the result in the previous questions, namely, Q5 and Q6, the fastest non-buffered read happens when `offset=80%` and `blocksize=8m`. Furthermore, I have tested the difference between `ioengine=psync`, which is the default for fio, and `ioengine=libaio`, which is Linux native asynchoronous I/O. The result shows that `ioengine=libaio` is better in terms of bandwidth. For asynchoronous I/O, I also tested the impact of the `iodepth`. The result showes that `iodepth=64` will reach the peak bandwidth. Therefore, the fastest non-buffered 1G read should be the combination of `offset=80%`, `blocksize=8m`, `ioengine=libaio`, and `iodepth=64`. == Bonus === Result #code(read("code/bonus.output")) === Question + Compare with multiple kinds of storage devices. \ Is there any significant difference between read/randread on storage devices? Why or why not? Please justify your answer in brief. + Find the specs of your own hardware that you tested on. \ Is your hardware running to spec? If not, could you come up with a possible theory? === Answer This experiment include two storage devices, Crucial P3 Plus M.2 SSD@ct1000p3pssd8 (Disk 1) and WD Blue HDD@wd10ezex (Disk 2). The hardware sequential read rate for Disk 1 is 5000MB/s. And the hardware transfer rate for Disk 2 is up to 150MB/s. The result for the experiment shows that + Disk 1 (SSD) is significantly faster than Disk 2 (HDD). + Disk 1 is quite a bit slower than the hardware spec (about 3400MB/s). + Disk 2 is faster than the hardware spec (about 170MB/s). The reason for the underperformance of Disk 1 might be - I'm using Disk 1 to run my OS at the same time, which interferes the result. - Disk 1 had been used for over 4 years and had used up 50% of the capacity. In constract, Disk 2 was seldom used and didn't used up any of the capacity. #bibliography("bibliography.yml")