[PATCH] Split status/eta code out of fio.c
[fio.git] / eta.c
CommitLineData
263e529f
JA
1/*
2 * Status and ETA code
3 */
4#include <unistd.h>
5#include <fcntl.h>
6#include <string.h>
7
8#include "fio.h"
9#include "os.h"
10
11static char run_str[MAX_JOBS + 1];
12
13/*
14 * Sets the status of the 'td' in the printed status map.
15 */
16static void check_str_update(struct thread_data *td)
17{
18 char c = run_str[td->thread_number - 1];
19
20 switch (td->runstate) {
21 case TD_REAPED:
22 c = '_';
23 break;
24 case TD_EXITED:
25 c = 'E';
26 break;
27 case TD_RUNNING:
28 if (td_rw(td)) {
29 if (td->sequential)
30 c = 'M';
31 else
32 c = 'm';
33 } else if (td_read(td)) {
34 if (td->sequential)
35 c = 'R';
36 else
37 c = 'r';
38 } else {
39 if (td->sequential)
40 c = 'W';
41 else
42 c = 'w';
43 }
44 break;
45 case TD_VERIFYING:
46 c = 'V';
47 break;
48 case TD_FSYNCING:
49 c = 'F';
50 break;
51 case TD_CREATED:
52 c = 'C';
53 break;
54 case TD_INITIALIZED:
55 c = 'I';
56 break;
57 case TD_NOT_CREATED:
58 c = 'P';
59 break;
60 default:
61 log_err("state %d\n", td->runstate);
62 }
63
64 run_str[td->thread_number - 1] = c;
65}
66
67/*
68 * Convert seconds to a printable string.
69 */
70static void eta_to_str(char *str, int eta_sec)
71{
72 unsigned int d, h, m, s;
73 static int always_d, always_h;
74
75 d = h = m = s = 0;
76
77 s = eta_sec % 60;
78 eta_sec /= 60;
79 m = eta_sec % 60;
80 eta_sec /= 60;
81 h = eta_sec % 24;
82 eta_sec /= 24;
83 d = eta_sec;
84
85 if (d || always_d) {
86 always_d = 1;
87 str += sprintf(str, "%02dd:", d);
88 }
89 if (h || always_h) {
90 always_h = 1;
91 str += sprintf(str, "%02dh:", h);
92 }
93
94 str += sprintf(str, "%02dm:", m);
95 str += sprintf(str, "%02ds", s);
96}
97
98/*
99 * Best effort calculation of the estimated pending runtime of a job.
100 */
101static int thread_eta(struct thread_data *td, unsigned long elapsed)
102{
103 unsigned long long bytes_total, bytes_done;
104 unsigned int eta_sec = 0;
105
106 bytes_total = td->total_io_size;
107
108 if (td->zone_size && td->zone_skip)
109 bytes_total /= (td->zone_skip / td->zone_size);
110
111 if (td->runstate == TD_RUNNING || td->runstate == TD_VERIFYING) {
112 double perc;
113
114 bytes_done = td->io_bytes[DDIR_READ] + td->io_bytes[DDIR_WRITE];
115 perc = (double) bytes_done / (double) bytes_total;
116 if (perc > 1.0)
117 perc = 1.0;
118
119 eta_sec = (elapsed * (1.0 / perc)) - elapsed;
120
121 if (td->timeout && eta_sec > (td->timeout - elapsed))
122 eta_sec = td->timeout - elapsed;
123 } else if (td->runstate == TD_NOT_CREATED || td->runstate == TD_CREATED
124 || td->runstate == TD_INITIALIZED) {
125 int t_eta = 0, r_eta = 0;
126
127 /*
128 * We can only guess - assume it'll run the full timeout
129 * if given, otherwise assume it'll run at the specified rate.
130 */
131 if (td->timeout)
132 t_eta = td->timeout + td->start_delay - elapsed;
133 if (td->rate) {
134 r_eta = (bytes_total / 1024) / td->rate;
135 r_eta += td->start_delay - elapsed;
136 }
137
138 if (r_eta && t_eta)
139 eta_sec = min(r_eta, t_eta);
140 else if (r_eta)
141 eta_sec = r_eta;
142 else if (t_eta)
143 eta_sec = t_eta;
144 else
145 eta_sec = 0;
146 } else {
147 /*
148 * thread is already done or waiting for fsync
149 */
150 eta_sec = 0;
151 }
152
153 return eta_sec;
154}
155
156/*
157 * Print status of the jobs we know about. This includes rate estimates,
158 * ETA, thread state, etc.
159 */
160void print_thread_status(void)
161{
162 unsigned long elapsed = mtime_since_genesis() / 1000;
163 int i, nr_running, nr_pending, t_rate, m_rate, *eta_secs, eta_sec;
164 char eta_str[32];
165 double perc = 0.0;
166
167 if (temp_stall_ts || terse_output)
168 return;
169
170 eta_secs = malloc(thread_number * sizeof(int));
171 memset(eta_secs, 0, thread_number * sizeof(int));
172
173 nr_pending = nr_running = t_rate = m_rate = 0;
174 for (i = 0; i < thread_number; i++) {
175 struct thread_data *td = &threads[i];
176
177 if (td->runstate == TD_RUNNING || td->runstate == TD_VERIFYING||
178 td->runstate == TD_FSYNCING) {
179 nr_running++;
180 t_rate += td->rate;
181 m_rate += td->ratemin;
182 } else if (td->runstate < TD_RUNNING)
183 nr_pending++;
184
185 if (elapsed >= 3)
186 eta_secs[i] = thread_eta(td, elapsed);
187 else
188 eta_secs[i] = INT_MAX;
189
190 check_str_update(td);
191 }
192
193 if (exitall_on_terminate)
194 eta_sec = INT_MAX;
195 else
196 eta_sec = 0;
197
198 for (i = 0; i < thread_number; i++) {
199 if (exitall_on_terminate) {
200 if (eta_secs[i] < eta_sec)
201 eta_sec = eta_secs[i];
202 } else {
203 if (eta_secs[i] > eta_sec)
204 eta_sec = eta_secs[i];
205 }
206 }
207
208 if (eta_sec != INT_MAX && elapsed) {
209 perc = (double) elapsed / (double) (elapsed + eta_sec);
210 eta_to_str(eta_str, eta_sec);
211 }
212
213 if (!nr_running && !nr_pending)
214 return;
215
216 printf("Threads running: %d", nr_running);
217 if (m_rate || t_rate)
218 printf(", commitrate %d/%dKiB/sec", t_rate, m_rate);
219 if (eta_sec != INT_MAX && nr_running) {
220 perc *= 100.0;
221 printf(": [%s] [%3.2f%% done] [eta %s]", run_str, perc,eta_str);
222 }
223 printf("\r");
224 fflush(stdout);
225 free(eta_secs);
226}
227
228void print_status_init(int thread_number)
229{
230 run_str[thread_number] = 'P';
231}