`
standalone
  • 浏览: 595943 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Test performance of allocating a zeroed file via various methods

    博客分类:
  • c++
阅读更多

/*
 * Test performance of allocating a zeroed file via various methods on
 * various file systems
 *
 *   Copyright (C) 2009 Red Hat Inc.
 *   Author(s): Amit Shah
 *
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU General Public License
 *    version 2 as published by the Free Software Foundation
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/mman.h>

#define GB(x) ((unsigned long long)x << 30)

int pre_test_setup(char *source, char *target, char *fstype,
		   unsigned long mntflags, char *mntopts, char *name, int *fd)
{
	int r;

	if (source) {
		r = mount(source, target, fstype, mntflags, mntopts);
		if (r < 0) {
			perror("mount");
			return -1;
		}
	}
	unlink(name);
	*fd = open(name, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
	if (*fd < 0) {
		perror("open");
		return -1;
	}

	/* Flush out all other data that might be pending writing to
	 * the disk. We don't want to count the time we wait for the
	 * buffers of other apps to clear. (Ideally, this test would
	 * be run in single user mode with nothing else running on the
	 * system.)
	 */
	sync();
	sync();
	/* Just to be sure - http://lwn.net/Articles/325420/ */
	sync();

	return 0;
}

int post_test_cleanup(char *target, int *fd)
{
	int r;

	r = close(*fd);
	if (r < 0)
		perror("close");

	if (strcmp(target, ".")) {
		r = umount(target);
		if (r < 0)
			perror("unmount");
	}
	return r;
}

void run_test(int (test)(char *, int *, off_t, size_t),
	      char *source, char *target, char *fstype, unsigned long mntflags,
	      char *mntopts, char *filename, off_t len, size_t data)
{
	int r, fd;

	r = pre_test_setup(source, target, fstype, mntflags, mntopts,
			   filename, &fd);
	if (r < 0)
		goto error_exit;

	(test)(target, &fd, len, data);
	return;

error_exit:
	post_test_cleanup(target, &fd);
	return;
}

int do_posix_fallocate(char *target, int *fd, off_t len, size_t data)
{
	int r;
	struct timeval tv1, tv2;

	printf("posix-fallocate run time:\n");
	gettimeofday(&tv1, NULL);
	r = posix_fallocate(*fd, 0, len);
	post_test_cleanup(target, fd);
	gettimeofday(&tv2, NULL);
	if (r < 0) {
		printf("posix_fallocate, error %d\n", r);
		return r;
	}
	printf("\tseconds:microseconds: %llu:%llu\n", tv1.tv_sec, tv1.tv_usec);
	printf("\tseconds:microseconds: %llu:%llu\n", tv2.tv_sec, tv2.tv_usec);
	printf("\t(approx %us)\n", tv2.tv_sec - tv1.tv_sec);

	return 0;
}

int do_fallocate(char *target, int *fd, off_t len, size_t data)
{
	int r;
	struct timeval tv1, tv2;

	printf("fallocate run time:\n");
	gettimeofday(&tv1, NULL);
	r = syscall(__NR_fallocate, *fd, 0, len);
	post_test_cleanup(target, fd);
	gettimeofday(&tv2, NULL);
	if (r < 0) {
		perror("fallocate");
		return r;
	}
	printf("\tseconds:microseconds: %llu:%llu\n", tv1.tv_sec, tv1.tv_usec);
	printf("\tseconds:microseconds: %llu:%llu\n", tv2.tv_sec, tv2.tv_usec);
	printf("\t(approx %us)\n", tv2.tv_sec - tv1.tv_sec);

	return 0;
}

int do_mmap(char *target, int *fd, off_t len, size_t data)
{
	struct timeval tv1, tv2;
	char *addr;

	/* memset has to have the mmap'ed file backed by something on
	 * disk -- bus error otherwise
	 */
	ftruncate(*fd, len);

	addr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, *fd, 0);
	if (addr == MAP_FAILED) {
		perror("mmap");
		return -2;
	}

	printf("mmap run time:\n");
	gettimeofday(&tv1, NULL);
	memset(addr, 0, len);
	munmap(addr, len);
	post_test_cleanup(target, fd);
	gettimeofday(&tv2, NULL);

	printf("\tseconds:microseconds: %llu:%llu\n", tv1.tv_sec, tv1.tv_usec);
	printf("\tseconds:microseconds: %llu:%llu\n", tv2.tv_sec, tv2.tv_usec);
	printf("\t(approx %us)\n", tv2.tv_sec - tv1.tv_sec);

	return 0;
}

int do_write_chunks(char *target, int *fd, off_t len, size_t data)
{
	struct timeval tv1, tv2;

	unsigned long long remain = len;
	char *zeros;

	zeros = calloc(1, data);

	printf("%llu-sized chunk run time:\n", data);
	gettimeofday(&tv1, NULL);
	while (remain) {
		int bytes = data;
		if (bytes > remain)
			bytes = remain;
		if ((bytes = write(*fd, zeros, bytes)) < 0) {
			perror("write");
			return -2;
		}
		remain -= bytes;
	}
	post_test_cleanup(target, fd);
	gettimeofday(&tv2, NULL);

	printf("\tseconds:microseconds: %llu:%llu\n", tv1.tv_sec, tv1.tv_usec);
	printf("\tseconds:microseconds: %llu:%llu\n", tv2.tv_sec, tv2.tv_usec);
	printf("\t(approx %us)\n", tv2.tv_sec - tv1.tv_sec);
	free(zeros);

	return 0;
}

int main(int argc, char **argv)
{
	char *source, *target, *fstype, *mntopts;
	char filename[200];
	unsigned long mntflags;
	unsigned long long filesize;

	/* FIXME! use getopt */
	if (argc < 2 || argc > 2 && argc < 5) {
		printf("usage: %s <filesize-in-gb> <device> <mountpoint> <fstype> [mntflags] [mntopts]\n",
		       argv[0]);
		return -1;
	}

	filesize = GB(atol(argv[1]));
	if (argc > 2) {
		source = argv[2];
		target = argv[3];
		fstype = argv[4];
	} else {
		source = NULL;
		target = ".";
		fstype = "native";
	}
	if (argc > 5)
		mntflags = atol(argv[5]);
	else
		mntflags = 0;
	if (argc > 6)
		mntopts = argv[6];
	else
		mntopts = NULL;

	sprintf(filename, "%s/%s-pf", target, fstype);
	run_test(do_posix_fallocate, source, target, fstype, mntflags, mntopts,
		 filename, filesize, 0);

#if 0
	sprintf(filename, "%s/%s-fallocate", target, fstype);
	run_test(do_fallocate, source, target, fstype, mntflags, mntopts,
		 filename, filesize, 0);
#endif

	sprintf(filename, "%s/%s-mmap", target, fstype);
	run_test(do_mmap, source, target, fstype, mntflags, mntopts,
		 filename, filesize, 0);

	sprintf(filename, "%s/%s-chunk4k", target, fstype);
	run_test(do_write_chunks, source, target, fstype, mntflags, mntopts,
		 filename, filesize, 4 * 1024);

	sprintf(filename, "%s/%s-chunk8k", target, fstype);
	run_test(do_write_chunks, source, target, fstype, mntflags, mntopts,
		 filename, filesize, 8 * 1024);

	return 0;
}
 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics