| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 1 | /* | 
|  | 2 | * blktrace support code for fio | 
|  | 3 | */ | 
|  | 4 | #include <stdio.h> | 
|  | 5 | #include <stdlib.h> | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 6 | #include <sys/stat.h> | 
|  | 7 | #include <dirent.h> | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 8 |  | 
| Jens Axboe | 01743ee | 2008-06-02 12:19:19 +0200 | [diff] [blame] | 9 | #include "flist.h" | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 10 | #include "fio.h" | 
|  | 11 | #include "blktrace_api.h" | 
|  | 12 |  | 
| Jens Axboe | 2da7df1 | 2010-08-01 21:27:28 +0200 | [diff] [blame] | 13 | #define TRACE_FIFO_SIZE	8192 | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 14 |  | 
|  | 15 | /* | 
|  | 16 | * fifo refill frontend, to avoid reading data in trace sized bites | 
|  | 17 | */ | 
|  | 18 | static int refill_fifo(struct thread_data *td, struct fifo *fifo, int fd) | 
|  | 19 | { | 
|  | 20 | char buf[TRACE_FIFO_SIZE]; | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 21 | unsigned int total; | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 22 | int ret; | 
|  | 23 |  | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 24 | total = sizeof(buf); | 
|  | 25 | if (total > fifo_room(fifo)) | 
|  | 26 | total = fifo_room(fifo); | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 27 |  | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 28 | ret = read(fd, buf, total); | 
|  | 29 | if (ret < 0) { | 
|  | 30 | td_verror(td, errno, "read blktrace file"); | 
|  | 31 | return -1; | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 32 | } | 
|  | 33 |  | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 34 | if (ret > 0) | 
|  | 35 | ret = fifo_put(fifo, buf, ret); | 
|  | 36 |  | 
| Jens Axboe | bd6f78b | 2008-02-01 20:27:52 +0100 | [diff] [blame] | 37 | dprint(FD_BLKTRACE, "refill: filled %d bytes\n", ret); | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 38 | return ret; | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 39 | } | 
|  | 40 |  | 
|  | 41 | /* | 
|  | 42 | * Retrieve 'len' bytes from the fifo, refilling if necessary. | 
|  | 43 | */ | 
|  | 44 | static int trace_fifo_get(struct thread_data *td, struct fifo *fifo, int fd, | 
|  | 45 | void *buf, unsigned int len) | 
|  | 46 | { | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 47 | if (fifo_len(fifo) < len) { | 
|  | 48 | int ret = refill_fifo(td, fifo, fd); | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 49 |  | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 50 | if (ret < 0) | 
|  | 51 | return ret; | 
|  | 52 | } | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 53 |  | 
|  | 54 | return fifo_get(fifo, buf, len); | 
|  | 55 | } | 
|  | 56 |  | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 57 | /* | 
|  | 58 | * Just discard the pdu by seeking past it. | 
|  | 59 | */ | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 60 | static int discard_pdu(struct thread_data *td, struct fifo *fifo, int fd, | 
|  | 61 | struct blk_io_trace *t) | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 62 | { | 
|  | 63 | if (t->pdu_len == 0) | 
|  | 64 | return 0; | 
|  | 65 |  | 
| Jens Axboe | bd6f78b | 2008-02-01 20:27:52 +0100 | [diff] [blame] | 66 | dprint(FD_BLKTRACE, "discard pdu len %u\n", t->pdu_len); | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 67 | return trace_fifo_get(td, fifo, fd, NULL, t->pdu_len); | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 68 | } | 
|  | 69 |  | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 70 | /* | 
|  | 71 | * Check if this is a blktrace binary data file. We read a single trace | 
|  | 72 | * into memory and check for the magic signature. | 
|  | 73 | */ | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 74 | int is_blktrace(const char *filename, int *need_swap) | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 75 | { | 
|  | 76 | struct blk_io_trace t; | 
|  | 77 | int fd, ret; | 
|  | 78 |  | 
|  | 79 | fd = open(filename, O_RDONLY); | 
| Jens Axboe | 4dced40 | 2007-07-23 14:16:55 +0200 | [diff] [blame] | 80 | if (fd < 0) | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 81 | return 0; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 82 |  | 
|  | 83 | ret = read(fd, &t, sizeof(t)); | 
|  | 84 | close(fd); | 
|  | 85 |  | 
|  | 86 | if (ret < 0) { | 
|  | 87 | perror("read blktrace"); | 
|  | 88 | return 0; | 
|  | 89 | } else if (ret != sizeof(t)) { | 
|  | 90 | log_err("fio: short read on blktrace file\n"); | 
|  | 91 | return 0; | 
|  | 92 | } | 
|  | 93 |  | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 94 | if ((t.magic & 0xffffff00) == BLK_IO_TRACE_MAGIC) { | 
|  | 95 | *need_swap = 0; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 96 | return 1; | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 97 | } | 
|  | 98 |  | 
|  | 99 | /* | 
|  | 100 | * Maybe it needs to be endian swapped... | 
|  | 101 | */ | 
|  | 102 | t.magic = fio_swap32(t.magic); | 
|  | 103 | if ((t.magic & 0xffffff00) == BLK_IO_TRACE_MAGIC) { | 
|  | 104 | *need_swap = 1; | 
|  | 105 | return 1; | 
|  | 106 | } | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 107 |  | 
|  | 108 | return 0; | 
|  | 109 | } | 
|  | 110 |  | 
| David Nellans | d1c46c0 | 2010-08-31 21:20:47 +0200 | [diff] [blame] | 111 | static int lookup_device(struct thread_data *td, char *path, unsigned int maj, | 
|  | 112 | unsigned int min) | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 113 | { | 
|  | 114 | struct dirent *dir; | 
|  | 115 | struct stat st; | 
|  | 116 | int found = 0; | 
|  | 117 | DIR *D; | 
|  | 118 |  | 
|  | 119 | D = opendir(path); | 
|  | 120 | if (!D) | 
|  | 121 | return 0; | 
|  | 122 |  | 
|  | 123 | while ((dir = readdir(D)) != NULL) { | 
|  | 124 | char full_path[256]; | 
|  | 125 |  | 
|  | 126 | if (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")) | 
|  | 127 | continue; | 
|  | 128 |  | 
| Bruce Cran | b9fd788 | 2012-02-20 17:01:46 +0000 | [diff] [blame] | 129 | sprintf(full_path, "%s%s%s", path, FIO_OS_PATH_SEPARATOR, dir->d_name); | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 130 | if (lstat(full_path, &st) == -1) { | 
|  | 131 | perror("lstat"); | 
|  | 132 | break; | 
|  | 133 | } | 
|  | 134 |  | 
|  | 135 | if (S_ISDIR(st.st_mode)) { | 
| David Nellans | d1c46c0 | 2010-08-31 21:20:47 +0200 | [diff] [blame] | 136 | found = lookup_device(td, full_path, maj, min); | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 137 | if (found) { | 
|  | 138 | strcpy(path, full_path); | 
|  | 139 | break; | 
|  | 140 | } | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | if (!S_ISBLK(st.st_mode)) | 
|  | 144 | continue; | 
|  | 145 |  | 
| David Nellans | d1c46c0 | 2010-08-31 21:20:47 +0200 | [diff] [blame] | 146 | /* | 
|  | 147 | * If replay_redirect is set then always return this device | 
|  | 148 | * upon lookup which overrides the device lookup based on | 
|  | 149 | * major minor in the actual blktrace | 
|  | 150 | */ | 
|  | 151 | if (td->o.replay_redirect) { | 
|  | 152 | dprint(FD_BLKTRACE, "device lookup: %d/%d\n overridden" | 
| Jens Axboe | 25a4e78 | 2014-04-11 00:08:41 +0200 | [diff] [blame] | 153 | " with: %s\n", maj, min, | 
| David Nellans | d1c46c0 | 2010-08-31 21:20:47 +0200 | [diff] [blame] | 154 | td->o.replay_redirect); | 
|  | 155 | strcpy(path, td->o.replay_redirect); | 
|  | 156 | found = 1; | 
|  | 157 | break; | 
|  | 158 | } | 
|  | 159 |  | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 160 | if (maj == major(st.st_rdev) && min == minor(st.st_rdev)) { | 
| Jens Axboe | 5ec10ea | 2008-03-06 15:42:00 +0100 | [diff] [blame] | 161 | dprint(FD_BLKTRACE, "device lookup: %d/%d\n", maj, min); | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 162 | strcpy(path, full_path); | 
|  | 163 | found = 1; | 
|  | 164 | break; | 
|  | 165 | } | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | closedir(D); | 
|  | 169 | return found; | 
|  | 170 | } | 
|  | 171 |  | 
| Jens Axboe | c69aa91 | 2007-05-22 15:51:50 +0200 | [diff] [blame] | 172 | #define FMINORBITS	20 | 
|  | 173 | #define FMINORMASK	((1U << FMINORBITS) - 1) | 
|  | 174 | #define FMAJOR(dev)	((unsigned int) ((dev) >> FMINORBITS)) | 
|  | 175 | #define FMINOR(dev)	((unsigned int) ((dev) & FMINORMASK)) | 
| Jens Axboe | eeb9c2a | 2007-05-16 18:28:47 +0200 | [diff] [blame] | 176 |  | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 177 | static void trace_add_open_close_event(struct thread_data *td, int fileno, enum file_log_act action) | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 178 | { | 
|  | 179 | struct io_piece *ipo; | 
|  | 180 |  | 
|  | 181 | ipo = calloc(1, sizeof(*ipo)); | 
| Jens Axboe | 0d29de8 | 2010-09-01 13:54:15 +0200 | [diff] [blame] | 182 | init_ipo(ipo); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 183 |  | 
|  | 184 | ipo->ddir = DDIR_INVAL; | 
|  | 185 | ipo->fileno = fileno; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 186 | ipo->file_action = action; | 
| Jens Axboe | 01743ee | 2008-06-02 12:19:19 +0200 | [diff] [blame] | 187 | flist_add_tail(&ipo->list, &td->io_log_list); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 188 | } | 
|  | 189 |  | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 190 | static int trace_add_file(struct thread_data *td, __u32 device) | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 191 | { | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 192 | static unsigned int last_maj, last_min, last_fileno; | 
| Jens Axboe | c69aa91 | 2007-05-22 15:51:50 +0200 | [diff] [blame] | 193 | unsigned int maj = FMAJOR(device); | 
|  | 194 | unsigned int min = FMINOR(device); | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 195 | struct fio_file *f; | 
|  | 196 | char dev[256]; | 
|  | 197 | unsigned int i; | 
|  | 198 |  | 
|  | 199 | if (last_maj == maj && last_min == min) | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 200 | return last_fileno; | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 201 |  | 
|  | 202 | last_maj = maj; | 
|  | 203 | last_min = min; | 
|  | 204 |  | 
|  | 205 | /* | 
|  | 206 | * check for this file in our list | 
|  | 207 | */ | 
|  | 208 | for_each_file(td, f, i) | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 209 | if (f->major == maj && f->minor == min) { | 
|  | 210 | last_fileno = f->fileno; | 
|  | 211 | return last_fileno; | 
|  | 212 | } | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 213 |  | 
|  | 214 | strcpy(dev, "/dev"); | 
| David Nellans | d1c46c0 | 2010-08-31 21:20:47 +0200 | [diff] [blame] | 215 | if (lookup_device(td, dev, maj, min)) { | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 216 | int fileno; | 
|  | 217 |  | 
| Jens Axboe | bd6f78b | 2008-02-01 20:27:52 +0100 | [diff] [blame] | 218 | dprint(FD_BLKTRACE, "add devices %s\n", dev); | 
| Jens Axboe | 49ffb4a | 2010-08-24 15:01:37 +0200 | [diff] [blame] | 219 | fileno = add_file_exclusive(td, dev); | 
| Jens Axboe | b53f2c5 | 2014-04-08 21:07:12 -0600 | [diff] [blame] | 220 | td->o.open_files++; | 
| Jens Axboe | 5903e7b | 2014-02-26 13:42:13 -0800 | [diff] [blame] | 221 | td->files[fileno]->major = maj; | 
|  | 222 | td->files[fileno]->minor = min; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 223 | trace_add_open_close_event(td, fileno, FIO_LOG_OPEN_FILE); | 
|  | 224 | last_fileno = fileno; | 
| Jens Axboe | bd6f78b | 2008-02-01 20:27:52 +0100 | [diff] [blame] | 225 | } | 
| Jens Axboe | f01b34a | 2013-11-21 11:13:12 -0700 | [diff] [blame] | 226 |  | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 227 | return last_fileno; | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 228 | } | 
|  | 229 |  | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 230 | /* | 
|  | 231 | * Store blk_io_trace data in an ipo for later retrieval. | 
|  | 232 | */ | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 233 | static void store_ipo(struct thread_data *td, unsigned long long offset, | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 234 | unsigned int bytes, int rw, unsigned long long ttime, | 
|  | 235 | int fileno) | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 236 | { | 
|  | 237 | struct io_piece *ipo = malloc(sizeof(*ipo)); | 
|  | 238 |  | 
| Jens Axboe | 0d29de8 | 2010-09-01 13:54:15 +0200 | [diff] [blame] | 239 | init_ipo(ipo); | 
|  | 240 |  | 
| Jens Axboe | a2eea81 | 2007-05-15 13:10:41 +0200 | [diff] [blame] | 241 | /* | 
|  | 242 | * the 512 is wrong here, it should be the hardware sector size... | 
|  | 243 | */ | 
|  | 244 | ipo->offset = offset * 512; | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 245 | ipo->len = bytes; | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 246 | ipo->delay = ttime / 1000; | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 247 | if (rw) | 
|  | 248 | ipo->ddir = DDIR_WRITE; | 
|  | 249 | else | 
|  | 250 | ipo->ddir = DDIR_READ; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 251 | ipo->fileno = fileno; | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 252 |  | 
| Jens Axboe | bd6f78b | 2008-02-01 20:27:52 +0100 | [diff] [blame] | 253 | dprint(FD_BLKTRACE, "store ddir=%d, off=%llu, len=%lu, delay=%lu\n", | 
|  | 254 | ipo->ddir, ipo->offset, | 
|  | 255 | ipo->len, ipo->delay); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 256 | queue_io_piece(td, ipo); | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 257 | } | 
|  | 258 |  | 
| Jens Axboe | 0b9d69e | 2009-09-11 22:29:54 +0200 | [diff] [blame] | 259 | static void handle_trace_notify(struct blk_io_trace *t) | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 260 | { | 
|  | 261 | switch (t->action) { | 
|  | 262 | case BLK_TN_PROCESS: | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 263 | dprint(FD_BLKTRACE, "got process notify: %x, %d\n", | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 264 | t->action, t->pid); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 265 | break; | 
|  | 266 | case BLK_TN_TIMESTAMP: | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 267 | dprint(FD_BLKTRACE, "got timestamp notify: %x, %d\n", | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 268 | t->action, t->pid); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 269 | break; | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 270 | case BLK_TN_MESSAGE: | 
|  | 271 | break; | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 272 | default: | 
|  | 273 | dprint(FD_BLKTRACE, "unknown trace act %x\n", t->action); | 
|  | 274 | break; | 
|  | 275 | } | 
|  | 276 | } | 
|  | 277 |  | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 278 | static void handle_trace_discard(struct thread_data *td, | 
|  | 279 | struct blk_io_trace *t, | 
|  | 280 | unsigned long long ttime, | 
|  | 281 | unsigned long *ios, unsigned int *bs) | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 282 | { | 
|  | 283 | struct io_piece *ipo = malloc(sizeof(*ipo)); | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 284 | int fileno; | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 285 |  | 
| Jens Axboe | 0d29de8 | 2010-09-01 13:54:15 +0200 | [diff] [blame] | 286 | init_ipo(ipo); | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 287 | fileno = trace_add_file(td, t->device); | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 288 |  | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 289 | ios[DDIR_TRIM]++; | 
|  | 290 | if (t->bytes > bs[DDIR_TRIM]) | 
|  | 291 | bs[DDIR_TRIM] = t->bytes; | 
|  | 292 |  | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 293 | td->o.size += t->bytes; | 
|  | 294 |  | 
|  | 295 | memset(ipo, 0, sizeof(*ipo)); | 
|  | 296 | INIT_FLIST_HEAD(&ipo->list); | 
|  | 297 |  | 
|  | 298 | /* | 
|  | 299 | * the 512 is wrong here, it should be the hardware sector size... | 
|  | 300 | */ | 
|  | 301 | ipo->offset = t->sector * 512; | 
|  | 302 | ipo->len = t->bytes; | 
|  | 303 | ipo->delay = ttime / 1000; | 
|  | 304 | ipo->ddir = DDIR_TRIM; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 305 | ipo->fileno = fileno; | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 306 |  | 
|  | 307 | dprint(FD_BLKTRACE, "store discard, off=%llu, len=%lu, delay=%lu\n", | 
|  | 308 | ipo->offset, ipo->len, | 
|  | 309 | ipo->delay); | 
|  | 310 | queue_io_piece(td, ipo); | 
|  | 311 | } | 
|  | 312 |  | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 313 | static void handle_trace_fs(struct thread_data *td, struct blk_io_trace *t, | 
|  | 314 | unsigned long long ttime, unsigned long *ios, | 
|  | 315 | unsigned int *bs) | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 316 | { | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 317 | int rw; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 318 | int fileno; | 
| Jens Axboe | fdefd98 | 2007-05-15 10:12:26 +0200 | [diff] [blame] | 319 |  | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 320 | fileno = trace_add_file(td, t->device); | 
| Jens Axboe | 5e6c206 | 2007-05-16 14:40:29 +0200 | [diff] [blame] | 321 |  | 
| Jens Axboe | e7a7d70 | 2007-05-15 10:13:04 +0200 | [diff] [blame] | 322 | rw = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0; | 
| Jens Axboe | d84f8d4 | 2007-05-16 08:47:46 +0200 | [diff] [blame] | 323 |  | 
|  | 324 | if (t->bytes > bs[rw]) | 
|  | 325 | bs[rw] = t->bytes; | 
|  | 326 |  | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 327 | ios[rw]++; | 
| Jens Axboe | 6df8ada | 2007-05-15 13:23:19 +0200 | [diff] [blame] | 328 | td->o.size += t->bytes; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 329 | store_ipo(td, t->sector, t->bytes, rw, ttime, fileno); | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 330 | } | 
|  | 331 |  | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 332 | /* | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 333 | * We only care for queue traces, most of the others are side effects | 
|  | 334 | * due to internal workings of the block layer. | 
|  | 335 | */ | 
|  | 336 | static void handle_trace(struct thread_data *td, struct blk_io_trace *t, | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 337 | unsigned long *ios, unsigned int *bs) | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 338 | { | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 339 | static unsigned long long last_ttime; | 
|  | 340 | unsigned long long delay; | 
|  | 341 |  | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 342 | if ((t->action & 0xffff) != __BLK_TA_QUEUE) | 
|  | 343 | return; | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 344 |  | 
|  | 345 | if (!(t->action & BLK_TC_ACT(BLK_TC_NOTIFY))) { | 
|  | 346 | if (!last_ttime || td->o.no_stall) { | 
|  | 347 | last_ttime = t->time; | 
|  | 348 | delay = 0; | 
|  | 349 | } else { | 
|  | 350 | delay = t->time - last_ttime; | 
|  | 351 | last_ttime = t->time; | 
|  | 352 | } | 
|  | 353 | } | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 354 |  | 
|  | 355 | if (t->action & BLK_TC_ACT(BLK_TC_NOTIFY)) | 
| Jens Axboe | aec2de2 | 2008-04-24 12:44:42 +0200 | [diff] [blame] | 356 | handle_trace_notify(t); | 
| Jens Axboe | ff58fce | 2010-08-25 12:02:08 +0200 | [diff] [blame] | 357 | else if (t->action & BLK_TC_ACT(BLK_TC_DISCARD)) | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 358 | handle_trace_discard(td, t, delay, ios, bs); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 359 | else | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 360 | handle_trace_fs(td, t, delay, ios, bs); | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 361 | } | 
|  | 362 |  | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 363 | static void byteswap_trace(struct blk_io_trace *t) | 
|  | 364 | { | 
|  | 365 | t->magic = fio_swap32(t->magic); | 
|  | 366 | t->sequence = fio_swap32(t->sequence); | 
|  | 367 | t->time = fio_swap64(t->time); | 
|  | 368 | t->sector = fio_swap64(t->sector); | 
|  | 369 | t->bytes = fio_swap32(t->bytes); | 
|  | 370 | t->action = fio_swap32(t->action); | 
|  | 371 | t->pid = fio_swap32(t->pid); | 
|  | 372 | t->device = fio_swap32(t->device); | 
|  | 373 | t->cpu = fio_swap32(t->cpu); | 
|  | 374 | t->error = fio_swap16(t->error); | 
|  | 375 | t->pdu_len = fio_swap16(t->pdu_len); | 
|  | 376 | } | 
|  | 377 |  | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 378 | static int t_is_write(struct blk_io_trace *t) | 
|  | 379 | { | 
|  | 380 | return (t->action & BLK_TC_ACT(BLK_TC_WRITE | BLK_TC_DISCARD)) != 0; | 
|  | 381 | } | 
|  | 382 |  | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 383 | /* | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 384 | * Load a blktrace file by reading all the blk_io_trace entries, and storing | 
|  | 385 | * them as io_pieces like the fio text version would do. | 
|  | 386 | */ | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 387 | int load_blktrace(struct thread_data *td, const char *filename, int need_swap) | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 388 | { | 
|  | 389 | struct blk_io_trace t; | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 390 | unsigned long ios[DDIR_RWDIR_CNT], skipped_writes; | 
|  | 391 | unsigned int rw_bs[DDIR_RWDIR_CNT]; | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 392 | struct fifo *fifo; | 
| Jens Axboe | 5903e7b | 2014-02-26 13:42:13 -0800 | [diff] [blame] | 393 | int fd, i, old_state; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 394 | struct fio_file *f; | 
| Jens Axboe | eb5fdcf | 2014-04-08 13:43:19 -0600 | [diff] [blame] | 395 | int this_depth, depth; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 396 |  | 
|  | 397 | fd = open(filename, O_RDONLY); | 
|  | 398 | if (fd < 0) { | 
|  | 399 | td_verror(td, errno, "open blktrace file"); | 
|  | 400 | return 1; | 
|  | 401 | } | 
|  | 402 |  | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 403 | fifo = fifo_alloc(TRACE_FIFO_SIZE); | 
|  | 404 |  | 
| Jens Axboe | 8edd973 | 2014-03-01 08:24:03 -0700 | [diff] [blame] | 405 | old_state = td_bump_runstate(td, TD_SETTING_UP); | 
| Jens Axboe | 5903e7b | 2014-02-26 13:42:13 -0800 | [diff] [blame] | 406 |  | 
| Jens Axboe | 6df8ada | 2007-05-15 13:23:19 +0200 | [diff] [blame] | 407 | td->o.size = 0; | 
|  | 408 |  | 
| Jens Axboe | d84f8d4 | 2007-05-16 08:47:46 +0200 | [diff] [blame] | 409 | ios[0] = ios[1] = 0; | 
|  | 410 | rw_bs[0] = rw_bs[1] = 0; | 
| Jens Axboe | 4241ea8 | 2007-09-12 08:18:36 +0200 | [diff] [blame] | 411 | skipped_writes = 0; | 
| Jens Axboe | eb5fdcf | 2014-04-08 13:43:19 -0600 | [diff] [blame] | 412 | this_depth = depth = 0; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 413 | do { | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 414 | int ret = trace_fifo_get(td, fifo, fd, &t, sizeof(t)); | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 415 |  | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 416 | if (ret < 0) | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 417 | goto err; | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 418 | else if (!ret) | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 419 | break; | 
| Jens Axboe | e288756 | 2007-05-16 09:25:09 +0200 | [diff] [blame] | 420 | else if (ret < (int) sizeof(t)) { | 
|  | 421 | log_err("fio: short fifo get\n"); | 
|  | 422 | break; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 423 | } | 
|  | 424 |  | 
| Jens Axboe | d95b34a | 2013-11-21 09:55:49 -0700 | [diff] [blame] | 425 | if (need_swap) | 
|  | 426 | byteswap_trace(&t); | 
|  | 427 |  | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 428 | if ((t.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) { | 
| Jens Axboe | 5ec10ea | 2008-03-06 15:42:00 +0100 | [diff] [blame] | 429 | log_err("fio: bad magic in blktrace data: %x\n", | 
|  | 430 | t.magic); | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 431 | goto err; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 432 | } | 
|  | 433 | if ((t.magic & 0xff) != BLK_IO_TRACE_VERSION) { | 
| Jens Axboe | 5ec10ea | 2008-03-06 15:42:00 +0100 | [diff] [blame] | 434 | log_err("fio: bad blktrace version %d\n", | 
|  | 435 | t.magic & 0xff); | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 436 | goto err; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 437 | } | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 438 | ret = discard_pdu(td, fifo, fd, &t); | 
|  | 439 | if (ret < 0) { | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 440 | td_verror(td, ret, "blktrace lseek"); | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 441 | goto err; | 
| Jens Axboe | f12b323 | 2007-05-16 12:16:44 +0200 | [diff] [blame] | 442 | } else if (t.pdu_len != ret) { | 
|  | 443 | log_err("fio: discarded %d of %d\n", ret, t.pdu_len); | 
|  | 444 | goto err; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 445 | } | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 446 | if ((t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) == 0) { | 
| Jens Axboe | eb5fdcf | 2014-04-08 13:43:19 -0600 | [diff] [blame] | 447 | if ((t.action & 0xffff) == __BLK_TA_QUEUE) | 
|  | 448 | this_depth++; | 
|  | 449 | else if ((t.action & 0xffff) == __BLK_TA_COMPLETE) { | 
|  | 450 | depth = max(depth, this_depth); | 
|  | 451 | this_depth = 0; | 
|  | 452 | } | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 453 |  | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 454 | if (t_is_write(&t) && read_only) { | 
| Jens Axboe | 691c8fb | 2008-03-07 14:26:26 +0100 | [diff] [blame] | 455 | skipped_writes++; | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 456 | continue; | 
| David Nellans | 64bbb86 | 2010-08-24 22:13:30 +0200 | [diff] [blame] | 457 | } | 
| Jens Axboe | a6edd63 | 2008-03-07 21:41:54 +0100 | [diff] [blame] | 458 | } | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 459 |  | 
|  | 460 | handle_trace(td, &t, ios, rw_bs); | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 461 | } while (1); | 
|  | 462 |  | 
| Jens Axboe | 85a47ca | 2012-06-11 13:19:13 +0200 | [diff] [blame] | 463 | for (i = 0; i < td->files_index; i++) { | 
| Jens Axboe | f01b34a | 2013-11-21 11:13:12 -0700 | [diff] [blame] | 464 | f = td->files[i]; | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 465 | trace_add_open_close_event(td, f->fileno, FIO_LOG_CLOSE_FILE); | 
| Jens Axboe | 85a47ca | 2012-06-11 13:19:13 +0200 | [diff] [blame] | 466 | } | 
| Shaohua Li | 89ac1d4 | 2012-06-11 08:56:32 +0200 | [diff] [blame] | 467 |  | 
| Jens Axboe | 38470f8 | 2007-05-16 09:26:23 +0200 | [diff] [blame] | 468 | fifo_free(fifo); | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 469 | close(fd); | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 470 |  | 
| Jens Axboe | 8edd973 | 2014-03-01 08:24:03 -0700 | [diff] [blame] | 471 | td_restore_runstate(td, old_state); | 
| Jens Axboe | 5903e7b | 2014-02-26 13:42:13 -0800 | [diff] [blame] | 472 |  | 
| Jens Axboe | f01b34a | 2013-11-21 11:13:12 -0700 | [diff] [blame] | 473 | if (!td->files_index) { | 
|  | 474 | log_err("fio: did not find replay device(s)\n"); | 
|  | 475 | return 1; | 
|  | 476 | } | 
|  | 477 |  | 
| Jens Axboe | eb5fdcf | 2014-04-08 13:43:19 -0600 | [diff] [blame] | 478 | /* | 
|  | 479 | * For stacked devices, we don't always get a COMPLETE event so | 
|  | 480 | * the depth grows to insane values. Limit it to something sane(r). | 
|  | 481 | */ | 
|  | 482 | if (!depth || depth > 1024) | 
|  | 483 | depth = 1024; | 
|  | 484 |  | 
| Jens Axboe | 4241ea8 | 2007-09-12 08:18:36 +0200 | [diff] [blame] | 485 | if (skipped_writes) | 
| Jens Axboe | 5ec10ea | 2008-03-06 15:42:00 +0100 | [diff] [blame] | 486 | log_err("fio: %s skips replay of %lu writes due to read-only\n", | 
|  | 487 | td->o.name, skipped_writes); | 
| Jens Axboe | 4241ea8 | 2007-09-12 08:18:36 +0200 | [diff] [blame] | 488 |  | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 489 | if (!ios[DDIR_READ] && !ios[DDIR_WRITE]) { | 
|  | 490 | log_err("fio: found no ios in blktrace data\n"); | 
|  | 491 | return 1; | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 492 | } else if (ios[DDIR_READ] && !ios[DDIR_WRITE]) { | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 493 | td->o.td_ddir = TD_DDIR_READ; | 
| Jens Axboe | d84f8d4 | 2007-05-16 08:47:46 +0200 | [diff] [blame] | 494 | td->o.max_bs[DDIR_READ] = rw_bs[DDIR_READ]; | 
|  | 495 | } else if (!ios[DDIR_READ] && ios[DDIR_WRITE]) { | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 496 | td->o.td_ddir = TD_DDIR_WRITE; | 
| Jens Axboe | d84f8d4 | 2007-05-16 08:47:46 +0200 | [diff] [blame] | 497 | td->o.max_bs[DDIR_WRITE] = rw_bs[DDIR_WRITE]; | 
|  | 498 | } else { | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 499 | td->o.td_ddir = TD_DDIR_RW; | 
| Jens Axboe | d84f8d4 | 2007-05-16 08:47:46 +0200 | [diff] [blame] | 500 | td->o.max_bs[DDIR_READ] = rw_bs[DDIR_READ]; | 
|  | 501 | td->o.max_bs[DDIR_WRITE] = rw_bs[DDIR_WRITE]; | 
| Jens Axboe | 5bca6f9 | 2014-07-14 15:07:11 +0200 | [diff] [blame^] | 502 | td->o.max_bs[DDIR_TRIM] = rw_bs[DDIR_TRIM]; | 
| Jens Axboe | d84f8d4 | 2007-05-16 08:47:46 +0200 | [diff] [blame] | 503 | } | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 504 |  | 
|  | 505 | /* | 
|  | 506 | * We need to do direct/raw ios to the device, to avoid getting | 
|  | 507 | * read-ahead in our way. | 
|  | 508 | */ | 
|  | 509 | td->o.odirect = 1; | 
|  | 510 |  | 
| Jens Axboe | eb5fdcf | 2014-04-08 13:43:19 -0600 | [diff] [blame] | 511 | /* | 
|  | 512 | * we don't know if this option was set or not. it defaults to 1, | 
|  | 513 | * so we'll just guess that we should override it if it's still 1 | 
|  | 514 | */ | 
|  | 515 | if (td->o.iodepth != 1) | 
|  | 516 | td->o.iodepth = depth; | 
|  | 517 |  | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 518 | return 0; | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 519 | err: | 
|  | 520 | close(fd); | 
| Jens Axboe | 38470f8 | 2007-05-16 09:26:23 +0200 | [diff] [blame] | 521 | fifo_free(fifo); | 
| Jens Axboe | 8c1fdf0 | 2007-05-15 11:54:21 +0200 | [diff] [blame] | 522 | return 1; | 
| Jens Axboe | fb7b71a | 2007-05-15 08:44:04 +0200 | [diff] [blame] | 523 | } |