* R+W, make random modifications, and msync() in a loop.
*
* The purpose is to stress the VM system.
+ *
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <err.h>
-
-#define NFILES 500
+#include <errno.h>
static void randomfill(int fd);
+static int mmap01(void *);
+static int mmap02(void *);
+static int build_files(void);
-int
-main(int argc, char *argv[])
+int opt_verbose;
+int opt_testno;
+int opt_nofiles;
+int opt_mbfile;
+int opt_count;
+int fliparg;
+
+int *fd;
+struct stat *st;
+char **pp;
+
+static const struct test {
+ char testdesc[128];
+ int (*testfn)(void *);
+} testlist[] = {
+ { "mmap01 - Massive mmap / msync (flushing all pages)", mmap01 },
+ { "mmap02 - Massive mmap / msync (flushing only specified pages)", mmap02 },
+ { "", NULL }
+};
+
+static int
+mmap01(void *arg)
{
+ int i;
+ int *bug = arg;
+ long jump;
+ size_t size, len;
- int i;
- size_t size;
- long jump;
- int fd[NFILES];
- struct stat st[NFILES];
- char name[128];
- char *p[NFILES];
+ if ((build_files()) != 0)
+ err(1, "Failed to create the files");
- for (i = 0; i < NFILES; i++) {
- snprintf(name, 128, "tmpfiles/file%d", i);
- if ((fd[i] = open(name, O_RDWR)) < 1) {
- if ((fd[i] = open(name, O_RDWR | O_CREAT, 0644)) < 1)
- err(1, "open");
- randomfill(fd[i]);
- }
- if ((fstat(fd[i], &st[i])) == -1)
- err(1, "fstat");
- fprintf(stdout, "\rFile creation, random data filled [%d/%d] ", i+1, NFILES);
- fflush(stdout);
- }
+ if (opt_verbose)
+ printf("\n");
- printf("\n");
+ for (i = 0; i < opt_nofiles; i++) {
- for (i = 0; i < NFILES; i++) {
- fflush(stdout);
- fprintf(stdout, "\rDoing mmap() + msync() [%d/%d] ", i+1, NFILES);
+ if (opt_verbose) {
+ fflush(stdout);
+ fprintf(stdout, "\rDoing mmap() + msync() [%d/%d] ", i+1, opt_nofiles);
+ }
size = st[i].st_size;
- p[i] = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
- if (p[i] == MAP_FAILED)
+ pp[i] = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
+ if (pp[i] == MAP_FAILED)
err(1, "mmap");
for (jump = 0; jump < size; jump += 65535) {
- p[i][jump] = jump + i;
+ pp[i][jump] = jump + i;
}
- /*
- * This is a funny bug. MS_SYNC and 0 are reversed (i.e.
- * the msync() call wasn't written correctly), but the
- * broken msync() leads to a heavier VM load as a veritible
- * ton of dirty file-backed pages wind up accumulating in
- * the memory maps.
- *
- * So we leave it as is for now.
- */
- if ((msync(*p, MS_SYNC, 0)) == -1) {
- printf("%s: %d %p\n", name, i, *p);
+ if (fliparg)
+ len = MS_SYNC;
+ else
+ len = 0;
+
+ if ((msync(pp[i], len, MS_SYNC)) == -1) {
+ printf("fd %d %p\n", fd[i], pp[i]);
err(1, "msync");
}
}
+ printf("\n");
+
+ return 0;
+}
+
+static int
+mmap02(void *arg)
+{
+ fliparg = 1;
+ mmap01(&fliparg);
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ int i;
+ const struct test *tp;
+
+ printf("tuxload: [-v] [-c count] [-m megs_per_file] [-n no_of_files] [-t test_to_run] \n"
+ "Available tests: \n");
+
+ for (tp = testlist; tp->testfn != NULL; tp++)
+ printf("\t%s\n", tp->testdesc);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int forever;
+ char c;
+
+ opt_verbose = opt_testno = 0;
+ opt_nofiles = 500;
+ opt_mbfile = 8;
+ opt_count = 1;
+ fliparg = 0;
+ forever = 0;
+
+ while ((c = getopt(argc, argv, "n:t:m:c:v")) != -1) {
+ switch(c) {
+ case 'v':
+ opt_verbose++;
+ break;
+ case 'n':
+ opt_nofiles = (int)strtol(optarg, NULL, 0);
+ break;
+ case 't':
+ opt_testno = (int)strtol(optarg, NULL, 0);
+ opt_testno--;
+ break;
+ case 'm':
+ opt_mbfile = (int)strtol(optarg, NULL, 0);
+ break;
+ case 'c':
+ opt_count = (int)strtol(optarg, NULL, 0);
+ if (opt_count == 0)
+ forever++;
+ break;
+ default:
+ usage();
+ ;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ st = malloc(opt_nofiles * sizeof(*st));
+ fd = malloc(opt_nofiles * sizeof(*fd));
+ pp = malloc(opt_nofiles * sizeof(*pp));
+
+ while (opt_count-- || forever)
+ testlist[opt_testno].testfn(0);
+
return 0;
}
+static int
+build_files(void)
+{
+ char name[128];
+ int i;
+ int error;
+
+ for (i = 0, error = 0; i < opt_nofiles; i++) {
+ snprintf(name, 128, "tmpfiles/file%d", i);
+ if ((fd[i] = open(name, O_RDWR)) < 1) {
+ if ((fd[i] = open(name, O_RDWR | O_CREAT, 0644)) < 1) {
+ error = errno;
+ break;
+ }
+ randomfill(fd[i]);
+ }
+ if ((fstat(fd[i], &st[i])) == -1) {
+ error = errno;
+ break;
+ }
+ if (opt_verbose) {
+ fprintf(stdout, "\rFile creation, random data filled [%d/%d] ", i+1, opt_nofiles);
+ fflush(stdout);
+ }
+ }
+
+ return error;
+}
+
static void
randomfill(int fd)
{
char buf[32768];
+ long tot;
int i;
srandomdev();
+ tot = opt_mbfile * 1024L;
for (i = 0; i < 32768; ++i)
buf[i] = random();
- for (i = 0; i < 8192; i += 32) /* 8MB */
+ for (i = 0; i < tot; i += 32) /* 8MB by default */
write(fd, buf, 32768);
fsync(fd);
lseek(fd, 0L, 0);