Fix fifo leak
[fio.git] / blktrace.c
CommitLineData
fb7b71a3
JA
1/*
2 * blktrace support code for fio
3 */
4#include <stdio.h>
5#include <stdlib.h>
8c1fdf04 6
fb7b71a3
JA
7#include "list.h"
8#include "fio.h"
9#include "blktrace_api.h"
10
e2887563
JA
11#define TRACE_FIFO_SIZE (sizeof(struct blk_io_trace) * 1000)
12
13/*
14 * fifo refill frontend, to avoid reading data in trace sized bites
15 */
16static int refill_fifo(struct thread_data *td, struct fifo *fifo, int fd)
17{
18 char buf[TRACE_FIFO_SIZE];
19 unsigned int total, left;
20 void *ptr;
21 int ret;
22
23 total = 0;
24 ptr = buf;
25 while (total < TRACE_FIFO_SIZE) {
26 left = TRACE_FIFO_SIZE - total;
27
28 ret = read(fd, ptr, left);
29 if (ret < 0) {
30 td_verror(td, errno, "read blktrace file");
31 return -1;
32 } else if (!ret)
33 break;
34
35 fifo_put(fifo, ptr, ret);
36 ptr += ret;
37 total += ret;
38 }
39
40 return 0;
41}
42
43/*
44 * Retrieve 'len' bytes from the fifo, refilling if necessary.
45 */
46static int trace_fifo_get(struct thread_data *td, struct fifo *fifo, int fd,
47 void *buf, unsigned int len)
48{
49 int ret;
50
51 if (fifo_len(fifo) >= len)
52 return fifo_get(fifo, buf, len);
53
54 ret = refill_fifo(td, fifo, fd);
55 if (ret < 0)
56 return ret;
57
58 if (fifo_len(fifo) < len)
59 return 0;
60
61 return fifo_get(fifo, buf, len);
62}
63
8c1fdf04
JA
64/*
65 * Just discard the pdu by seeking past it.
66 */
fb7b71a3
JA
67static int discard_pdu(int fd, struct blk_io_trace *t)
68{
69 if (t->pdu_len == 0)
70 return 0;
71
72 if (lseek(fd, t->pdu_len, SEEK_CUR) < 0)
73 return errno;
74
75 return 0;
76}
77
8c1fdf04
JA
78/*
79 * Check if this is a blktrace binary data file. We read a single trace
80 * into memory and check for the magic signature.
81 */
fb7b71a3
JA
82int is_blktrace(const char *filename)
83{
84 struct blk_io_trace t;
85 int fd, ret;
86
87 fd = open(filename, O_RDONLY);
88 if (fd < 0) {
89 perror("open blktrace");
90 return 0;
91 }
92
93 ret = read(fd, &t, sizeof(t));
94 close(fd);
95
96 if (ret < 0) {
97 perror("read blktrace");
98 return 0;
99 } else if (ret != sizeof(t)) {
100 log_err("fio: short read on blktrace file\n");
101 return 0;
102 }
103
104 if ((t.magic & 0xffffff00) == BLK_IO_TRACE_MAGIC)
105 return 1;
106
107 return 0;
108}
109
8c1fdf04
JA
110/*
111 * Store blk_io_trace data in an ipo for later retrieval.
112 */
fdefd987 113static void store_ipo(struct thread_data *td, unsigned long long offset,
8c1fdf04 114 unsigned int bytes, int rw, unsigned long long ttime)
fdefd987
JA
115{
116 struct io_piece *ipo = malloc(sizeof(*ipo));
117
118 memset(ipo, 0, sizeof(*ipo));
119 INIT_LIST_HEAD(&ipo->list);
a2eea81b
JA
120 /*
121 * the 512 is wrong here, it should be the hardware sector size...
122 */
123 ipo->offset = offset * 512;
fdefd987 124 ipo->len = bytes;
8c1fdf04 125 ipo->delay = ttime / 1000;
fdefd987
JA
126 if (rw)
127 ipo->ddir = DDIR_WRITE;
128 else
129 ipo->ddir = DDIR_READ;
130
131 list_add_tail(&ipo->list, &td->io_log_list);
132}
133
8c1fdf04
JA
134/*
135 * We only care for queue traces, most of the others are side effects
136 * due to internal workings of the block layer.
137 */
138static void handle_trace(struct thread_data *td, struct blk_io_trace *t,
d84f8d49
JA
139 unsigned long long ttime, unsigned long *ios,
140 unsigned int *bs)
fb7b71a3 141{
fdefd987
JA
142 int rw;
143
144 if ((t->action & 0xffff) != __BLK_TA_QUEUE)
145 return;
a2eea81b
JA
146 if (t->action & BLK_TC_ACT(BLK_TC_PC))
147 return;
148
149 /*
150 * should not happen, need to look into that...
151 */
152 if (!t->bytes)
153 return;
fdefd987 154
e7a7d70b 155 rw = (t->action & BLK_TC_ACT(BLK_TC_WRITE)) != 0;
d84f8d49
JA
156
157 if (t->bytes > bs[rw])
158 bs[rw] = t->bytes;
159
8c1fdf04 160 ios[rw]++;
6df8adaa 161 td->o.size += t->bytes;
8c1fdf04 162 store_ipo(td, t->sector, t->bytes, rw, ttime);
fb7b71a3
JA
163}
164
8c1fdf04
JA
165/*
166 * Load a blktrace file by reading all the blk_io_trace entries, and storing
167 * them as io_pieces like the fio text version would do.
168 */
fb7b71a3
JA
169int load_blktrace(struct thread_data *td, const char *filename)
170{
a61eddec 171 unsigned long long ttime, delay;
fb7b71a3 172 struct blk_io_trace t;
8c1fdf04 173 unsigned long ios[2];
a61eddec 174 unsigned int cpu;
d84f8d49 175 unsigned int rw_bs[2];
e2887563 176 struct fifo *fifo;
fb7b71a3
JA
177 int fd;
178
179 fd = open(filename, O_RDONLY);
180 if (fd < 0) {
181 td_verror(td, errno, "open blktrace file");
182 return 1;
183 }
184
e2887563
JA
185 fifo = fifo_alloc(TRACE_FIFO_SIZE);
186
6df8adaa
JA
187 td->o.size = 0;
188
a61eddec 189 cpu = 0;
d84f8d49
JA
190 ttime = 0;
191 ios[0] = ios[1] = 0;
192 rw_bs[0] = rw_bs[1] = 0;
fb7b71a3 193 do {
e2887563 194 int ret = trace_fifo_get(td, fifo, fd, &t, sizeof(t));
fb7b71a3 195
e2887563 196 if (ret < 0)
8c1fdf04 197 goto err;
e2887563
JA
198 else if (!ret)
199 break;
200 else if (ret < (int) sizeof(t)) {
201 log_err("fio: short fifo get\n");
fb7b71a3 202 break;
fb7b71a3
JA
203 }
204
205 if ((t.magic & 0xffffff00) != BLK_IO_TRACE_MAGIC) {
206 log_err("fio: bad magic in blktrace data\n");
8c1fdf04 207 goto err;
fb7b71a3
JA
208 }
209 if ((t.magic & 0xff) != BLK_IO_TRACE_VERSION) {
210 log_err("fio: bad blktrace version %d\n", t.magic & 0xff);
8c1fdf04 211 goto err;
fb7b71a3
JA
212 }
213 ret = discard_pdu(fd, &t);
214 if (ret) {
215 td_verror(td, ret, "blktrace lseek");
8c1fdf04 216 goto err;
fb7b71a3 217 }
a61eddec 218 if (!ttime) {
8c1fdf04 219 ttime = t.time;
a61eddec
JA
220 cpu = t.cpu;
221 }
222 delay = 0;
223 if (cpu == t.cpu)
224 delay = t.time - ttime;
d84f8d49 225 handle_trace(td, &t, delay, ios, rw_bs);
8c1fdf04 226 ttime = t.time;
a61eddec 227 cpu = t.cpu;
fb7b71a3
JA
228 } while (1);
229
38470f85 230 fifo_free(fifo);
fb7b71a3 231 close(fd);
8c1fdf04
JA
232
233 if (!ios[DDIR_READ] && !ios[DDIR_WRITE]) {
234 log_err("fio: found no ios in blktrace data\n");
235 return 1;
d84f8d49 236 } else if (ios[DDIR_READ] && !ios[DDIR_READ]) {
8c1fdf04 237 td->o.td_ddir = TD_DDIR_READ;
d84f8d49
JA
238 td->o.max_bs[DDIR_READ] = rw_bs[DDIR_READ];
239 } else if (!ios[DDIR_READ] && ios[DDIR_WRITE]) {
8c1fdf04 240 td->o.td_ddir = TD_DDIR_WRITE;
d84f8d49
JA
241 td->o.max_bs[DDIR_WRITE] = rw_bs[DDIR_WRITE];
242 } else {
8c1fdf04 243 td->o.td_ddir = TD_DDIR_RW;
d84f8d49
JA
244 td->o.max_bs[DDIR_READ] = rw_bs[DDIR_READ];
245 td->o.max_bs[DDIR_WRITE] = rw_bs[DDIR_WRITE];
246 }
8c1fdf04
JA
247
248 /*
249 * We need to do direct/raw ios to the device, to avoid getting
250 * read-ahead in our way.
251 */
252 td->o.odirect = 1;
253
fb7b71a3 254 return 0;
8c1fdf04
JA
255err:
256 close(fd);
38470f85 257 fifo_free(fifo);
8c1fdf04 258 return 1;
fb7b71a3 259}