Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 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 <sys/stat.h> |
| 25 | #include <sys/errno.h> |
| 26 | #include <fcntl.h> |
| 27 | #include <string.h> |
| 28 | #include <assert.h> |
| 29 | #include <pthread.h> |
| 30 | #include <sys/statfs.h> |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 31 | #include <sys/resource.h> |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 32 | #include <inttypes.h> |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 33 | #include "ioshark.h" |
| 34 | #define IOSHARK_MAIN |
| 35 | #include "ioshark_bench.h" |
| 36 | |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 37 | /* |
| 38 | * Note on "quick" mode where we do reads on existing /system, |
| 39 | * /vendor and other files in ro partitions, instead of creating |
| 40 | * them. The ioshark compiler builds up a table of all the files |
| 41 | * in /system, /vendor and other ro partitions. For files in this |
| 42 | * list, the benchmark skips the pre-creation of these files and |
| 43 | * reads them directly. |
| 44 | * The code relevant to this is in *filename_cache*. |
| 45 | */ |
| 46 | |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 47 | char *progname; |
| 48 | |
Mohan Srinivasan | 9d00a12 | 2017-03-09 11:24:38 -0800 | [diff] [blame] | 49 | #define MAX_INPUT_FILES 8192 |
| 50 | #define MAX_THREADS 8192 |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 51 | |
| 52 | struct thread_state_s { |
| 53 | char *filename; |
| 54 | FILE *fp; |
| 55 | int num_files; |
| 56 | void *db_handle; |
| 57 | }; |
| 58 | |
| 59 | struct thread_state_s thread_state[MAX_INPUT_FILES]; |
| 60 | int num_input_files = 0; |
| 61 | int next_input_file; |
| 62 | |
| 63 | pthread_t tid[MAX_THREADS]; |
| 64 | |
| 65 | /* |
| 66 | * Global options |
| 67 | */ |
| 68 | int do_delay = 0; |
| 69 | int verbose = 0; |
Mohan Srinivasan | 2aa6e6f | 2017-02-22 16:19:25 -0800 | [diff] [blame] | 70 | int summary_mode = 0; |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 71 | int quick_mode = 0; |
Mohan Srinivasan | b9d4b52 | 2017-07-12 14:03:16 -0700 | [diff] [blame] | 72 | char *blockdev_name = NULL; /* if user would like to specify blockdev */ |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 73 | |
| 74 | #if 0 |
| 75 | static long gettid() |
| 76 | { |
| 77 | return syscall(__NR_gettid); |
| 78 | } |
| 79 | #endif |
| 80 | |
| 81 | void usage() |
| 82 | { |
Mohan Srinivasan | b9d4b52 | 2017-07-12 14:03:16 -0700 | [diff] [blame] | 83 | fprintf(stderr, "%s [-b blockdev_name] [-d preserve_delays] [-n num_iterations] [-t num_threads] -q -v | -s <list of parsed input files>\n", |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 84 | progname); |
| 85 | fprintf(stderr, "%s -s, -v are mutually exclusive\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 86 | progname); |
| 87 | exit(EXIT_FAILURE); |
| 88 | } |
| 89 | |
| 90 | pthread_mutex_t time_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 91 | pthread_mutex_t stats_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 92 | pthread_mutex_t work_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 93 | struct timeval aggregate_file_create_time; |
| 94 | struct timeval debug_file_create_time; |
| 95 | struct timeval aggregate_file_remove_time; |
| 96 | struct timeval aggregate_IO_time; |
| 97 | struct timeval aggregate_delay_time; |
| 98 | |
| 99 | u_int64_t aggr_op_counts[IOSHARK_MAX_FILE_OP]; |
| 100 | struct rw_bytes_s aggr_io_rw_bytes; |
| 101 | struct rw_bytes_s aggr_create_rw_bytes; |
| 102 | |
| 103 | /* |
| 104 | * Locking needed here because aggregate_delay_time is updated |
| 105 | * from multiple threads concurrently. |
| 106 | */ |
| 107 | static void |
| 108 | update_time(struct timeval *aggr_time, |
| 109 | struct timeval *delta_time) |
| 110 | { |
| 111 | struct timeval tmp; |
| 112 | |
| 113 | pthread_mutex_lock(&time_mutex); |
| 114 | timeradd(aggr_time, delta_time, &tmp); |
| 115 | *aggr_time = tmp; |
| 116 | pthread_mutex_unlock(&time_mutex); |
| 117 | } |
| 118 | |
| 119 | static void |
| 120 | update_op_counts(u_int64_t *op_counts) |
| 121 | { |
| 122 | int i; |
| 123 | |
| 124 | pthread_mutex_lock(&stats_mutex); |
| 125 | for (i = IOSHARK_LSEEK ; i < IOSHARK_MAX_FILE_OP ; i++) |
| 126 | aggr_op_counts[i] += op_counts[i]; |
| 127 | pthread_mutex_unlock(&stats_mutex); |
| 128 | } |
| 129 | |
| 130 | static void |
| 131 | update_byte_counts(struct rw_bytes_s *dest, struct rw_bytes_s *delta) |
| 132 | { |
| 133 | pthread_mutex_lock(&stats_mutex); |
| 134 | dest->bytes_read += delta->bytes_read; |
| 135 | dest->bytes_written += delta->bytes_written; |
| 136 | pthread_mutex_unlock(&stats_mutex); |
| 137 | } |
| 138 | |
| 139 | static int work_next_file; |
| 140 | static int work_num_files; |
| 141 | |
| 142 | void |
| 143 | init_work(int next_file, int num_files) |
| 144 | { |
| 145 | pthread_mutex_lock(&work_mutex); |
| 146 | work_next_file = next_file; |
| 147 | work_num_files = work_next_file + num_files; |
| 148 | pthread_mutex_unlock(&work_mutex); |
| 149 | } |
| 150 | |
| 151 | /* Dole out the next file to work on to the thread */ |
| 152 | static struct thread_state_s * |
| 153 | get_work() |
| 154 | { |
| 155 | struct thread_state_s *work = NULL; |
| 156 | |
| 157 | pthread_mutex_lock(&work_mutex); |
| 158 | if (work_next_file < work_num_files) |
| 159 | work = &thread_state[work_next_file++]; |
| 160 | pthread_mutex_unlock(&work_mutex); |
| 161 | return work; |
| 162 | } |
| 163 | |
| 164 | static void |
| 165 | create_files(struct thread_state_s *state) |
| 166 | { |
| 167 | int i; |
| 168 | struct ioshark_file_state file_state; |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 169 | char path[MAX_IOSHARK_PATHLEN]; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 170 | void *db_node; |
| 171 | struct rw_bytes_s rw_bytes; |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 172 | char *filename; |
| 173 | int readonly; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 174 | |
| 175 | memset(&rw_bytes, 0, sizeof(struct rw_bytes_s)); |
| 176 | for (i = 0 ; i < state->num_files ; i++) { |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 177 | if (ioshark_read_file_state(state->fp, &file_state) != 1) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 178 | fprintf(stderr, "%s read error tracefile\n", |
| 179 | progname); |
| 180 | exit(EXIT_FAILURE); |
| 181 | } |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 182 | /* |
| 183 | * Check to see if the file is in a readonly partition, |
| 184 | * in which case, we don't have to pre-create the file |
| 185 | * we can just read the existing file. |
| 186 | */ |
| 187 | filename = |
| 188 | get_ro_filename(file_state.global_filename_ix); |
Mohan Srinivasan | 9d00a12 | 2017-03-09 11:24:38 -0800 | [diff] [blame] | 189 | if (quick_mode) |
| 190 | assert(filename != NULL); |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 191 | if (quick_mode == 0 || |
| 192 | is_readonly_mount(filename, file_state.size) == 0) { |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 193 | sprintf(path, "file.%d.%"PRIu64"", |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 194 | (int)(state - thread_state), |
| 195 | file_state.fileno); |
| 196 | create_file(path, file_state.size, |
| 197 | &rw_bytes); |
| 198 | filename = path; |
| 199 | readonly = 0; |
| 200 | } else { |
| 201 | readonly = 1; |
| 202 | } |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 203 | db_node = files_db_add_byfileno(state->db_handle, |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 204 | file_state.fileno, |
| 205 | readonly); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 206 | files_db_update_size(db_node, file_state.size); |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 207 | files_db_update_filename(db_node, filename); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 208 | } |
| 209 | update_byte_counts(&aggr_create_rw_bytes, &rw_bytes); |
| 210 | } |
| 211 | |
| 212 | static void |
| 213 | do_one_io(void *db_node, |
| 214 | struct ioshark_file_operation *file_op, |
| 215 | u_int64_t *op_counts, |
| 216 | struct rw_bytes_s *rw_bytes, |
| 217 | char **bufp, int *buflen) |
| 218 | { |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 219 | assert(file_op->ioshark_io_op < IOSHARK_MAX_FILE_OP); |
| 220 | op_counts[file_op->ioshark_io_op]++; |
| 221 | switch (file_op->ioshark_io_op) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 222 | int ret; |
| 223 | char *p; |
| 224 | int fd; |
| 225 | |
| 226 | case IOSHARK_LSEEK: |
| 227 | case IOSHARK_LLSEEK: |
| 228 | ret = lseek(files_db_get_fd(db_node), |
| 229 | file_op->lseek_offset, |
| 230 | file_op->lseek_action); |
| 231 | if (ret < 0) { |
| 232 | fprintf(stderr, |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 233 | "%s: lseek(%s %"PRIu64" %d) returned error %d\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 234 | progname, files_db_get_filename(db_node), |
| 235 | file_op->lseek_offset, |
| 236 | file_op->lseek_action, errno); |
| 237 | exit(EXIT_FAILURE); |
| 238 | } |
| 239 | break; |
| 240 | case IOSHARK_PREAD64: |
| 241 | p = get_buf(bufp, buflen, file_op->prw_len, 0); |
| 242 | ret = pread(files_db_get_fd(db_node), p, |
| 243 | file_op->prw_len, file_op->prw_offset); |
| 244 | rw_bytes->bytes_read += file_op->prw_len; |
| 245 | if (ret < 0) { |
| 246 | fprintf(stderr, |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 247 | "%s: pread(%s %"PRIu64" %"PRIu64") error %d\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 248 | progname, |
| 249 | files_db_get_filename(db_node), |
| 250 | file_op->prw_len, |
| 251 | file_op->prw_offset, errno); |
| 252 | exit(EXIT_FAILURE); |
| 253 | } |
| 254 | break; |
| 255 | case IOSHARK_PWRITE64: |
| 256 | p = get_buf(bufp, buflen, file_op->prw_len, 1); |
| 257 | ret = pwrite(files_db_get_fd(db_node), p, |
| 258 | file_op->prw_len, file_op->prw_offset); |
| 259 | rw_bytes->bytes_written += file_op->prw_len; |
| 260 | if (ret < 0) { |
| 261 | fprintf(stderr, |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 262 | "%s: pwrite(%s %"PRIu64" %"PRIu64") error %d\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 263 | progname, |
| 264 | files_db_get_filename(db_node), |
| 265 | file_op->prw_len, |
| 266 | file_op->prw_offset, errno); |
| 267 | exit(EXIT_FAILURE); |
| 268 | } |
| 269 | break; |
| 270 | case IOSHARK_READ: |
| 271 | p = get_buf(bufp, buflen, file_op->rw_len, 0); |
| 272 | ret = read(files_db_get_fd(db_node), p, |
| 273 | file_op->rw_len); |
| 274 | rw_bytes->bytes_read += file_op->rw_len; |
| 275 | if (ret < 0) { |
| 276 | fprintf(stderr, |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 277 | "%s: read(%s %"PRIu64") error %d\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 278 | progname, |
| 279 | files_db_get_filename(db_node), |
| 280 | file_op->rw_len, |
| 281 | errno); |
| 282 | exit(EXIT_FAILURE); |
| 283 | } |
| 284 | break; |
| 285 | case IOSHARK_WRITE: |
| 286 | p = get_buf(bufp, buflen, file_op->rw_len, 1); |
| 287 | ret = write(files_db_get_fd(db_node), p, |
| 288 | file_op->rw_len); |
| 289 | rw_bytes->bytes_written += file_op->rw_len; |
| 290 | if (ret < 0) { |
| 291 | fprintf(stderr, |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 292 | "%s: write(%s %"PRIu64") error %d\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 293 | progname, |
| 294 | files_db_get_filename(db_node), |
| 295 | file_op->rw_len, |
| 296 | errno); |
| 297 | exit(EXIT_FAILURE); |
| 298 | } |
| 299 | break; |
| 300 | case IOSHARK_MMAP: |
| 301 | case IOSHARK_MMAP2: |
| 302 | ioshark_handle_mmap(db_node, file_op, |
| 303 | bufp, buflen, op_counts, |
| 304 | rw_bytes); |
| 305 | break; |
| 306 | case IOSHARK_OPEN: |
| 307 | if (file_op->open_flags & O_CREAT) { |
| 308 | fd = open(files_db_get_filename(db_node), |
| 309 | file_op->open_flags, |
| 310 | file_op->open_mode); |
| 311 | if (fd < 0) { |
| 312 | /* |
| 313 | * EEXIST error acceptable, others are fatal. |
| 314 | * Although we failed to O_CREAT the file (O_EXCL) |
| 315 | * We will force an open of the file before any |
| 316 | * IO. |
| 317 | */ |
| 318 | if (errno == EEXIST) { |
| 319 | return; |
| 320 | } else { |
| 321 | fprintf(stderr, |
| 322 | "%s: O_CREAT open(%s %x %o) error %d\n", |
| 323 | progname, |
| 324 | files_db_get_filename(db_node), |
| 325 | file_op->open_flags, |
| 326 | file_op->open_mode, errno); |
| 327 | exit(EXIT_FAILURE); |
| 328 | } |
| 329 | } |
| 330 | } else { |
| 331 | fd = open(files_db_get_filename(db_node), |
| 332 | file_op->open_flags); |
| 333 | if (fd < 0) { |
| 334 | if (file_op->open_flags & O_DIRECTORY) { |
| 335 | /* O_DIRECTORY open()s should fail */ |
| 336 | return; |
| 337 | } else { |
| 338 | fprintf(stderr, |
| 339 | "%s: open(%s %x) error %d\n", |
| 340 | progname, |
| 341 | files_db_get_filename(db_node), |
| 342 | file_op->open_flags, |
| 343 | errno); |
| 344 | exit(EXIT_FAILURE); |
| 345 | } |
| 346 | } |
| 347 | } |
| 348 | files_db_close_fd(db_node); |
| 349 | files_db_update_fd(db_node, fd); |
| 350 | break; |
| 351 | case IOSHARK_FSYNC: |
| 352 | case IOSHARK_FDATASYNC: |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 353 | if (file_op->ioshark_io_op == IOSHARK_FSYNC) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 354 | ret = fsync(files_db_get_fd(db_node)); |
| 355 | if (ret < 0) { |
| 356 | fprintf(stderr, |
| 357 | "%s: fsync(%s) error %d\n", |
| 358 | progname, |
| 359 | files_db_get_filename(db_node), |
| 360 | errno); |
| 361 | exit(EXIT_FAILURE); |
| 362 | } |
| 363 | } else { |
| 364 | ret = fdatasync(files_db_get_fd(db_node)); |
| 365 | if (ret < 0) { |
| 366 | fprintf(stderr, |
| 367 | "%s: fdatasync(%s) error %d\n", |
| 368 | progname, |
| 369 | files_db_get_filename(db_node), |
| 370 | errno); |
| 371 | exit(EXIT_FAILURE); |
| 372 | } |
| 373 | } |
| 374 | break; |
| 375 | case IOSHARK_CLOSE: |
| 376 | ret = close(files_db_get_fd(db_node)); |
| 377 | if (ret < 0) { |
| 378 | fprintf(stderr, |
| 379 | "%s: close(%s) error %d\n", |
| 380 | progname, |
| 381 | files_db_get_filename(db_node), errno); |
| 382 | exit(EXIT_FAILURE); |
| 383 | } |
| 384 | files_db_update_fd(db_node, -1); |
| 385 | break; |
| 386 | default: |
| 387 | fprintf(stderr, "%s: unknown FILE_OP %d\n", |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 388 | progname, file_op->ioshark_io_op); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 389 | exit(EXIT_FAILURE); |
| 390 | break; |
| 391 | } |
| 392 | } |
| 393 | |
| 394 | static void |
| 395 | do_io(struct thread_state_s *state) |
| 396 | { |
| 397 | void *db_node; |
| 398 | struct ioshark_header header; |
| 399 | struct ioshark_file_operation file_op; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 400 | int fd; |
| 401 | int i; |
| 402 | char *buf = NULL; |
| 403 | int buflen = 0; |
| 404 | struct timeval total_delay_time; |
| 405 | u_int64_t op_counts[IOSHARK_MAX_FILE_OP]; |
| 406 | struct rw_bytes_s rw_bytes; |
| 407 | |
| 408 | rewind(state->fp); |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 409 | if (ioshark_read_header(state->fp, &header) != 1) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 410 | fprintf(stderr, "%s read error %s\n", |
| 411 | progname, state->filename); |
| 412 | exit(EXIT_FAILURE); |
| 413 | } |
| 414 | /* |
| 415 | * First open and pre-create all the files. Indexed by fileno. |
| 416 | */ |
| 417 | timerclear(&total_delay_time); |
| 418 | memset(&rw_bytes, 0, sizeof(struct rw_bytes_s)); |
| 419 | memset(op_counts, 0, sizeof(op_counts)); |
| 420 | fseek(state->fp, |
| 421 | sizeof(struct ioshark_header) + |
| 422 | header.num_files * sizeof(struct ioshark_file_state), |
| 423 | SEEK_SET); |
| 424 | /* |
| 425 | * Loop over all the IOs, and launch each |
| 426 | */ |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 427 | for (i = 0 ; i < (int)header.num_io_operations ; i++) { |
| 428 | if (ioshark_read_file_op(state->fp, &file_op) != 1) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 429 | fprintf(stderr, "%s read error trace.outfile\n", |
| 430 | progname); |
George Burgess IV | b4bc355 | 2018-05-17 13:51:34 -0700 | [diff] [blame] | 431 | goto fail; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 432 | } |
| 433 | if (do_delay) { |
| 434 | struct timeval start; |
| 435 | |
| 436 | (void)gettimeofday(&start, (struct timezone *)NULL); |
Mohan Srinivasan | 9d00a12 | 2017-03-09 11:24:38 -0800 | [diff] [blame] | 437 | usleep(file_op.delta_us); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 438 | update_delta_time(&start, &total_delay_time); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 439 | } |
| 440 | db_node = files_db_lookup_byfileno(state->db_handle, |
| 441 | file_op.fileno); |
| 442 | if (db_node == NULL) { |
| 443 | fprintf(stderr, |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 444 | "%s Can't lookup fileno %"PRIu64", fatal error\n", |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 445 | progname, file_op.fileno); |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 446 | fprintf(stderr, |
| 447 | "%s state filename %s, i %d\n", |
| 448 | progname, state->filename, i); |
George Burgess IV | b4bc355 | 2018-05-17 13:51:34 -0700 | [diff] [blame] | 449 | goto fail; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 450 | } |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 451 | if (file_op.ioshark_io_op != IOSHARK_OPEN && |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 452 | files_db_get_fd(db_node) == -1) { |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 453 | int openflags; |
| 454 | |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 455 | /* |
| 456 | * This is a hack to workaround the fact that we did not |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 457 | * see an open() for this file until now. open() the |
| 458 | * file O_RDWR, so that we can perform the IO. |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 459 | */ |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 460 | if (files_db_readonly(db_node)) |
| 461 | openflags = O_RDONLY; |
| 462 | else |
| 463 | openflags = O_RDWR; |
| 464 | fd = open(files_db_get_filename(db_node), |
| 465 | openflags); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 466 | if (fd < 0) { |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 467 | fprintf(stderr, "%s: open(%s %x) error %d\n", |
| 468 | progname, |
| 469 | files_db_get_filename(db_node), |
| 470 | openflags, |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 471 | errno); |
George Burgess IV | b4bc355 | 2018-05-17 13:51:34 -0700 | [diff] [blame] | 472 | goto fail; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 473 | } |
| 474 | files_db_update_fd(db_node, fd); |
| 475 | } |
| 476 | do_one_io(db_node, &file_op, |
| 477 | op_counts, &rw_bytes, &buf, &buflen); |
| 478 | } |
George Burgess IV | b4bc355 | 2018-05-17 13:51:34 -0700 | [diff] [blame] | 479 | |
| 480 | free(buf); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 481 | files_db_fsync_discard_files(state->db_handle); |
| 482 | files_db_close_files(state->db_handle); |
| 483 | update_time(&aggregate_delay_time, &total_delay_time); |
| 484 | update_op_counts(op_counts); |
| 485 | update_byte_counts(&aggr_io_rw_bytes, &rw_bytes); |
George Burgess IV | b4bc355 | 2018-05-17 13:51:34 -0700 | [diff] [blame] | 486 | return; |
| 487 | |
| 488 | fail: |
| 489 | free(buf); |
| 490 | exit(EXIT_FAILURE); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 491 | } |
| 492 | |
| 493 | void * |
| 494 | io_thread(void *unused __attribute__((unused))) |
| 495 | { |
| 496 | struct thread_state_s *state; |
| 497 | |
| 498 | srand(gettid()); |
| 499 | while ((state = get_work())) |
| 500 | do_io(state); |
| 501 | pthread_exit(NULL); |
| 502 | return(NULL); |
| 503 | } |
| 504 | |
| 505 | static void |
| 506 | do_create(struct thread_state_s *state) |
| 507 | { |
| 508 | struct ioshark_header header; |
| 509 | |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 510 | if (ioshark_read_header(state->fp, &header) != 1) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 511 | fprintf(stderr, "%s read error %s\n", |
| 512 | progname, state->filename); |
| 513 | exit(EXIT_FAILURE); |
| 514 | } |
| 515 | state->num_files = header.num_files; |
| 516 | state->db_handle = files_db_create_handle(); |
| 517 | create_files(state); |
| 518 | } |
| 519 | |
| 520 | void * |
| 521 | create_files_thread(void *unused __attribute__((unused))) |
| 522 | { |
| 523 | struct thread_state_s *state; |
| 524 | |
| 525 | while ((state = get_work())) |
| 526 | do_create(state); |
| 527 | pthread_exit(NULL); |
| 528 | return(NULL); |
| 529 | } |
| 530 | |
| 531 | int |
| 532 | get_start_end(int *start_ix) |
| 533 | { |
| 534 | int i, j, ret_numfiles; |
| 535 | u_int64_t free_fs_bytes; |
| 536 | char *infile; |
| 537 | FILE *fp; |
| 538 | struct ioshark_header header; |
| 539 | struct ioshark_file_state file_state; |
| 540 | struct statfs fsstat; |
| 541 | static int fssize_clamp_next_index = 0; |
| 542 | static int chunk = 0; |
| 543 | |
| 544 | if (fssize_clamp_next_index == num_input_files) |
| 545 | return 0; |
| 546 | if (statfs("/data/local/tmp", &fsstat) < 0) { |
| 547 | fprintf(stderr, "%s: Can't statfs /data/local/tmp\n", |
| 548 | progname); |
| 549 | exit(EXIT_FAILURE); |
| 550 | } |
| 551 | free_fs_bytes = (fsstat.f_bavail * fsstat.f_bsize) * 9 /10; |
| 552 | for (i = fssize_clamp_next_index; i < num_input_files; i++) { |
| 553 | infile = thread_state[i].filename; |
| 554 | fp = fopen(infile, "r"); |
| 555 | if (fp == NULL) { |
| 556 | fprintf(stderr, "%s: Can't open %s\n", |
| 557 | progname, infile); |
| 558 | exit(EXIT_FAILURE); |
| 559 | } |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 560 | if (ioshark_read_header(fp, &header) != 1) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 561 | fprintf(stderr, "%s read error %s\n", |
| 562 | progname, infile); |
| 563 | exit(EXIT_FAILURE); |
| 564 | } |
Mohan Srinivasan | 9dd7870 | 2017-07-19 15:26:57 -0700 | [diff] [blame] | 565 | for (j = 0 ; j < (int)header.num_files ; j++) { |
| 566 | if (ioshark_read_file_state(fp, &file_state) != 1) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 567 | fprintf(stderr, "%s read error tracefile\n", |
| 568 | progname); |
| 569 | exit(EXIT_FAILURE); |
| 570 | } |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 571 | if (quick_mode == 0 || |
| 572 | !is_readonly_mount( |
| 573 | get_ro_filename(file_state.global_filename_ix), |
| 574 | file_state.size)) { |
| 575 | if (file_state.size > free_fs_bytes) { |
| 576 | fclose(fp); |
| 577 | goto out; |
| 578 | } |
| 579 | free_fs_bytes -= file_state.size; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 580 | } |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 581 | } |
| 582 | fclose(fp); |
| 583 | } |
| 584 | out: |
| 585 | if (verbose) { |
| 586 | if (chunk > 0 || i < num_input_files) { |
| 587 | printf("Breaking up input files, Chunk %d: %d to %d\n", |
| 588 | chunk++, fssize_clamp_next_index, i - 1); |
| 589 | } else { |
| 590 | printf("Entire Dataset fits start = %d to %d, free_bytes = %ju\n", |
| 591 | fssize_clamp_next_index, |
| 592 | i - fssize_clamp_next_index, |
| 593 | free_fs_bytes); |
| 594 | } |
| 595 | } |
| 596 | *start_ix = fssize_clamp_next_index; |
| 597 | ret_numfiles = i - fssize_clamp_next_index; |
| 598 | fssize_clamp_next_index = i; |
| 599 | return ret_numfiles; |
| 600 | } |
| 601 | |
| 602 | int |
| 603 | ioshark_pthread_create(pthread_t *tidp, void *(*start_routine)(void *)) |
| 604 | { |
| 605 | pthread_attr_t attr; |
| 606 | |
| 607 | pthread_attr_init(&attr); |
| 608 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); |
| 609 | pthread_attr_setstacksize(&attr, (size_t)(1024*1024)); |
| 610 | return pthread_create(tidp, &attr, start_routine, (void *)NULL); |
| 611 | } |
| 612 | |
| 613 | void |
| 614 | wait_for_threads(int num_threads) |
| 615 | { |
| 616 | int i; |
| 617 | |
| 618 | for (i = 0; i < num_threads; i++) { |
| 619 | pthread_join(tid[i], NULL); |
| 620 | tid[i] = 0; |
| 621 | } |
| 622 | } |
| 623 | |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 624 | #define IOSHARK_FD_LIM 8192 |
| 625 | |
| 626 | static void |
| 627 | sizeup_fd_limits(void) |
| 628 | { |
| 629 | struct rlimit r; |
| 630 | |
| 631 | getrlimit(RLIMIT_NOFILE, &r); |
| 632 | if (r.rlim_cur >= IOSHARK_FD_LIM) |
| 633 | /* cur limit already at what we want */ |
| 634 | return; |
| 635 | /* |
| 636 | * Size up both the Max and Cur to IOSHARK_FD_LIM. |
| 637 | * If we are not running as root, this will fail, |
| 638 | * catch that below and exit. |
| 639 | */ |
| 640 | if (r.rlim_max < IOSHARK_FD_LIM) |
| 641 | r.rlim_max = IOSHARK_FD_LIM; |
| 642 | r.rlim_cur = IOSHARK_FD_LIM; |
| 643 | if (setrlimit(RLIMIT_NOFILE, &r) < 0) { |
| 644 | fprintf(stderr, "%s: Can't setrlimit (RLIMIT_NOFILE, 8192)\n", |
| 645 | progname); |
| 646 | exit(EXIT_FAILURE); |
| 647 | } |
| 648 | getrlimit(RLIMIT_NOFILE, &r); |
| 649 | if (r.rlim_cur < IOSHARK_FD_LIM) { |
| 650 | fprintf(stderr, "%s: Can't setrlimit up to 8192\n", |
| 651 | progname); |
| 652 | fprintf(stderr, "%s: Running as root ?\n", |
| 653 | progname); |
| 654 | exit(EXIT_FAILURE); |
| 655 | } |
| 656 | } |
| 657 | |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 658 | int |
| 659 | main(int argc, char **argv) |
| 660 | { |
| 661 | int i; |
| 662 | FILE *fp; |
| 663 | struct stat st; |
| 664 | char *infile; |
| 665 | int num_threads = 0; |
| 666 | int num_iterations = 1; |
| 667 | int c; |
| 668 | int num_files, start_file; |
| 669 | struct thread_state_s *state; |
| 670 | |
| 671 | progname = argv[0]; |
Mohan Srinivasan | b9d4b52 | 2017-07-12 14:03:16 -0700 | [diff] [blame] | 672 | while ((c = getopt(argc, argv, "b:dn:st:qv")) != EOF) { |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 673 | switch (c) { |
Mohan Srinivasan | b9d4b52 | 2017-07-12 14:03:16 -0700 | [diff] [blame] | 674 | case 'b': |
| 675 | blockdev_name = strdup(optarg); |
| 676 | break; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 677 | case 'd': |
| 678 | do_delay = 1; |
| 679 | break; |
| 680 | case 'n': |
| 681 | num_iterations = atoi(optarg); |
| 682 | break; |
Mohan Srinivasan | 2aa6e6f | 2017-02-22 16:19:25 -0800 | [diff] [blame] | 683 | case 's': |
| 684 | /* Non-verbose summary mode for nightly runs */ |
| 685 | summary_mode = 1; |
| 686 | break; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 687 | case 't': |
| 688 | num_threads = atoi(optarg); |
| 689 | break; |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 690 | case 'q': |
| 691 | /* |
| 692 | * If quick mode is enabled, then we won't |
| 693 | * pre-create files that we are doing IO on that |
| 694 | * live in readonly partitions (/system, /vendor etc) |
| 695 | */ |
| 696 | quick_mode = 1; |
| 697 | break; |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 698 | case 'v': |
| 699 | verbose = 1; |
| 700 | break; |
| 701 | default: |
Mohan Srinivasan | 9d00a12 | 2017-03-09 11:24:38 -0800 | [diff] [blame] | 702 | usage(); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 703 | } |
| 704 | } |
| 705 | |
Mohan Srinivasan | 2aa6e6f | 2017-02-22 16:19:25 -0800 | [diff] [blame] | 706 | if ((verbose + summary_mode) == 2) |
| 707 | usage(); |
| 708 | |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 709 | if (num_threads > MAX_THREADS) |
| 710 | usage(); |
| 711 | |
| 712 | if (optind == argc) |
| 713 | usage(); |
| 714 | |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 715 | sizeup_fd_limits(); |
| 716 | |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 717 | for (i = optind; i < argc; i++) { |
| 718 | infile = argv[i]; |
| 719 | if (stat(infile, &st) < 0) { |
| 720 | fprintf(stderr, "%s: Can't stat %s\n", |
| 721 | progname, infile); |
| 722 | exit(EXIT_FAILURE); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 723 | } |
| 724 | if (st.st_size == 0) { |
| 725 | fprintf(stderr, "%s: Empty file %s\n", |
| 726 | progname, infile); |
| 727 | continue; |
| 728 | } |
| 729 | fp = fopen(infile, "r"); |
| 730 | if (fp == NULL) { |
| 731 | fprintf(stderr, "%s: Can't open %s\n", |
| 732 | progname, infile); |
| 733 | continue; |
| 734 | } |
| 735 | thread_state[num_input_files].filename = infile; |
| 736 | thread_state[num_input_files].fp = fp; |
| 737 | num_input_files++; |
| 738 | } |
| 739 | |
| 740 | if (num_input_files == 0) { |
| 741 | exit(EXIT_SUCCESS); |
| 742 | } |
| 743 | if (verbose) { |
| 744 | printf("Total Input Files = %d\n", num_input_files); |
| 745 | printf("Num Iterations = %d\n", num_iterations); |
| 746 | } |
| 747 | timerclear(&aggregate_file_create_time); |
| 748 | timerclear(&aggregate_file_remove_time); |
| 749 | timerclear(&aggregate_IO_time); |
| 750 | |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 751 | if (quick_mode) |
| 752 | init_filename_cache(); |
| 753 | |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 754 | capture_util_state_before(); |
| 755 | |
| 756 | /* |
| 757 | * We pre-create the files that we need once and then we |
| 758 | * loop around N times doing IOs on the pre-created files. |
| 759 | * |
| 760 | * get_start_end() breaks up the total work here to make sure |
| 761 | * that all the files we need to pre-create fit into the |
| 762 | * available space in /data/local/tmp (hardcoded for now). |
| 763 | * |
| 764 | * If it won't fit, then we do several sweeps. |
| 765 | */ |
| 766 | while ((num_files = get_start_end(&start_file))) { |
| 767 | struct timeval time_for_pass; |
| 768 | |
| 769 | /* Create files once */ |
Mohan Srinivasan | 2aa6e6f | 2017-02-22 16:19:25 -0800 | [diff] [blame] | 770 | if (!summary_mode) |
| 771 | printf("Doing Pre-creation of Files\n"); |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 772 | if (quick_mode && !summary_mode) |
| 773 | printf("Skipping Pre-creation of read-only Files\n"); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 774 | if (num_threads == 0 || num_threads > num_files) |
| 775 | num_threads = num_files; |
| 776 | (void)system("echo 3 > /proc/sys/vm/drop_caches"); |
| 777 | init_work(start_file, num_files); |
| 778 | (void)gettimeofday(&time_for_pass, |
| 779 | (struct timezone *)NULL); |
| 780 | for (i = 0; i < num_threads; i++) { |
| 781 | if (ioshark_pthread_create(&(tid[i]), |
| 782 | create_files_thread)) { |
| 783 | fprintf(stderr, |
| 784 | "%s: Can't create creator thread %d\n", |
| 785 | progname, i); |
| 786 | exit(EXIT_FAILURE); |
| 787 | } |
| 788 | } |
| 789 | wait_for_threads(num_threads); |
| 790 | update_delta_time(&time_for_pass, &aggregate_file_create_time); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 791 | /* Do the IOs N times */ |
| 792 | for (i = 0 ; i < num_iterations ; i++) { |
| 793 | (void)system("echo 3 > /proc/sys/vm/drop_caches"); |
Mohan Srinivasan | 2aa6e6f | 2017-02-22 16:19:25 -0800 | [diff] [blame] | 794 | if (!summary_mode) { |
| 795 | if (num_iterations > 1) |
| 796 | printf("Starting Test. Iteration %d...\n", |
| 797 | i); |
| 798 | else |
| 799 | printf("Starting Test...\n"); |
| 800 | } |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 801 | init_work(start_file, num_files); |
| 802 | (void)gettimeofday(&time_for_pass, |
| 803 | (struct timezone *)NULL); |
| 804 | for (c = 0; c < num_threads; c++) { |
| 805 | if (ioshark_pthread_create(&(tid[c]), |
| 806 | io_thread)) { |
| 807 | fprintf(stderr, |
| 808 | "%s: Can't create thread %d\n", |
| 809 | progname, c); |
| 810 | exit(EXIT_FAILURE); |
| 811 | } |
| 812 | } |
| 813 | wait_for_threads(num_threads); |
| 814 | update_delta_time(&time_for_pass, |
| 815 | &aggregate_IO_time); |
| 816 | } |
| 817 | |
| 818 | /* |
| 819 | * We are done with the N iterations of IO. |
| 820 | * Destroy the files we pre-created. |
| 821 | */ |
| 822 | init_work(start_file, num_files); |
| 823 | while ((state = get_work())) { |
| 824 | struct timeval start; |
| 825 | |
| 826 | (void)gettimeofday(&start, (struct timezone *)NULL); |
| 827 | files_db_unlink_files(state->db_handle); |
| 828 | update_delta_time(&start, &aggregate_file_remove_time); |
| 829 | files_db_free_memory(state->db_handle); |
| 830 | } |
| 831 | } |
Mohan Srinivasan | 2aa6e6f | 2017-02-22 16:19:25 -0800 | [diff] [blame] | 832 | if (!summary_mode) { |
| 833 | printf("Total Creation time = %ju.%ju (msecs.usecs)\n", |
| 834 | get_msecs(&aggregate_file_create_time), |
| 835 | get_usecs(&aggregate_file_create_time)); |
| 836 | printf("Total Remove time = %ju.%ju (msecs.usecs)\n", |
| 837 | get_msecs(&aggregate_file_remove_time), |
| 838 | get_usecs(&aggregate_file_remove_time)); |
| 839 | if (do_delay) |
| 840 | printf("Total delay time = %ju.%ju (msecs.usecs)\n", |
| 841 | get_msecs(&aggregate_delay_time), |
| 842 | get_usecs(&aggregate_delay_time)); |
| 843 | printf("Total Test (IO) time = %ju.%ju (msecs.usecs)\n", |
| 844 | get_msecs(&aggregate_IO_time), |
| 845 | get_usecs(&aggregate_IO_time)); |
| 846 | if (verbose) |
| 847 | print_bytes("Upfront File Creation bytes", |
| 848 | &aggr_create_rw_bytes); |
| 849 | print_bytes("Total Test (IO) bytes", &aggr_io_rw_bytes); |
| 850 | if (verbose) |
| 851 | print_op_stats(aggr_op_counts); |
| 852 | report_cpu_disk_util(); |
| 853 | } else { |
| 854 | printf("%ju.%ju ", |
| 855 | get_msecs(&aggregate_file_create_time), |
| 856 | get_usecs(&aggregate_file_create_time)); |
| 857 | printf("%ju.%ju ", |
| 858 | get_msecs(&aggregate_file_remove_time), |
| 859 | get_usecs(&aggregate_file_remove_time)); |
| 860 | if (do_delay) |
| 861 | printf("%ju.%ju ", |
| 862 | get_msecs(&aggregate_delay_time), |
| 863 | get_usecs(&aggregate_delay_time)); |
| 864 | printf("%ju.%ju ", |
| 865 | get_msecs(&aggregate_IO_time), |
| 866 | get_usecs(&aggregate_IO_time)); |
| 867 | print_bytes(NULL, &aggr_io_rw_bytes); |
| 868 | report_cpu_disk_util(); |
| 869 | printf("\n"); |
| 870 | } |
Mohan Srinivasan | 02f8626 | 2017-02-24 16:34:28 -0800 | [diff] [blame] | 871 | if (quick_mode) |
| 872 | free_filename_cache(); |
Mohan Srinivasan | b707f30 | 2017-01-19 16:40:52 -0800 | [diff] [blame] | 873 | } |