Home | History | Annotate | Download | only in ioshark
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <sys/time.h>
     19 #include <sys/types.h>
     20 #include <unistd.h>
     21 #include <sys/syscall.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <pthread.h>
     25 #include <sys/stat.h>
     26 #include <sys/errno.h>
     27 #include <fcntl.h>
     28 #include <string.h>
     29 #include <assert.h>
     30 #include "ioshark.h"
     31 #include "ioshark_bench.h"
     32 
     33 /*
     34  * The purpose of this code is to convert mmap() calls into
     35  * a mix of (semi)-random reads and writes.
     36  * PROT_READ => 4KB/8KB/16KB random reads.
     37  * PROT_WRITE => adds 4KB random writes.
     38  */
     39 
     40 extern char *progname;
     41 
     42 #define IOSHARK_MAX_MMAP_IOLEN	(16*1024)
     43 
     44 #define MMAP_ENTS		16
     45 
     46 struct mmap_io_ent_tab_s {
     47 	off_t offset;
     48 	size_t len;
     49 };
     50 
     51 struct mmap_io_ent_s {
     52 	int				num_entries;
     53 	struct mmap_io_ent_tab_s	table[MMAP_ENTS + 1];
     54 	size_t				resid;
     55 };
     56 
     57 static void
     58 setup_mmap_io_state(struct mmap_io_ent_s *mio,
     59 		    size_t total_len, off_t offset)
     60 {
     61 	int slice;
     62 
     63 	memset(mio, 0, sizeof(struct mmap_io_ent_s));
     64 	mio->resid = total_len;
     65 	slice = MAX(IOSHARK_MAX_MMAP_IOLEN,
     66 		    total_len / MMAP_ENTS);
     67 	while (total_len > 0) {
     68 		assert(mio->num_entries < MMAP_ENTS + 1);
     69 		mio->table[mio->num_entries].offset = offset;
     70 		mio->table[mio->num_entries].len =
     71 			MIN((u_int64_t)total_len, (u_int64_t)slice);
     72 		total_len -= mio->table[mio->num_entries].len;
     73 		offset += mio->table[mio->num_entries].len;
     74 		mio->num_entries++;
     75 	}
     76 }
     77 
     78 static size_t
     79 mmap_getnext_off_len(struct mmap_io_ent_s *mio,
     80 		     off_t *offset)
     81 {
     82 	int i;
     83 	int find_rand_index[MMAP_ENTS + 1];
     84 	int rand_index_len = 0;
     85 	size_t iolength;
     86 
     87 	if (mio->resid == 0)
     88 		return 0;
     89 	/* Pick a slot with residual length > 0 at random first */
     90 	for (i = 0 ; i < MMAP_ENTS + 1 ; i++) {
     91 		if (mio->table[i].len > 0)
     92 			find_rand_index[rand_index_len++] = i;
     93 	}
     94 	i = find_rand_index[rand() % rand_index_len];
     95 	/* Randomize iolength 4K-16K */
     96 	iolength = ((rand() % 4) + 1) * 4096;
     97 	iolength = MIN(mio->table[i].len, iolength);
     98 	*offset = mio->table[i].offset;
     99 	mio->table[i].offset += iolength;
    100 	mio->table[i].len -= iolength;
    101 	mio->resid -= iolength;
    102 	return iolength;
    103 }
    104 
    105 static void
    106 mmap_do_io(void *db_node, int prot, off_t offset, size_t len,
    107 	   char **bufp, int *buflen, u_int64_t *op_counts,
    108 	   struct rw_bytes_s *rw_bytes)
    109 {
    110 	char *p;
    111 	int ret;
    112 
    113 	if (!(prot & IOSHARK_PROT_WRITE)) {
    114 		/* Only preads */
    115 		p = get_buf(bufp, buflen, len, 0);
    116 		ret = pread(files_db_get_fd(db_node),
    117 			    p, len, offset);
    118 		rw_bytes->bytes_read += len;
    119 		if (ret < 0) {
    120 			fprintf(stderr,
    121 				"%s: mapped pread(%s %zu %lu) error fd=%d %s\n",
    122 				progname, files_db_get_filename(db_node),
    123 				len, offset, files_db_get_fd(db_node),
    124 				strerror(errno));
    125 			exit(EXIT_FAILURE);
    126 		}
    127 		op_counts[IOSHARK_MAPPED_PREAD]++;
    128 	} else {
    129 		/* 50-50 R/W */
    130 		if ((rand() % 2) == 1) {
    131 			p = get_buf(bufp, buflen, len, 1);
    132 			ret = pwrite(files_db_get_fd(db_node),
    133 				     p, len, offset);
    134 			rw_bytes->bytes_written += len;
    135 			if (ret < 0) {
    136 #if 0
    137 				fprintf(stderr,
    138 					"%s: mapped pwrite failed, file unwriteable ? open_flags=%x\n",
    139 					progname,
    140 					fcntl(files_db_get_fd(db_node), F_GETFL));
    141 				exit(EXIT_FAILURE);
    142 #endif
    143 			} else
    144 				op_counts[IOSHARK_MAPPED_PWRITE]++;
    145 		} else {
    146 			p = get_buf(bufp, buflen, len, 0);
    147 			ret = pread(files_db_get_fd(db_node),
    148 				    p, len, offset);
    149 			rw_bytes->bytes_read += len;
    150 			if (ret < 0) {
    151 				fprintf(stderr,
    152 				"%s: mapped pread(%s %zu %lu) error fd=%d %s\n",
    153 					progname, files_db_get_filename(db_node),
    154 					len,
    155 					offset, files_db_get_fd(db_node),
    156 					strerror(errno));
    157 				exit(EXIT_FAILURE);
    158 			}
    159 			op_counts[IOSHARK_MAPPED_PREAD]++;
    160 		}
    161 	}
    162 }
    163 
    164 void
    165 ioshark_handle_mmap(void *db_node,
    166 		    struct ioshark_file_operation *file_op,
    167 		    char **bufp, int *buflen, u_int64_t *op_counts,
    168 		    struct rw_bytes_s *rw_bytes)
    169 {
    170 	off_t offset = file_op->mmap_offset;
    171 	size_t len = file_op->mmap_len;
    172 	int prot = file_op->mmap_prot;
    173 	struct mmap_io_ent_s mio;
    174 	struct stat statbuf;
    175 
    176 	if (fstat(files_db_get_fd(db_node), &statbuf) < 0) {
    177 		fprintf(stderr,
    178 			"%s: fstat failure %s\n",
    179 			__func__, strerror(errno));
    180 		exit(EXIT_FAILURE);
    181 	}
    182 	/*
    183 	 * The size of the file better accomodate offset + len
    184 	 * Else there is an issue with pre-creation
    185 	 */
    186 	assert(offset + len <= statbuf.st_size);
    187 	if (len <= IOSHARK_MAX_MMAP_IOLEN) {
    188 		mmap_do_io(db_node, prot, offset, len,
    189 			   bufp, buflen, op_counts,
    190 			   rw_bytes);
    191 		return;
    192 	}
    193 	setup_mmap_io_state(&mio, len, offset);
    194 	assert(mio.num_entries > 0);
    195 	while ((len = mmap_getnext_off_len(&mio, &offset))) {
    196 		assert((offset + len) <=
    197 		       (file_op->mmap_offset + file_op->mmap_len));
    198 		mmap_do_io(db_node, prot, offset, len, bufp, buflen,
    199 			   op_counts, rw_bytes);
    200 	}
    201 }
    202