2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <sys/types.h>
21 #include <sys/syscall.h>
26 #include <sys/errno.h>
31 #include "ioshark_bench.h"
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.
40 extern char *progname;
42 #define IOSHARK_MAX_MMAP_IOLEN (16*1024)
46 struct mmap_io_ent_tab_s {
51 struct mmap_io_ent_s {
53 struct mmap_io_ent_tab_s table[MMAP_ENTS + 1];
58 setup_mmap_io_state(struct mmap_io_ent_s *mio,
59 size_t total_len, off_t offset)
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;
79 mmap_getnext_off_len(struct mmap_io_ent_s *mio,
83 int find_rand_index[MMAP_ENTS + 1];
84 int rand_index_len = 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;
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;
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)
113 if (!(prot & IOSHARK_PROT_WRITE)) {
115 p = get_buf(bufp, buflen, len, 0);
116 ret = pread(files_db_get_fd(db_node),
118 rw_bytes->bytes_read += len;
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),
127 op_counts[IOSHARK_MAPPED_PREAD]++;
130 if ((rand() % 2) == 1) {
131 p = get_buf(bufp, buflen, len, 1);
132 ret = pwrite(files_db_get_fd(db_node),
134 rw_bytes->bytes_written += len;
138 "%s: mapped pwrite failed, file unwriteable ? open_flags=%x\n",
140 fcntl(files_db_get_fd(db_node), F_GETFL));
144 op_counts[IOSHARK_MAPPED_PWRITE]++;
146 p = get_buf(bufp, buflen, len, 0);
147 ret = pread(files_db_get_fd(db_node),
149 rw_bytes->bytes_read += len;
152 "%s: mapped pread(%s %zu %lu) error fd=%d %s\n",
153 progname, files_db_get_filename(db_node),
155 offset, files_db_get_fd(db_node),
159 op_counts[IOSHARK_MAPPED_PREAD]++;
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)
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;
176 if (fstat(files_db_get_fd(db_node), &statbuf) < 0) {
178 "%s: fstat failure %s\n",
179 __func__, strerror(errno));
183 * The size of the file better accomodate offset + len
184 * Else there is an issue with pre-creation
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,
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);