On 3/12/25 11:02, Chao Yu wrote: > On 3/12/25 03:36, Jaegeuk Kim wrote: >> On 03/11, Chao Yu wrote: >>> On 3/4/25 09:10, Jaegeuk Kim via Linux-f2fs-devel wrote: >>>> From: Jaegeuk Kim <jaeg...@google.com> >>>> >>>> This adds a fragread command in f2fs_io, which is able to measure the >>>> read performance on fragmented data buffer. >>>> >>>> Signed-off-by: Jaegeuk Kim <jaeg...@google.com> >>>> --- >>>> tools/f2fs_io/f2fs_io.c | 110 ++++++++++++++++++++++++++++++++++++++++ >>>> 1 file changed, 110 insertions(+) >>>> >>>> diff --git a/tools/f2fs_io/f2fs_io.c b/tools/f2fs_io/f2fs_io.c >>>> index b72c26648f56..8431262575e0 100644 >>>> --- a/tools/f2fs_io/f2fs_io.c >>>> +++ b/tools/f2fs_io/f2fs_io.c >>>> @@ -1018,6 +1018,115 @@ static void do_read(int argc, char **argv, const >>>> struct cmd_desc *cmd) >>>> exit(0); >>>> } >>>> >>>> +#define fragread_desc "read data with a fragmented buffer from file" >>>> +#define fragread_help \ >>>> +"f2fs_io fragread [chunk_size in 4kb] [offset in chunk_size] [count] >>>> [advice] [file_path]\n\n" \ >>>> +"Read data in file_path and print nbytes\n" \ >>>> +"advice can be\n" \ >>>> +" 1 : set sequential|willneed\n" \ >>>> +" 0 : none\n" \ >>>> + >>>> +#ifndef PAGE_SIZE >>>> +#define PAGE_SIZE sysconf(_SC_PAGESIZE) >>>> +#endif >>>> +#define ALLOC_SIZE (2 * 1024 * 1024 - 4 * 1024) // 2MB - 4KB >>>> + >>>> +static void do_fragread(int argc, char **argv, const struct cmd_desc *cmd) >>>> +{ >>>> + u64 buf_size = 0, ret = 0, read_cnt = 0; >>>> + u64 offset; >>>> + char *buf = NULL; >>>> + uintptr_t idx, ptr; >>>> + unsigned bs, count, i; >>>> + u64 total_time = 0; >>>> + int flags = 0, alloc_count = 0; >>>> + void *mem_hole, **mem_holes; >>>> + int fd, advice; >>>> + >>>> + if (argc != 6) { >>>> + fputs("Excess arguments\n\n", stderr); >>>> + fputs(cmd->cmd_help, stderr); >>>> + exit(1); >>>> + } >>>> + >>>> + bs = atoi(argv[1]); >>>> + if (bs > 256 * 1024) >>>> + die("Too big chunk size - limit: 1GB"); >>>> + buf_size = bs * F2FS_DEFAULT_BLKSIZE; >>>> + >>>> + offset = atoi(argv[2]) * buf_size; >>>> + count = atoi(argv[3]); >>>> + advice = atoi(argv[4]); >>>> + mem_holes = xmalloc(sizeof(void *) * (buf_size / PAGE_SIZE)); >>>> + >>>> + /* 1. Allocate the buffer using mmap. */ >>>> + buf = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, >>>> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); >>>> + >>>> + /* 2. Loop and touch each page. */ >>>> + for (idx = (uintptr_t)buf; idx < (uintptr_t)buf + buf_size; >>>> + idx += PAGE_SIZE) >>>> + { >>>> + /* Touch the current page. */ >>>> + volatile char *page = (volatile char *)idx; >>>> + *page; >>>> + >>>> + /* 3. Allocate (2M - 4K) memory using mmap and touch all of it. >>>> */ >>>> + mem_hole = mmap(NULL, ALLOC_SIZE, PROT_READ | PROT_WRITE, >>>> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); >>>> + if (mem_hole == MAP_FAILED) >>>> + die_errno("map failed"); >>>> + >>>> + /* Store the allocated memory pointer. */ >>>> + mem_holes[alloc_count++] = mem_hole; >>> >>> Do we need to call mlock to hold allocated cache in the memory, if >>> administrator enables swap, memory fragment will be gone once anonymous >>> pages are swapped to device? >> >> Hmm, the test is going to use this very intensively, so is it possible? > > Not sure, but I doubt it is possible to happen in low-end device? due to it > has > very less memory and system may has already token the most of memory.
Anyway, code looks clean, I think we can take a look at this later. Reviewed-by: Chao Yu <c...@kernel.org> Thanks, > > Thanks, > >> >>> >>> Thanks, >>> >>>> + >>>> + /* Touch all allocated memory. */ >>>> + for (ptr = (uintptr_t)mem_hole; >>>> + ptr < (uintptr_t)mem_hole + ALLOC_SIZE; >>>> + ptr += PAGE_SIZE) { >>>> + volatile char *alloc_page = (volatile char *)ptr; >>>> + *alloc_page; >>>> + } >>>> + } >>>> + printf("Touched allocated memory: count = %u\n", alloc_count); >>>> + printf(" - allocated memory: = "); >>>> + for (idx = 0; idx < 5; idx++) >>>> + printf(" %p", mem_holes[idx]); >>>> + printf("\n"); >>>> + >>>> + fd = xopen(argv[5], O_RDONLY | flags, 0); >>>> + >>>> + if (advice) { >>>> + if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE, >>>> + POSIX_FADV_SEQUENTIAL) != 0) >>>> + die_errno("fadvise failed"); >>>> + if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE, >>>> + POSIX_FADV_WILLNEED) != 0) >>>> + die_errno("fadvise failed"); >>>> + printf("fadvise SEQUENTIAL|WILLNEED to a file: %s\n", argv[5]); >>>> + } >>>> + >>>> + total_time = get_current_us(); >>>> + >>>> + for (i = 0; i < count; i++) { >>>> + ret = pread(fd, buf, buf_size, offset + buf_size * i); >>>> + if (ret != buf_size) { >>>> + printf("pread expected: %"PRIu64", readed: %"PRIu64"\n", >>>> + buf_size, ret); >>>> + if (ret > 0) >>>> + read_cnt += ret; >>>> + break; >>>> + } >>>> + >>>> + read_cnt += ret; >>>> + } >>>> + printf("Fragmented_Read %"PRIu64" bytes total_time = %"PRIu64" us, BW = >>>> %.Lf MB/s\n", >>>> + read_cnt, get_current_us() - total_time, >>>> + ((long double)read_cnt / (get_current_us() - total_time))); >>>> + printf("\n"); >>>> + exit(0); >>>> +} >>>> + >>>> #define randread_desc "random read data from file" >>>> #define randread_help \ >>>> "f2fs_io randread [chunk_size in 4kb] [count] [IO] [advise] >>>> [file_path]\n\n" \ >>>> @@ -2002,6 +2111,7 @@ const struct cmd_desc cmd_list[] = { >>>> CMD(write_advice), >>>> CMD(read), >>>> CMD(randread), >>>> + CMD(fragread), >>>> CMD(fiemap), >>>> CMD(gc_urgent), >>>> CMD(defrag_file), > _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel