2b90f452e8c22bca740b235ebb26094a12892574
[fio.git] / log.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "list.h"
4 #include "fio.h"
5
6 void write_iolog_put(struct thread_data *td, struct io_u *io_u)
7 {
8         fprintf(td->iolog_f, "%u,%llu,%lu\n", io_u->ddir, io_u->offset, io_u->buflen);
9 }
10
11 int read_iolog_get(struct thread_data *td, struct io_u *io_u)
12 {
13         struct io_piece *ipo;
14
15         if (!list_empty(&td->io_log_list)) {
16                 ipo = list_entry(td->io_log_list.next, struct io_piece, list);
17                 list_del(&ipo->list);
18                 io_u->offset = ipo->offset;
19                 io_u->buflen = ipo->len;
20                 io_u->ddir = ipo->ddir;
21                 io_u->file = ipo->file;
22                 free(ipo);
23                 return 0;
24         }
25
26         return 1;
27 }
28
29 void prune_io_piece_log(struct thread_data *td)
30 {
31         struct io_piece *ipo;
32         struct rb_node *n;
33
34         while ((n = rb_first(&td->io_hist_tree)) != NULL) {
35                 ipo = rb_entry(n, struct io_piece, rb_node);
36                 rb_erase(n, &td->io_hist_tree);
37                 free(ipo);
38         }
39 }
40
41 /*
42  * log a successful write, so we can unwind the log for verify
43  */
44 void log_io_piece(struct thread_data *td, struct io_u *io_u)
45 {
46         struct rb_node **p = &td->io_hist_tree.rb_node;
47         struct rb_node *parent = NULL;
48         struct io_piece *ipo, *__ipo;
49
50         ipo = malloc(sizeof(struct io_piece));
51         memset(&ipo->rb_node, 0, sizeof(ipo->rb_node));
52         ipo->file = io_u->file;
53         ipo->offset = io_u->offset;
54         ipo->len = io_u->buflen;
55
56         /*
57          * Sort the entry into the verification list
58          */
59         while (*p) {
60                 parent = *p;
61
62                 __ipo = rb_entry(parent, struct io_piece, rb_node);
63                 if (ipo->offset < __ipo->offset)
64                         p = &(*p)->rb_left;
65                 else if (ipo->offset > __ipo->offset)
66                         p = &(*p)->rb_right;
67                 else
68                         break;
69         }
70
71         rb_link_node(&ipo->rb_node, parent, p);
72         rb_insert_color(&ipo->rb_node, &td->io_hist_tree);
73 }
74
75 void write_iolog_close(struct thread_data *td)
76 {
77         fflush(td->iolog_f);
78         fclose(td->iolog_f);
79         free(td->iolog_buf);
80 }
81
82 /*
83  * Open a stored log and read in the entries.
84  */
85 static int init_iolog_read(struct thread_data *td)
86 {
87         unsigned long long offset;
88         unsigned int bytes;
89         char *str, *p;
90         FILE *f;
91         int rw, reads, writes;
92
93         f = fopen(td->o.read_iolog_file, "r");
94         if (!f) {
95                 perror("fopen read iolog");
96                 return 1;
97         }
98
99         /*
100          * Read in the read iolog and store it, reuse the infrastructure
101          * for doing verifications.
102          */
103         str = malloc(4096);
104         reads = writes = 0;
105         while ((p = fgets(str, 4096, f)) != NULL) {
106                 struct io_piece *ipo;
107
108                 if (sscanf(p, "%d,%llu,%u", &rw, &offset, &bytes) != 3) {
109                         log_err("bad iolog: %s\n", p);
110                         continue;
111                 }
112                 if (rw == DDIR_READ)
113                         reads++;
114                 else if (rw == DDIR_WRITE)
115                         writes++;
116                 else {
117                         log_err("bad ddir: %d\n", rw);
118                         continue;
119                 }
120
121                 ipo = malloc(sizeof(*ipo));
122                 INIT_LIST_HEAD(&ipo->list);
123                 ipo->offset = offset;
124                 ipo->len = bytes;
125                 ipo->ddir = (enum fio_ddir) rw;
126                 if (bytes > td->o.max_bs[rw])
127                         td->o.max_bs[rw] = bytes;
128                 list_add_tail(&ipo->list, &td->io_log_list);
129         }
130
131         free(str);
132         fclose(f);
133
134         if (!reads && !writes)
135                 return 1;
136         else if (reads && !writes)
137                 td->o.td_ddir = TD_DDIR_READ;
138         else if (!reads && writes)
139                 td->o.td_ddir = TD_DDIR_READ;
140         else
141                 td->o.td_ddir = TD_DDIR_RW;
142
143         return 0;
144 }
145
146 /*
147  * Setup a log for storing io patterns.
148  */
149 static int init_iolog_write(struct thread_data *td)
150 {
151         FILE *f;
152
153         f = fopen(td->o.write_iolog_file, "w+");
154         if (!f) {
155                 perror("fopen write iolog");
156                 return 1;
157         }
158
159         /*
160          * That's it for writing, setup a log buffer and we're done.
161           */
162         td->iolog_f = f;
163         td->iolog_buf = malloc(8192);
164         setvbuf(f, td->iolog_buf, _IOFBF, 8192);
165         return 0;
166 }
167
168 int init_iolog(struct thread_data *td)
169 {
170         int ret = 0;
171
172         if (td->io_ops->flags & FIO_DISKLESSIO)
173                 return 0;
174
175         if (td->o.read_iolog_file)
176                 ret = init_iolog_read(td);
177         else if (td->o.write_iolog_file)
178                 ret = init_iolog_write(td);
179
180         return ret;
181 }
182
183 void setup_log(struct io_log **log)
184 {
185         struct io_log *l = malloc(sizeof(*l));
186
187         l->nr_samples = 0;
188         l->max_samples = 1024;
189         l->log = malloc(l->max_samples * sizeof(struct io_sample));
190         *log = l;
191 }
192
193 void __finish_log(struct io_log *log, const char *name)
194 {
195         unsigned int i;
196         FILE *f;
197
198         f = fopen(name, "w");
199         if (!f) {
200                 perror("fopen log");
201                 return;
202         }
203
204         for (i = 0; i < log->nr_samples; i++)
205                 fprintf(f, "%lu, %lu, %u\n", log->log[i].time, log->log[i].val, log->log[i].ddir);
206
207         fclose(f);
208         free(log->log);
209         free(log);
210 }
211
212 void finish_log(struct thread_data *td, struct io_log *log, const char *name)
213 {
214         char file_name[256];
215
216         snprintf(file_name, 200, "client%d_%s.log", td->thread_number, name);
217         __finish_log(log, file_name);
218 }