/* * Create lots of VMA's mapped by lots of tasks. To tickle objrmap and the * virtual scan. */ #include #include #include #include #include #include #include #include #include #include #include char *progname; char *filename; void *mapped_mem; int niters; int ntasks = 100; int nvmas = 100; int vmasize = 1024*1024; int vmas_to_do = -1; int pagesize; int fd; char **vma_addresses; volatile int *nr_children_running; int verbose; enum access_pattern { ap_random, ap_linear, ap_half } access_pattern = ap_linear; void open_file() { fd = open(filename, O_RDWR|O_TRUNC|O_CREAT, 0666); if (fd < 0) { fprintf(stderr, "%s: Cannot open `%s': %s\n", progname, filename, strerror(errno)); exit(1); } } void usage(void) { fprintf(stderr, "Usage: %s [-hlrvV] [-iN] [-nN] [-sN] [-tN] filename\n", progname); fprintf(stderr, " -h: Pattern: half of memory is busy\n"); fprintf(stderr, " -l: Pattern: linear\n"); fprintf(stderr, " -r: Pattern: random\n"); fprintf(stderr, " -iN: Number of iterations\n"); fprintf(stderr, " -nN: Number of VMAs\n"); fprintf(stderr, " -sN: VMA size (pages)\n"); fprintf(stderr, " -tN: Run N tasks\n"); fprintf(stderr, " -VN: Number of VMAs to process\n"); fprintf(stderr, " -v: Verbose\n"); exit(1); } void touch_pages(int nr_vmas) { int i; for (i = 0; i < nr_vmas; i++) { char *p = vma_addresses[i]; int page; for (page = 0; page < vmasize; page++) p[page * pagesize]++; } } void msync_file(int nr_vmas) { int i; for (i = 0; i < nr_vmas; i++) { char *p = vma_addresses[i]; msync(p, vmasize * pagesize, MS_ASYNC); } } void touch_random_pages(void) { int vma; int page; srand(getpid() * time(0)); for (vma = 0; vma < vmas_to_do; vma++) { for (page = 0; page < vmasize; page++) { int rand_vma; int rand_page; char *p; rand_vma = rand() % nvmas; rand_page = rand() % vmasize; p = vma_addresses[rand_vma] + rand_page * pagesize; (*p)++; } if (verbose > 1) printf("vma %d/%d done\n", vma, nvmas); } } void child(int childno) { int iter; sleep(1); if (access_pattern == ap_half && childno == 0) { while (*nr_children_running > 1) { touch_pages(nvmas / 2); } return; } for (iter = 0; iter < niters; iter++) { if (access_pattern == ap_random) { touch_random_pages(); } else if (access_pattern == ap_linear) { touch_pages(nvmas); } else if (access_pattern == ap_half) { touch_pages(nvmas); } if (verbose > 0) printf("%d/%d\n", iter, niters); } } int main(int argc, char *argv[]) { int c; int i; loff_t offset; loff_t file_size; int childno; progname = argv[0]; while ((c = getopt(argc, argv, "vrlhi:n:s:t:V:")) != -1) { switch (c) { case 'h': access_pattern = ap_half; break; case 'l': access_pattern = ap_linear; break; case 'r': access_pattern = ap_random; break; case 'i': niters = strtol(optarg, NULL, 10); break; case 'n': nvmas = strtol(optarg, NULL, 10); break; case 's': vmasize = strtol(optarg, NULL, 10); break; case 't': ntasks = strtol(optarg, NULL, 10); break; case 'V': vmas_to_do = strtol(optarg, NULL, 10); break; case 'v': verbose++; break; } } if (optind == argc) usage(); filename = argv[optind++]; if (optind != argc) usage(); if (vmas_to_do == -1) vmas_to_do = nvmas; pagesize = getpagesize(); open_file(); file_size = nvmas; file_size *= vmasize; file_size += nvmas - 1; file_size *= pagesize; printf("Total file size: %lldk, Total memory: %lldk\n", file_size / 1024, ((long long)nvmas * vmasize * pagesize) / 1024); if (ftruncate(fd, file_size) < 0) { perror("ftruncate"); exit(1); } vma_addresses = malloc(nvmas * sizeof(*vma_addresses)); nr_children_running = (int *)mmap(0, sizeof(*nr_children_running), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); if (nr_children_running == MAP_FAILED) { perror("mmap1"); exit(1); } offset = 0; for (i = 0; i < nvmas; i++) { char *p; p = mmap(0, vmasize * pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); if (p == MAP_FAILED) { perror("mmap"); exit(1); } vma_addresses[i] = p; offset += vmasize * pagesize + pagesize; } touch_pages(nvmas); msync_file(nvmas); *nr_children_running = ntasks; for (childno = 0; childno < ntasks; childno++) { if (fork() == 0) { child(childno); exit(0); } } signal(SIGINT, SIG_IGN); for (i = 0; i < ntasks; i++) { pid_t pid; int status; /* Catch each child error status and report. */ pid = wait3(&status, 0, 0); if (pid < 0) /* No more children? */ break; (*nr_children_running)--; } exit(0); }