[PATCH 2/2] erofs-utils:tests: add new test options for stress tests
Jiawei Wang
kyr1ewang at qq.com
Sun Sep 1 16:35:49 AEST 2024
This patch add some new test options (direct_io, mmap and fadvise) for
stress test.
Signed-off-by: Jiawei Wang <kyr1ewang at qq.com>
---
tests/erofsstress/stress.c | 459 +++++++++++++++++++++++++++++++++----
1 file changed, 418 insertions(+), 41 deletions(-)
diff --git a/tests/erofsstress/stress.c b/tests/erofsstress/stress.c
index 4dfe489..84a665c 100644
--- a/tests/erofsstress/stress.c
+++ b/tests/erofsstress/stress.c
@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
@@ -27,6 +28,9 @@
#define MAX_SCAN_CHUNKSIZE (256 * 1024)
bool superuser;
+bool direct_io = false;
+bool mmap_flag = false;
+bool fadvise_flag = false;
unsigned int nprocs = 1, loops = 1, r_seed;
sig_atomic_t should_stop = 0;
@@ -114,6 +118,8 @@ int drop_file_cache(int fd, int mode)
struct fent {
char *subpath;
+ void *fd_ptr;
+ void *chkfd_ptr;
int fd, chkfd;
};
@@ -282,60 +288,276 @@ static int testdir_fd = -1, chkdir_fd = -1;
int tryopen(struct fent *fe)
{
+ int err;
+ uint64_t filesize;
+
if (fe->fd < 0) {
- fe->fd = openat(testdir_fd, fe->subpath, O_RDONLY);
+ fe->fd = openat(testdir_fd, fe->subpath, direct_io ? O_RDONLY | O_DIRECT : O_RDONLY);
if (fe->fd < 0)
return -errno;
/* use force_page_cache_readahead for every read request */
posix_fadvise(fe->fd, 0, 0, POSIX_FADV_RANDOM);
+
+ filesize = lseek64(fe->fd, 0, SEEK_END);
+ if (mmap_flag) {
+ fe->fd_ptr = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fe->fd, 0);
+ if (fe->fd_ptr == MAP_FAILED) {
+ fprintf(stderr, "%s failed mmap\n", __func__);
+ return -errno;
+ }
+ }
}
- if (chkdir_fd >= 0 && fe->chkfd < 0)
- fe->chkfd = openat(chkdir_fd, fe->subpath, O_RDONLY);
+ if (chkdir_fd >= 0 && fe->chkfd < 0) {
+ fe->chkfd = openat(chkdir_fd, fe->subpath, direct_io ? O_RDONLY | O_DIRECT : O_RDONLY);
+
+ if (fe->chkfd > 0) {
+ filesize = lseek64(fe->chkfd, 0, SEEK_END);
+ if (mmap_flag) {
+ fe->chkfd_ptr = mmap(NULL, filesize, PROT_READ, MAP_PRIVATE, fe->chkfd, 0);
+ if (fe->chkfd_ptr == MAP_FAILED) {
+ fprintf(stderr, "%s failed mmap\n", __func__);
+ return -errno;
+ }
+ }
+ } else
+ fe->chkfd_ptr = NULL;
+ }
return 0;
}
-int doscan(int fd, int chkfd, uint64_t filesize, uint64_t chunksize)
+void mismatch_output(struct fent *ent, uint64_t pos, uint64_t chunksize)
+{
+ int fd, ret;
+ ssize_t nread, nread2;
+ char filename[20];
+ char *buf, *chkbuf;
+
+ ret = posix_memalign(&buf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE);
+ if (ret) {
+ fprintf(stderr, "posix_memalign failed: %s\n", strerror(ret));
+ goto cleanup;
+ }
+ nread = pread64(ent->fd, buf, chunksize, pos);
+ if (nread <= 0) {
+ fprintf(stderr, "read file failed");
+ goto cleanup;
+ }
+
+ ret = posix_memalign(&chkbuf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE);
+ if (ret) {
+ fprintf(stderr, "posix_memalign failed: %s\n", strerror(ret));
+ goto cleanup;
+ }
+ nread2 = pread64(ent->chkfd, chkbuf, chunksize, pos);
+ if (nread2 <=0) {
+ fprintf(stderr, "read file failed");
+ goto cleanup;
+ }
+
+ sprintf(filename, "%d", getpid());
+ strcat(filename, "_mismatch");
+ fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ fprintf(stderr, "error opening file");
+ goto cleanup;
+ }
+
+ ret = write(fd, ent->subpath, strlen(ent->subpath));
+ if (ret == -1) {
+ fprintf(stderr, "error writing file");
+ goto cleanup;
+ }
+ write(fd, "\n", 1);
+
+ ret = write(fd, buf, nread);
+ if (ret == -1) {
+ fprintf(stderr, "error writing file");
+ goto cleanup;
+ }
+ write(fd, "\n", 1);
+ ret = write(fd, chkbuf, nread2);
+ if (ret == -1) {
+ fprintf(stderr, "error writing file");
+ goto cleanup;
+ }
+cleanup:
+ free(buf);
+ free(chkbuf);
+}
+
+int doscan(struct fent *ent, uint64_t filesize, uint64_t chunksize)
{
- static char buf[MAX_SCAN_CHUNKSIZE], chkbuf[MAX_SCAN_CHUNKSIZE];
+ char *buf, *chkbuf;
uint64_t pos;
+ int err = 0;
printf("doscan(%u): filesize: %llu, chunksize: %llu\n",
getpid(), (unsigned long long)filesize,
(unsigned long long)chunksize);
-
+
+ err = posix_memalign(&buf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE);
+ if (err) {
+ fprintf(stderr, "posix_memalign failed: %s\n", strerror(err));
+ goto cleanup;
+ }
+
+ err = posix_memalign(&chkbuf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE);
+ if (err) {
+ fprintf(stderr, "posix_memalign failed: %s\n", strerror(err));
+ goto cleanup;
+ }
+
for (pos = 0; pos < filesize; pos += chunksize) {
ssize_t nread, nread2;
+
+ nread = pread64(ent->fd, buf, chunksize, pos);
+ if (nread <= 0) {
+ err = -errno;
+ goto cleanup;
+ }
- nread = pread64(fd, buf, chunksize, pos);
-
- if (nread <= 0)
- return -errno;
-
- if (nread < chunksize && nread != filesize - pos)
- return -ERANGE;
+ if (nread < chunksize && nread != filesize - pos) {
+ err = -ERANGE;
+ goto cleanup;
+ }
- if (chkfd < 0)
+ if (ent->chkfd < 0)
continue;
- nread2 = pread64(chkfd, chkbuf, chunksize, pos);
- if (nread2 <= 0)
- return -errno;
+ nread2 = pread64(ent->chkfd, chkbuf, chunksize, pos);
+ if (nread2 <= 0) {
+ err = -errno;
+ goto cleanup;
+ }
- if (nread != nread2)
- return -EFBIG;
+ if (nread != nread2) {
+ err = -EFBIG;
+ goto cleanup;
+ }
if (memcmp(buf, chkbuf, nread)) {
fprintf(stderr, "doscan: %llu bytes mismatch @ %llu\n",
(unsigned long long)chunksize,
(unsigned long long)pos);
+ mismatch_output(ent, pos, chunksize);
+ err = -EBADMSG;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ free(buf);
+ free(chkbuf);
+ return err;
+}
+
+int doscan_mmap(struct fent *ent, uint64_t filesize, uint64_t chunksize)
+{
+ uint64_t pos, nread;
+
+ printf("doscan_mmap(%u): filesize: %llu, chunksize: %llu\n",
+ getpid(), (unsigned long long)filesize,
+ (unsigned long long)chunksize);
+
+ if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize)
+ return -EFBIG;
+
+ for (pos = 0; pos < filesize; pos += chunksize) {
+
+ if (pos + chunksize < filesize)
+ nread = chunksize;
+ else
+ nread = filesize - pos;
+
+ if (ent->chkfd < 0)
+ continue;
+
+ if (memcmp(ent->fd_ptr + pos, ent->chkfd_ptr + pos, nread)) {
+ fprintf(stderr, "doscan_mmap: %llu bytes mismatch @ %llu\n",
+ (unsigned long long)chunksize,
+ (unsigned long long)pos);
+ mismatch_output(ent, pos, chunksize);
return -EBADMSG;
}
}
return 0;
}
+int doscan_fadvise(struct fent *ent, uint64_t filesize, uint64_t chunksize)
+{
+ int err;
+ uint64_t pos, nread;
+
+ printf("doscan_fadvise(%u): filesize: %llu, chunksize: %llu\n",
+ getpid(), (unsigned long long)filesize,
+ (unsigned long long)chunksize);
+
+ if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize)
+ return -EFBIG;
+
+ for (pos = 0; pos < filesize; pos += chunksize) {
+
+ if (pos + chunksize < filesize)
+ nread = chunksize;
+ else
+ nread = filesize - pos;
+
+ err = posix_fadvise(ent->fd, pos, nread, POSIX_FADV_WILLNEED);
+ if (err) {
+ perror("posix_fadvise");
+ return -errno;;
+ }
+
+ if (ent->chkfd < 0)
+ continue;
+
+ err = posix_fadvise(ent->chkfd, pos, nread, POSIX_FADV_WILLNEED);
+ if (err) {
+ perror("posix_fadvise");
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+int doscan_random(struct fent *ent, uint64_t filesize, uint64_t chunksize)
+{
+ bool flag = false;
+ int err;
+ int randnum;
+
+ srand(time(NULL));
+ while(true) {
+ if (flag)
+ break;
+
+ randnum = rand() % 3 + 1;
+ switch(randnum) {
+ case 1:
+ flag = true;
+ err = doscan(ent, filesize, chunksize);
+ break;
+ case 2:
+ if (mmap_flag) {
+ flag = true;
+ err = doscan_mmap(ent, filesize, chunksize);
+ }
+ break;
+ case 3:
+ if (fadvise_flag) {
+ flag = true;
+ err = doscan_fadvise(ent, filesize, chunksize);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return err;
+}
+
int getdents_f(struct fent *fe)
{
int dfd;
@@ -379,17 +601,30 @@ int readlink_f(struct fent *fe)
return 0;
}
-int read_f(int fd, int chkfd, uint64_t filesize)
+int read_f(struct fent *ent, uint64_t filesize)
{
- static char buf[MAX_CHUNKSIZE], chkbuf[MAX_CHUNKSIZE];
+ char *buf, *chkbuf;
uint64_t lr, off, len, trimmed;
size_t nread, nread2;
+ int err = 0;
lr = ((uint64_t) random() << 32) + random();
off = lr % filesize;
len = (random() % MAX_CHUNKSIZE) + 1;
trimmed = len;
-
+
+ err = posix_memalign(&buf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE);
+ if (err) {
+ fprintf(stderr, "posix_memalign failed: %s\n", strerror(err));
+ goto cleanup;
+ }
+
+ err = posix_memalign(&chkbuf, PAGE_SIZE, MAX_SCAN_CHUNKSIZE);
+ if (err) {
+ fprintf(stderr, "posix_memalign failed: %s\n", strerror(err));
+ goto cleanup;
+ }
+
if (off + len > filesize) {
uint64_t a = filesize - off + 16 * getpagesize();
@@ -397,44 +632,175 @@ int read_f(int fd, int chkfd, uint64_t filesize)
len %= a;
trimmed = len <= filesize - off ? len : filesize - off;
}
-
+
+ if (direct_io) {
+ off = (((off - 1) >> PAGE_SHIFT) + 1)
+ << PAGE_SHIFT;
+ trimmed = len = (((len - 1) >> PAGE_SHIFT) + 1)
+ << PAGE_SHIFT;
+ if (!len || off + len > filesize)
+ goto cleanup;
+ }
+
printf("read_f(%u): %llu bytes @ %llu\n", getpid(),
- len | 0ULL, off | 0ULL);
+ len | 0ULL, off | 0ULL);
- nread = pread64(fd, buf, len, off);
+ nread = pread64(ent->fd, buf, len, off);
if (nread != trimmed) {
fprintf(stderr, "read_f(%d, %u): failed to read %llu bytes @ %llu\n",
__LINE__, getpid(), len | 0ULL, off | 0ULL);
- return -errno;
+ err = -errno;
+ goto cleanup;
}
- if (chkfd < 0)
- return 0;
+ if (ent->chkfd < 0)
+ goto cleanup;
- nread2 = pread64(chkfd, chkbuf, len, off);
+ nread2 = pread64(ent->chkfd, chkbuf, len, off);
if (nread2 <= 0) {
fprintf(stderr, "read_f(%d, %u): failed to read %llu bytes @ %llu\n",
__LINE__, getpid(), len | 0ULL, off | 0ULL);
- return -errno;
+ err = -errno;
+ goto cleanup;
}
if (nread != nread2) {
fprintf(stderr, "read_f(%d, %u): size mismatch %llu bytes @ %llu\n",
__LINE__, getpid(), len | 0ULL, off | 0ULL);
- return -EFBIG;
+ mismatch_output(ent, off, len);
+ err = -EFBIG;
+ goto cleanup;
}
if (memcmp(buf, chkbuf, nread)) {
fprintf(stderr, "read_f(%d, %u): data mismatch %llu bytes @ %llu\n",
__LINE__, getpid(), len | 0ULL, off | 0ULL);
+ mismatch_output(ent, off, len);
+ err = -EBADMSG;
+ goto cleanup;
+ }
+
+cleanup:
+ free(buf);
+ free(chkbuf);
+ return err;
+}
+
+int read_f_mmap(struct fent *ent, uint64_t filesize)
+{
+ uint64_t lr, off, len, trimmed;
+
+ lr = ((uint64_t) random() << 32) + random();
+ off = lr % filesize;
+ len = (random() % MAX_CHUNKSIZE) + 1;
+ trimmed = len;
+
+ if (off + len > filesize) {
+ uint64_t a = filesize - off + 16 * getpagesize();
+
+ if (len > a)
+ len %= a;
+ trimmed = len <= filesize - off ? len : filesize - off;
+ }
+
+ printf("read_f_mmap(%u): %llu bytes @ %llu\n", getpid(),
+ len | 0ULL, off | 0ULL);
+
+ if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize)
+ return -EFBIG;
+
+ if (ent->chkfd < 0)
+ return 0;
+
+ if (memcmp(ent->fd_ptr + off, ent->chkfd_ptr + off, trimmed)) {
+ fprintf(stderr, "read_f_mmap(%d, %u): data mismatch %llu bytes @ %llu\n",
+ __LINE__, getpid(), len | 0ULL, off | 0ULL);
+ mismatch_output(ent, off, len);
return -EBADMSG;
}
return 0;
}
-int testfd(int fd, int chkfd, int mode)
+int read_f_fadvise(struct fent *ent, uint64_t filesize)
{
- const off64_t filesize = lseek64(fd, 0, SEEK_END);
+ int err;
+ uint64_t lr, off, len, trimmed;
+
+ lr = ((uint64_t) random() << 32) + random();
+ off = lr % filesize;
+ len = (random() % MAX_CHUNKSIZE) + 1;
+ trimmed = len;
+
+ if (off + len > filesize) {
+ uint64_t a = filesize - off + 16 * getpagesize();
+
+ if (len > a)
+ len %= a;
+ trimmed = len <= filesize - off ? len : filesize - off;
+ }
+
+ printf("read_f_fadvise(%u): %llu bytes @ %llu\n", getpid(),
+ len | 0ULL, off | 0ULL);
+
+ err = posix_fadvise(ent->fd, off, trimmed, POSIX_FADV_WILLNEED);
+ if (err) {
+ perror("posix_fadvise");
+ return -errno;
+ }
+
+ if (ent->chkfd >= 0 && lseek(ent->chkfd, 0, SEEK_END) != filesize)
+ return -EFBIG;
+
+ if (ent->chkfd < 0)
+ return 0;
+
+ err = posix_fadvise(ent->chkfd, off, trimmed, POSIX_FADV_WILLNEED);
+ if (err) {
+ perror("posix_fadvise");
+ return -errno;
+ }
+ return 0;
+}
+
+int read_f_random(struct fent * ent, uint64_t filesize)
+{
+ bool flag = false;
+ int err;
+ int randnum;
+
+ srand(time(NULL));
+ while(true) {
+ if (flag)
+ break;
+
+ randnum = rand() % 3 + 1;
+ switch(randnum) {
+ case 1:
+ flag = true;
+ err = read_f(ent, filesize);
+ break;
+ case 2:
+ if (mmap_flag) {
+ flag = true;
+ err = read_f_mmap(ent, filesize);
+ }
+ break;
+ case 3:
+ if (fadvise_flag) {
+ flag = true;
+ err = read_f_fadvise(ent, filesize);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return err;
+}
+
+int testfd(struct fent *ent, int mode)
+{
+ const off64_t filesize = lseek64(ent->fd, 0, SEEK_END);
uint64_t chunksize, maxchunksize;
int err;
@@ -450,16 +816,16 @@ int testfd(int fd, int chkfd, int mode)
<< PAGE_SHIFT;
if (!chunksize)
chunksize = PAGE_SIZE;
- err = doscan(fd, chkfd, filesize, chunksize);
+ err = doscan_random(ent, filesize, chunksize);
if (err)
return err;
- } else if (mode == RANDSCAN_UNALIGNED) {
+ } else if (mode == RANDSCAN_UNALIGNED && !direct_io) {
chunksize = (random() * random() % MAX_SCAN_CHUNKSIZE) + 1;
- err = doscan(fd, chkfd, filesize, chunksize);
+ err = doscan_random(ent, filesize, chunksize);
if (err)
return err;
} else if (mode == RANDREAD) {
- err = read_f(fd, chkfd, filesize);
+ err = read_f_random(ent, filesize);
if (err)
return err;
}
@@ -470,7 +836,6 @@ int doproc(int mode)
{
struct fent *fe;
int ret;
-
if (mode <= GETDENTS) {
fe = getfent(FT_DIRm, random());
if (!fe)
@@ -492,7 +857,7 @@ int doproc(int mode)
ret = tryopen(fe);
if (ret)
return ret;
- return testfd(fe->fd, fe->chkfd, mode);
+ return testfd(fe, mode);
}
void randomdelay(void)
@@ -522,7 +887,7 @@ static int parse_options(int argc, char *argv[])
char *testdir, *chkdir;
int opt;
- while ((opt = getopt(argc, argv, "l:p:s:")) != -1) {
+ while ((opt = getopt(argc, argv, "l:p:s:dmf")) != -1) {
switch (opt) {
case 'l':
loops = atoi(optarg);
@@ -547,6 +912,15 @@ static int parse_options(int argc, char *argv[])
return -EINVAL;
}
break;
+ case 'd':
+ direct_io = true;
+ break;
+ case 'm':
+ mmap_flag = true;
+ break;
+ case 'f':
+ fadvise_flag = true;
+ break;
default: /* '?' */
return -EINVAL;
}
@@ -585,7 +959,10 @@ void usage(void)
" -l# specifies the no. of times the testrun should loop.\n"
" *use 0 for infinite (default 1)\n"
" -p# specifies the no. of processes (default 1)\n"
- " -s# specifies the seed for the random generator (default random)\n",
+ " -s# specifies the seed for the random generator (default random)\n"
+ " -d using direct_io to start stress test\n"
+ " -m using mmap to start stress test\n"
+ " -f using fadvise to start stress test\n",
stderr);
}
--
2.34.1
More information about the Linux-erofs
mailing list