summaryrefslogtreecommitdiff
path: root/ioshark/ioshark_bench_mmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioshark/ioshark_bench_mmap.c')
-rw-r--r--ioshark/ioshark_bench_mmap.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/ioshark/ioshark_bench_mmap.c b/ioshark/ioshark_bench_mmap.c
new file mode 100644
index 00000000..7ee7c41b
--- /dev/null
+++ b/ioshark/ioshark_bench_mmap.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <linux/fs.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include "ioshark.h"
+#include "ioshark_bench.h"
+
+/*
+ * The purpose of this code is to convert mmap() calls into
+ * a mix of (semi)-random reads and writes.
+ * PROT_READ => 4KB/8KB/16KB random reads.
+ * PROT_WRITE => adds 4KB random writes.
+ */
+
+extern char *progname;
+
+#define IOSHARK_MAX_MMAP_IOLEN (16*1024)
+
+#define MMAP_ENTS 16
+
+struct mmap_io_ent_tab_s {
+ off_t offset;
+ size_t len;
+};
+
+struct mmap_io_ent_s {
+ int num_entries;
+ struct mmap_io_ent_tab_s table[MMAP_ENTS + 1];
+ size_t resid;
+};
+
+static void
+setup_mmap_io_state(struct mmap_io_ent_s *mio,
+ size_t total_len, off_t offset)
+{
+ int slice;
+
+ memset(mio, 0, sizeof(struct mmap_io_ent_s));
+ mio->resid = total_len;
+ slice = MAX(IOSHARK_MAX_MMAP_IOLEN,
+ total_len / MMAP_ENTS);
+ while (total_len > 0) {
+ assert(mio->num_entries < MMAP_ENTS + 1);
+ mio->table[mio->num_entries].offset = offset;
+ mio->table[mio->num_entries].len =
+ MIN((u_int64_t)total_len, (u_int64_t)slice);
+ total_len -= mio->table[mio->num_entries].len;
+ offset += mio->table[mio->num_entries].len;
+ mio->num_entries++;
+ }
+}
+
+static size_t
+mmap_getnext_off_len(struct mmap_io_ent_s *mio,
+ off_t *offset)
+{
+ int i;
+ int find_rand_index[MMAP_ENTS + 1];
+ int rand_index_len = 0;
+ size_t iolength;
+
+ if (mio->resid == 0)
+ return 0;
+ /* Pick a slot with residual length > 0 at random first */
+ for (i = 0 ; i < MMAP_ENTS + 1 ; i++) {
+ if (mio->table[i].len > 0)
+ find_rand_index[rand_index_len++] = i;
+ }
+ i = find_rand_index[rand() % rand_index_len];
+ /* Randomize iolength 4K-16K */
+ iolength = ((rand() % 4) + 1) * 4096;
+ iolength = MIN(mio->table[i].len, iolength);
+ *offset = mio->table[i].offset;
+ mio->table[i].offset += iolength;
+ mio->table[i].len -= iolength;
+ mio->resid -= iolength;
+ return iolength;
+}
+
+static void
+mmap_do_io(void *db_node, int prot, off_t offset, size_t len,
+ char **bufp, int *buflen, u_int64_t *op_counts,
+ struct rw_bytes_s *rw_bytes, struct timeval *io_time)
+{
+ struct timeval start;
+ char *p;
+ int ret;
+
+ if (!(prot & IOSHARK_PROT_WRITE)) {
+ /* Only preads */
+ p = get_buf(bufp, buflen, len, 0);
+ (void)gettimeofday(&start,
+ (struct timezone *)NULL);
+ ret = pread(files_db_get_fd(db_node),
+ p, len, offset);
+ update_delta_time(&start, io_time);
+ rw_bytes->bytes_read += len;
+ if (ret < 0) {
+ fprintf(stderr,
+ "%s: mapped pread(%s %lu %lu) error fd=%d %s\n",
+ progname, files_db_get_filename(db_node),
+ len, offset, files_db_get_fd(db_node),
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ op_counts[IOSHARK_MAPPED_PREAD]++;
+ } else {
+ /* 50-50 R/W */
+ if ((rand() % 2) == 1) {
+ p = get_buf(bufp, buflen, len, 1);
+ (void)gettimeofday(&start,
+ (struct timezone *)NULL);
+ ret = pwrite(files_db_get_fd(db_node),
+ p, len, offset);
+ update_delta_time(&start, io_time);
+ rw_bytes->bytes_written += len;
+ if (ret < 0) {
+#if 0
+ fprintf(stderr,
+ "%s: mapped pwrite failed, file unwriteable ? open_flags=%x\n",
+ progname,
+ fcntl(files_db_get_fd(db_node), F_GETFL));
+ exit(EXIT_FAILURE);
+#endif
+ } else
+ op_counts[IOSHARK_MAPPED_PWRITE]++;
+ } else {
+ p = get_buf(bufp, buflen, len, 0);
+ (void)gettimeofday(&start,
+ (struct timezone *)NULL);
+ ret = pread(files_db_get_fd(db_node),
+ p, len, offset);
+ update_delta_time(&start, io_time);
+ rw_bytes->bytes_read += len;
+ if (ret < 0) {
+ fprintf(stderr,
+ "%s: mapped pread(%s %lu %lu) error fd=%d %s\n",
+ progname, files_db_get_filename(db_node),
+ len,
+ offset, files_db_get_fd(db_node),
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ op_counts[IOSHARK_MAPPED_PREAD]++;
+ }
+ }
+}
+
+void
+ioshark_handle_mmap(void *db_node,
+ struct ioshark_file_operation *file_op,
+ char **bufp, int *buflen, u_int64_t *op_counts,
+ struct rw_bytes_s *rw_bytes, struct timeval *io_time)
+{
+ off_t offset = file_op->mmap_offset;
+ size_t len = file_op->mmap_len;
+ int prot = file_op->mmap_prot;
+ struct mmap_io_ent_s mio;
+ struct stat statbuf;
+
+ if (fstat(files_db_get_fd(db_node), &statbuf) < 0) {
+ fprintf(stderr,
+ "%s: fstat failure %s\n",
+ __func__, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * The size of the file better accomodate offset + len
+ * Else there is an issue with pre-creation
+ */
+ assert(offset + len <= statbuf.st_size);
+ if (len <= IOSHARK_MAX_MMAP_IOLEN) {
+ mmap_do_io(db_node, prot, offset, len,
+ bufp, buflen, op_counts,
+ rw_bytes, io_time);
+ return;
+ }
+ setup_mmap_io_state(&mio, len, offset);
+ assert(mio.num_entries > 0);
+ while ((len = mmap_getnext_off_len(&mio, &offset))) {
+ assert((offset + len) <=
+ (file_op->mmap_offset + file_op->mmap_len));
+ mmap_do_io(db_node, prot, offset, len, bufp, buflen,
+ op_counts, rw_bytes, io_time);
+ }
+}