Avoid using the rbtree if we don't have to
[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, *parent;
47         struct io_piece *ipo, *__ipo;
48
49         ipo = malloc(sizeof(struct io_piece));
50         ipo->file = io_u->file;
51         ipo->offset = io_u->offset;
52         ipo->len = io_u->buflen;
53
54         /*
55          * We don't need to sort the entries, if:
56          *
57          *      Sequential writes, or
58          *      Random writes that lay out the file as it goes along
59          *
60          * For both these cases, just reading back data in the order we
61          * wrote it out is the fastest.
62          */
63         if (!td_random(td) || !td->o.overwrite) {
64                 INIT_LIST_HEAD(&ipo->list);
65                 list_add_tail(&ipo->list, &td->io_hist_list);
66                 return;
67         }
68
69         RB_CLEAR_NODE(&ipo->rb_node);
70         p = &td->io_hist_tree.rb_node;
71         parent = NULL;
72
73         /*
74          * Sort the entry into the verification list
75          */
76         while (*p) {
77                 parent = *p;
78
79                 __ipo = rb_entry(parent, struct io_piece, rb_node);
80                 if (ipo->offset <= __ipo->offset)
81                         p = &(*p)->rb_left;
82                 else
83                         p = &(*p)->rb_right;
84         }
85
86         rb_link_node(&ipo->rb_node, parent, p);
87         rb_insert_color(&ipo->rb_node, &td->io_hist_tree);
88 }
89
90 void write_iolog_close(struct thread_data *td)
91 {
92         fflush(td->iolog_f);
93         fclose(td->iolog_f);
94         free(td->iolog_buf);
95 }
96
97 /*
98  * Open a stored log and read in the entries.
99  */
100 static int init_iolog_read(struct thread_data *td)
101 {
102         unsigned long long offset;
103         unsigned int bytes;
104         char *str, *p;
105         FILE *f;
106         int rw, reads, writes;
107
108         f = fopen(td->o.read_iolog_file, "r");
109         if (!f) {
110                 perror("fopen read iolog");
111                 return 1;
112         }
113
114         /*
115          * Read in the read iolog and store it, reuse the infrastructure
116          * for doing verifications.
117          */
118         str = malloc(4096);
119         reads = writes = 0;
120         while ((p = fgets(str, 4096, f)) != NULL) {
121                 struct io_piece *ipo;
122
123                 if (sscanf(p, "%d,%llu,%u", &rw, &offset, &bytes) != 3) {
124                         log_err("bad iolog: %s\n", p);
125                         continue;
126                 }
127                 if (rw == DDIR_READ)
128                         reads++;
129                 else if (rw == DDIR_WRITE)
130                         writes++;
131                 else if (rw != DDIR_SYNC) {
132                         log_err("bad ddir: %d\n", rw);
133                         continue;
134                 }
135
136                 ipo = malloc(sizeof(*ipo));
137                 INIT_LIST_HEAD(&ipo->list);
138                 ipo->offset = offset;
139                 ipo->len = bytes;
140                 ipo->ddir = (enum fio_ddir) rw;
141                 if (bytes > td->o.max_bs[rw])
142                         td->o.max_bs[rw] = bytes;
143                 list_add_tail(&ipo->list, &td->io_log_list);
144         }
145
146         free(str);
147         fclose(f);
148
149         if (!reads && !writes)
150                 return 1;
151         else if (reads && !writes)
152                 td->o.td_ddir = TD_DDIR_READ;
153         else if (!reads && writes)
154                 td->o.td_ddir = TD_DDIR_READ;
155         else
156                 td->o.td_ddir = TD_DDIR_RW;
157
158         return 0;
159 }
160
161 /*
162  * Setup a log for storing io patterns.
163  */
164 static int init_iolog_write(struct thread_data *td)
165 {
166         FILE *f;
167
168         f = fopen(td->o.write_iolog_file, "w+");
169         if (!f) {
170                 perror("fopen write iolog");
171                 return 1;
172         }
173
174         /*
175          * That's it for writing, setup a log buffer and we're done.
176           */
177         td->iolog_f = f;
178         td->iolog_buf = malloc(8192);
179         setvbuf(f, td->iolog_buf, _IOFBF, 8192);
180         return 0;
181 }
182
183 int init_iolog(struct thread_data *td)
184 {
185         int ret = 0;
186
187         if (td->io_ops->flags & FIO_DISKLESSIO)
188                 return 0;
189
190         if (td->o.read_iolog_file)
191                 ret = init_iolog_read(td);
192         else if (td->o.write_iolog_file)
193                 ret = init_iolog_write(td);
194
195         return ret;
196 }
197
198 void setup_log(struct io_log **log)
199 {
200         struct io_log *l = malloc(sizeof(*l));
201
202         l->nr_samples = 0;
203         l->max_samples = 1024;
204         l->log = malloc(l->max_samples * sizeof(struct io_sample));
205         *log = l;
206 }
207
208 void __finish_log(struct io_log *log, const char *name)
209 {
210         unsigned int i;
211         FILE *f;
212
213         f = fopen(name, "w");
214         if (!f) {
215                 perror("fopen log");
216                 return;
217         }
218
219         for (i = 0; i < log->nr_samples; i++)
220                 fprintf(f, "%lu, %lu, %u\n", log->log[i].time, log->log[i].val, log->log[i].ddir);
221
222         fclose(f);
223         free(log->log);
224         free(log);
225 }
226
227 void finish_log(struct thread_data *td, struct io_log *log, const char *name)
228 {
229         char file_name[256];
230
231         snprintf(file_name, 200, "client%d_%s.log", td->thread_number, name);
232         __finish_log(log, file_name);
233 }