summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2014-10-03 13:01:27 +0200
committerDaniel Lezcano <daniel.lezcano@linaro.org>2014-10-03 13:01:27 +0200
commitaac5f6d9b9541f09b4d94a89400b529266d4f61c (patch)
treeeffdbe34363b5da69914f691f522ad5923fe1c5b
parente5832769a00fddb21cd0261fa1c639b71a9ad949 (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.c299
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();