e788af5ba5d91e0fe203144c2e8f2f3765b86850
[fio.git] / helper_thread.c
1 #include "fio.h"
2 #include "smalloc.h"
3 #include "helper_thread.h"
4
5 static struct helper_data {
6         volatile int exit;
7         volatile int reset;
8         volatile int do_stat;
9         struct sk_out *sk_out;
10         pthread_t thread;
11         pthread_mutex_t lock;
12         pthread_cond_t cond;
13         struct fio_mutex *startup_mutex;
14 } *helper_data;
15
16 void helper_thread_destroy(void)
17 {
18         pthread_cond_destroy(&helper_data->cond);
19         pthread_mutex_destroy(&helper_data->lock);
20         sfree(helper_data);
21 }
22
23 void helper_reset(void)
24 {
25         if (!helper_data)
26                 return;
27
28         pthread_mutex_lock(&helper_data->lock);
29
30         if (!helper_data->reset) {
31                 helper_data->reset = 1;
32                 pthread_cond_signal(&helper_data->cond);
33         }
34
35         pthread_mutex_unlock(&helper_data->lock);
36 }
37
38 void helper_do_stat(void)
39 {
40         if (!helper_data)
41                 return;
42
43         pthread_mutex_lock(&helper_data->lock);
44         helper_data->do_stat = 1;
45         pthread_cond_signal(&helper_data->cond);
46         pthread_mutex_unlock(&helper_data->lock);
47 }
48
49 bool helper_should_exit(void)
50 {
51         if (!helper_data)
52                 return true;
53
54         return helper_data->exit;
55 }
56
57 void helper_thread_exit(void)
58 {
59         void *ret;
60
61         pthread_mutex_lock(&helper_data->lock);
62         helper_data->exit = 1;
63         pthread_cond_signal(&helper_data->cond);
64         pthread_mutex_unlock(&helper_data->lock);
65
66         pthread_join(helper_data->thread, &ret);
67 }
68
69 static void *helper_thread_main(void *data)
70 {
71         struct helper_data *hd = data;
72         unsigned int msec_to_next_event, next_log;
73         struct timeval tv, last_du;
74         int ret = 0;
75
76         sk_out_assign(hd->sk_out);
77
78         gettimeofday(&tv, NULL);
79         memcpy(&last_du, &tv, sizeof(tv));
80
81         fio_mutex_up(hd->startup_mutex);
82
83         msec_to_next_event = DISK_UTIL_MSEC;
84         while (!ret && !hd->exit) {
85                 struct timespec ts;
86                 struct timeval now;
87                 uint64_t since_du;
88
89                 timeval_add_msec(&tv, msec_to_next_event);
90                 ts.tv_sec = tv.tv_sec;
91                 ts.tv_nsec = tv.tv_usec * 1000;
92
93                 pthread_mutex_lock(&hd->lock);
94                 pthread_cond_timedwait(&hd->cond, &hd->lock, &ts);
95
96                 gettimeofday(&now, NULL);
97
98                 if (hd->reset) {
99                         memcpy(&tv, &now, sizeof(tv));
100                         memcpy(&last_du, &now, sizeof(last_du));
101                         hd->reset = 0;
102                 }
103
104                 pthread_mutex_unlock(&hd->lock);
105
106                 since_du = mtime_since(&last_du, &now);
107                 if (since_du >= DISK_UTIL_MSEC || DISK_UTIL_MSEC - since_du < 10) {
108                         ret = update_io_ticks();
109                         timeval_add_msec(&last_du, DISK_UTIL_MSEC);
110                         msec_to_next_event = DISK_UTIL_MSEC;
111                         if (since_du >= DISK_UTIL_MSEC)
112                                 msec_to_next_event -= (since_du - DISK_UTIL_MSEC);
113                 } else {
114                         if (since_du >= DISK_UTIL_MSEC)
115                                 msec_to_next_event = DISK_UTIL_MSEC - (DISK_UTIL_MSEC - since_du);
116                         else
117                                 msec_to_next_event = DISK_UTIL_MSEC;
118                 }
119
120                 if (hd->do_stat) {
121                         hd->do_stat = 0;
122                         __show_running_run_stats();
123                 }
124
125                 next_log = calc_log_samples();
126                 if (!next_log)
127                         next_log = DISK_UTIL_MSEC;
128
129                 msec_to_next_event = min(next_log, msec_to_next_event);
130
131                 if (!is_backend)
132                         print_thread_status();
133         }
134
135         fio_writeout_logs(false);
136
137         sk_out_drop();
138         return NULL;
139 }
140
141 int helper_thread_create(struct fio_mutex *startup_mutex, struct sk_out *sk_out)
142 {
143         struct helper_data *hd;
144         int ret;
145
146         hd = smalloc(sizeof(*hd));
147
148         setup_disk_util();
149
150         hd->sk_out = sk_out;
151
152         ret = mutex_cond_init_pshared(&hd->lock, &hd->cond);
153         if (ret)
154                 return 1;
155
156         hd->startup_mutex = startup_mutex;
157
158         ret = pthread_create(&hd->thread, NULL, helper_thread_main, hd);
159         if (ret) {
160                 log_err("Can't create helper thread: %s\n", strerror(ret));
161                 return 1;
162         }
163
164         helper_data = hd;
165
166         dprint(FD_MUTEX, "wait on startup_mutex\n");
167         fio_mutex_down(startup_mutex);
168         dprint(FD_MUTEX, "done waiting on startup_mutex\n");
169         return 0;
170 }