blob: 77594d2342b843a871b7ddc9eb8ab9f92611c520 [file] [log] [blame]
/*
* Create lots of VMA's mapped by lots of tasks. To tickle objrmap and the
* virtual scan.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
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);
}