C++程序  |  256行  |  4.79 KB

/*
 * 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);
}