From 838b38dadd00252c04fa5d548223b3a38062fe96 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 6 Nov 2007 13:08:12 +0200 Subject: fs-tests: add simple performance test Signed-off-by: Adrian Hunter --- tests/fs-tests/lib/tests.c | 42 +++++++++ tests/fs-tests/lib/tests.h | 6 ++ tests/fs-tests/simple/Makefile | 4 +- tests/fs-tests/simple/perf.c | 195 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 tests/fs-tests/simple/perf.c (limited to 'tests') diff --git a/tests/fs-tests/lib/tests.c b/tests/fs-tests/lib/tests.c index 9b8f443..aaf3907 100644 --- a/tests/fs-tests/lib/tests.c +++ b/tests/fs-tests/lib/tests.c @@ -1002,6 +1002,48 @@ void tests_remount(void) CHECK(chdir(cwd) != -1); } +/* Un-mount or re-mount test file system */ +static void tests_mnt(int mnt) +{ + static struct mntent mount_info; + char *source; + char *target; + char *filesystemtype; + unsigned long mountflags; + void *data; + static char cwd[4096]; + + if (mnt == 0) { + CHECK(tests_get_mount_info(&mount_info)); + if (strcmp(mount_info.mnt_dir,"/") == 0) + return; + CHECK(getcwd(cwd, 4096) != NULL); + CHECK(chdir("/") != -1); + CHECK(umount(tests_file_system_mount_dir) != -1); + } else { + source = mount_info.mnt_fsname; + target = tests_file_system_mount_dir; + filesystemtype = tests_file_system_type; + mountflags = 0; + data = NULL; + CHECK(mount(source, target, filesystemtype, mountflags, data) + != -1); + CHECK(chdir(cwd) != -1); + } +} + +/* Unmount test file system */ +void tests_unmount(void) +{ + tests_mnt(0); +} + +/* Mount test file system */ +void tests_mount(void) +{ + tests_mnt(1); +} + /* Check whether the test file system is also the root file system */ int tests_fs_is_rootfs(void) { diff --git a/tests/fs-tests/lib/tests.h b/tests/fs-tests/lib/tests.h index db08628..04c834d 100644 --- a/tests/fs-tests/lib/tests.h +++ b/tests/fs-tests/lib/tests.h @@ -146,6 +146,12 @@ int64_t tests_remove_entry(void); /* Un-mount and re-mount test file system */ void tests_remount(void); +/* Un-mount test file system */ +void tests_unmount(void); + +/* Mount test file system */ +void tests_mount(void); + /* Check whether the test file system is also the root file system */ int tests_fs_is_rootfs(void); diff --git a/tests/fs-tests/simple/Makefile b/tests/fs-tests/simple/Makefile index 8190993..d447da3 100644 --- a/tests/fs-tests/simple/Makefile +++ b/tests/fs-tests/simple/Makefile @@ -10,7 +10,8 @@ LDFLAGS := $(LDFLAGS) TARGETS = test_1 \ test_2 \ ftrunc \ - orph + orph \ + perf all: $(TARGETS) @@ -26,3 +27,4 @@ tests: all ./test_2 --sync ./ftrunc ./orph --sync + ./perf diff --git a/tests/fs-tests/simple/perf.c b/tests/fs-tests/simple/perf.c new file mode 100644 index 0000000..43d708d --- /dev/null +++ b/tests/fs-tests/simple/perf.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2007 Nokia Corporation. + * + * 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 + * + * Author: Adrian Hunter + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tests.h" + +#define BLOCK_SIZE 32 * 1024 + +struct timeval tv_start; +struct timeval tv_stop; + +static inline void start_timer(void) +{ + CHECK(gettimeofday(&tv_start, NULL) != -1); +} + +static inline long long stop_timer(void) +{ + long long usecs; + + CHECK(gettimeofday(&tv_stop, NULL) != -1); + usecs = (tv_stop.tv_sec - tv_start.tv_sec); + usecs *= 1000000; + usecs += tv_stop.tv_usec; + usecs -= tv_start.tv_usec; + return usecs; +} + +static unsigned speed(size_t bytes, long long usecs) +{ + unsigned long long k; + + k = bytes * 1000000ULL; + k /= usecs; + k /= 1024; + CHECK(k <= UINT_MAX); + return (unsigned) k; +} + +void perf(void) +{ + pid_t pid; + int fd, i; + ssize_t written, readsz; + size_t remains, block, actual_size; + char file_name[256]; + unsigned char *buf; + long long write_time, unmount_time, mount_time, read_time; + + /* Sync all file systems */ + sync(); + /* Make random data to write */ + buf = malloc(BLOCK_SIZE); + CHECK(buf != NULL); + pid = getpid(); + srand(pid); + for (i = 0; i < BLOCK_SIZE; i++) + buf[i] = rand(); + /* Open file */ + tests_cat_pid(file_name, "perf_test_file_", pid); + start_timer(); + fd = open(file_name, O_CREAT | O_RDWR | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); + CHECK(fd != -1); + CHECK(tests_size_parameter > 0); + CHECK(tests_size_parameter <= SIZE_MAX); + /* Write to file */ + actual_size = 0; + remains = tests_size_parameter; + while (remains > 0) { + if (remains > BLOCK_SIZE) + block = BLOCK_SIZE; + else + block = remains; + written = write(fd, buf, block); + if (written <= 0) { + CHECK(errno == ENOSPC); /* File system full */ + errno = 0; + break; + } + remains -= written; + actual_size += written; + } + CHECK(fsync(fd) != -1); + CHECK(close(fd) != -1); + write_time = stop_timer(); + /* Unmount */ + start_timer(); + tests_unmount(); + unmount_time = stop_timer(); + /* Mount */ + start_timer(); + tests_mount(); + mount_time = stop_timer(); + /* Open file, read it, and close it */ + start_timer(); + fd = open(file_name, O_RDONLY); + CHECK(fd != -1); + remains = actual_size; + while (remains > 0) { + if (remains > BLOCK_SIZE) + block = BLOCK_SIZE; + else + block = remains; + readsz = read(fd, buf, block); + CHECK(readsz == block); + remains -= readsz; + } + CHECK(close(fd) != -1); + read_time = stop_timer(); + CHECK(unlink(file_name) != -1); + /* Display timings */ + printf("File system read and write speed\n"); + printf("================================\n"); + printf("Specfied file size: %lld\n", tests_size_parameter); + printf("Actual file size: %zu\n", actual_size); + printf("Write time (us): %lld\n", write_time); + printf("Unmount time (us): %lld\n", unmount_time); + printf("Mount time (us): %lld\n", mount_time); + printf("Read time (us): %lld\n", read_time); + printf("Write speed (KiB/s): %u\n", speed(actual_size, write_time)); + printf("Read speed (KiB/s): %u\n", speed(actual_size, read_time)); + printf("Test completed\n"); +} + +/* Title of this test */ + +const char *perf_get_title(void) +{ + return "Measure file system read and write speed"; +} + +/* Description of this test */ + +const char *perf_get_description(void) +{ + return + "Syncs the file system (a newly created empty file system is " \ + "preferable). Creates a file named perf_test_file_pid, where " \ + "pid is the process id. The file is filled with random data. " \ + "The size of the file is given by the -z or --size option, " \ + "otherwise it defaults to 10MiB. Unmounts the file system. " \ + "Mounts the file system. Reads the entire file in 32KiB size " \ + "blocks. Displays the time taken for each activity. Deletes " \ + "the file. Note that the file is synced after writing and " \ + "that time is included in the write time and speed."; +} + +int main(int argc, char *argv[]) +{ + int run_test; + + /* Set default test file size */ + tests_size_parameter = 10 * 1024 * 1024; + + /* Handle common arguments */ + run_test = tests_get_args(argc, argv, perf_get_title(), + perf_get_description(), "z"); + if (!run_test) + return 1; + /* Change directory to the file system and check it is ok for testing */ + tests_check_test_file_system(); + /* Do the actual test */ + perf(); + return 0; +} -- cgit v1.2.3