diff options
author | Daniel Lezcano <daniel.lezcano@linaro.org> | 2014-10-03 13:01:27 +0200 |
---|---|---|
committer | Daniel Lezcano <daniel.lezcano@linaro.org> | 2014-10-03 13:01:27 +0200 |
commit | aac5f6d9b9541f09b4d94a89400b529266d4f61c (patch) | |
tree | effdbe34363b5da69914f691f522ad5923fe1c5b | |
parent | e5832769a00fddb21cd0261fa1c639b71a9ad949 (diff) |
Fix mutual exclusive option when opening a file
Make optional to the command line the bucket size, file size, etc ...
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r-- | iolatsimu.c | 299 |
1 files changed, 203 insertions, 96 deletions
diff --git a/iolatsimu.c b/iolatsimu.c index 119e844..84e84ca 100644 --- a/iolatsimu.c +++ b/iolatsimu.c @@ -1,7 +1,11 @@ #define _GNU_SOURCE +#include <errno.h> +#include <getopt.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <math.h> +#include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> #include <sys/wait.h> @@ -45,16 +49,6 @@ * residency. * */ -#define BUCKET_INTERVAL 500 -static int bucket_interval = BUCKET_INTERVAL; - -/* - * Number of successive hits for the same bucket. That is the thresold - * triggering the move of the element at the beginning of the list, so - * becoming more weighted for the statistics when guessing for the next - * latency. - */ -#define BUCKET_SUCCESSIVE 5 /* * For debugging purpose @@ -74,12 +68,22 @@ static int nrlatency = 0; struct bucket { int hits; int successive_hits; + int avg_successive_hits; int index; struct list_head list; }; static LIST_HEAD(bucket_list); +static struct bucket *last_bucket; + +struct options { + int pagesize; + const char *path; + int nrprocesses; + int bucketsize; +}; + /* * Find a bucket associated with the specified index */ @@ -110,6 +114,7 @@ static struct bucket *bucket_alloc(int index) if (bucket) { bucket->hits = 0; bucket->successive_hits = 0; + bucket->avg_successive_hits = 0; bucket->index = index; INIT_LIST_HEAD(&bucket->list); } @@ -168,20 +173,22 @@ static int bucket_guessed_index(void) /* * Return the bucket index for the specified latency */ -static int bucket_index(int latency) +static int bucket_index(int latency, int bucket_interval) { return latency / bucket_interval; } +#define AVG(A, B, I) ((A) + ((B - A) / (I))) + /* * The dynamic of the list is the following. * - Each new element is inserted at the end of the list * - Each element passing <BUCKET_SUCCESSIVE> times in this function * is elected to be moved at the beginning at the list */ -static int bucket_fill(int latency) +static int bucket_fill(int latency, struct options *options) { - int index = bucket_index(latency); + int index = bucket_index(latency, options->bucketsize); struct bucket *bucket; /* @@ -203,6 +210,21 @@ static int bucket_fill(int latency) list_add_tail(&bucket->list, &bucket_list); } + if (bucket != last_bucket) { + + if (last_bucket) { + + last_bucket->avg_successive_hits = + AVG(last_bucket->avg_successive_hits, + last_bucket->successive_hits, + last_bucket->hits + 1); + + last_bucket->successive_hits = 0; + } + + last_bucket = bucket; + } + /* * Increase the number of times this bucket has been hit */ @@ -213,10 +235,8 @@ static int bucket_fill(int latency) * We had a successive number of the same bucket, move it at * the beginning of the list */ - if (bucket->successive_hits == BUCKET_SUCCESSIVE) { + if (bucket->successive_hits >= bucket->avg_successive_hits) list_move(&bucket->list, &bucket_list); - bucket->successive_hits = 1; - } return 0; } @@ -251,71 +271,205 @@ static void bucket_show(void) */ #define NROFFSET 256 -#define PAGESIZE 16384 -// #define PAGESIZE 1048576 16384 -static char buffer[PAGESIZE]; +static char *buffer; /* - * Write the big file with size NROFFSET * PAGESIZE + * Write the big file with size NROFFSET * pagesize */ -void write_file(int fd) +void write_file(int fd, size_t size) { int i = 0; for (i = 0; i < NROFFSET; i++) - write(fd, buffer, sizeof(buffer)); + if (write(fd, buffer, size) < 0) + perror("write"); fsync(fd); } -int mktempfile(const char *dirname) +int mktempfile(const char *path, size_t size) { char *name; + struct stat s; int fd; - if (asprintf(&name, "%s/iosimul-XXXXXX", dirname) < 0) { - perror("asprintf"); - return -1; + fd = stat(path, &s); + if (fd < 0) { + if (errno == ENOENT) { + + fd = open(path, O_CREAT | O_SYNC | O_RDWR, 0600); + + if (fd >= 0) { + unlink(path); + write_file(fd, size); + } + } + goto out; } - fd = mkstemp(name); - if (fd >= 0) - unlink(name); + if (S_ISDIR(s.st_mode)) { + + if (asprintf(&name, "%s/iosimul-XXXXXX", path) < 0) { + perror("asprintf"); + return -1; + } + fd = mkostemp(name, O_SYNC | O_RDWR); + if (fd >= 0) { + unlink(name); + write_file(fd, size); + } + goto out; + } + + if (S_ISREG(s.st_mode)) { + fd = open(path, O_RDWR | O_SYNC); + if (fd >= 0) + write_file(fd, size); + } +out: return fd; } -int main(int argc, char *argv[]) +int access_file(int fd, struct options *options) { struct timeval begin, end; off_t offset; - int i; + int i, ret; unsigned long int latency; - const char *dirname = "/tmp"; - int fd, pid; - int nrchild = 1; - - /* - * Optionnally we can specify the directory to test the - * latencies, ... - */ - if (argc > 1) - dirname = argv[1]; /* - * ... the bucket interval, ... + * Initialize the random seed with the number of + * current usec. This random value will be used to + * access the file randomly, no sequential accesses + * which can be optimized by the hardware */ - if (argc > 2) - bucket_interval = atoi(argv[2]); + gettimeofday(&begin, NULL); + srandom(begin.tv_usec); + + for (i = 0; i < 10000; i++) { + + /* + * Compute the offset address to read from + */ + offset = (random() % NROFFSET) * options->pagesize; + + /* + * man posix_fadvise + */ + posix_fadvise(fd, offset, options->pagesize, + POSIX_FADV_DONTNEED); + + /* + * Measure the time to read a options->pagesize buffer + */ + gettimeofday(&begin, NULL); + if (random() % 2) + ret = pread(fd, buffer, options->pagesize, offset); + else + ret = pwrite(fd, buffer, options->pagesize, offset); + + gettimeofday(&end, NULL); + + if (ret <= 0) + perror("pread/pwrite"); + + latency = ((end.tv_sec - begin.tv_sec) * 1000000) + ( + end.tv_usec - begin.tv_usec); + + /* + * Fill a bucket with this latency + */ + bucket_fill(latency, options); + } + + return 0; +} + +static int getoptions(int argc, char *argv[], struct options *options) +{ + struct option long_options[] = { + { "pagesize", required_argument, NULL, 'p' }, + { "path", required_argument, NULL, 'f' }, + { "nrprocesses", required_argument, NULL, 't' }, + { "bucketsize", required_argument, NULL, 'b' }, + { 0, 0, 0, 0 } + }; + int c; + + memset(options, 0, sizeof(*options)); + + while (1) { + + int optindex = 0; + + c = getopt_long(argc, argv, "p:f:t:b:", + long_options, &optindex); + if (c == -1) + break; + + switch (c) { + case 'p': + options->pagesize = atoi(optarg); + break; + case 'f': + options->path = optarg; + break; + case 't': + options->nrprocesses = atoi(optarg); + break; + case 'b': + options->bucketsize = atoi(optarg); + break; + default: + fprintf(stderr, "%s: Unknown option `-%c'.\n", + basename(argv[0]), optopt); + return -1; + } + } + + if (!options->path) + options->path = "/tmp"; + + if (!options->pagesize) + options->pagesize = 4096; + + if (!options->bucketsize) + options->bucketsize = 200; + + if (!options->nrprocesses) + options->nrprocesses = 1; + + return optind; +} + +int main(int argc, char *argv[]) +{ + struct options options; + int fd, pid; + int i; + + if (getoptions(argc, argv, &options) <= 0) + return -1; + + buffer = malloc(sizeof(*buffer) * options.pagesize); + if (!buffer) { + fprintf(stderr, "failed to allocate buffer\n"); + return -1; + } /* - * ... the number of processes + * Make temporary file, we don't want to pollute the file system + * with big files if this program crashes */ - if (argc > 3) - nrchild = atoi(argv[3]); + fd = mktempfile(options.path, options.pagesize); + if (fd < 0) { + perror("mktempfile"); + return -1; + } - for (i = 0; i < nrchild; i++) { + for (i = 0; i < options.nrprocesses; i++) { pid = fork(); @@ -327,54 +481,7 @@ int main(int argc, char *argv[]) if (pid) continue; - /* - * Make temporary file, we don't want to pollute the file system - * with big files if this program crashes - */ - fd = mktempfile(dirname); - if (fd < 0) { - perror("mktempfile"); - return -1; - } - - write_file(fd); - - /* - * Initialize the random seed with the number of - * current usec. This random value will be used to - * access the file randomly, no sequential accesses - * which can be optimized by the hardware - */ - gettimeofday(&begin, NULL); - srandom(begin.tv_usec); - - for (i = 0; i < 10000; i++) { - - /* - * Compute the offset address to read from - */ - offset = (random() % NROFFSET) * PAGESIZE; - - /* - * man posix_fadvise - */ - posix_fadvise(fd, offset, PAGESIZE, - POSIX_FADV_DONTNEED); - - /* - * Measure the time to read a PAGESIZE buffer - */ - gettimeofday(&begin, NULL); - pread(fd, buffer, PAGESIZE, offset); - gettimeofday(&end, NULL); - latency = ((end.tv_sec - begin.tv_sec) * 1000000) + ( - end.tv_usec - begin.tv_usec); - - /* - * Fill a bucket with this latency - */ - bucket_fill(latency); - } + access_file(fd, &options); bucket_show(); |