diff options
Diffstat (limited to 'ioshark/ioshark_bench_mmap.c')
-rw-r--r-- | ioshark/ioshark_bench_mmap.c | 213 |
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); + } +} |