Commit | Line | Data |
---|---|---|
4f37732a BVA |
1 | #ifdef CONFIG_VALGRIND_DEV |
2 | #include <valgrind/drd.h> | |
3 | #else | |
4 | #define DRD_IGNORE_VAR(x) do { } while (0) | |
5 | #endif | |
6 | ||
a39fb9ea JA |
7 | #include "fio.h" |
8 | #include "smalloc.h" | |
9 | #include "helper_thread.h" | |
16e56d25 | 10 | #include "steadystate.h" |
ae626d4e | 11 | #include "pshared.h" |
a39fb9ea | 12 | |
31eca641 BVA |
13 | enum action { |
14 | A_EXIT = 1, | |
15 | A_RESET = 2, | |
16 | A_DO_STAT = 3, | |
17 | }; | |
18 | ||
a39fb9ea JA |
19 | static struct helper_data { |
20 | volatile int exit; | |
31eca641 | 21 | int pipe[2]; /* 0: read end; 1: write end. */ |
a39fb9ea JA |
22 | struct sk_out *sk_out; |
23 | pthread_t thread; | |
971caeb1 | 24 | struct fio_sem *startup_sem; |
a39fb9ea JA |
25 | } *helper_data; |
26 | ||
27 | void helper_thread_destroy(void) | |
28 | { | |
31eca641 BVA |
29 | close(helper_data->pipe[0]); |
30 | close(helper_data->pipe[1]); | |
a39fb9ea JA |
31 | sfree(helper_data); |
32 | } | |
33 | ||
31eca641 | 34 | static void submit_action(enum action a) |
a39fb9ea | 35 | { |
31eca641 BVA |
36 | const uint8_t data = a; |
37 | int ret; | |
38 | ||
a39fb9ea JA |
39 | if (!helper_data) |
40 | return; | |
41 | ||
31eca641 BVA |
42 | ret = write(helper_data->pipe[1], &data, sizeof(data)); |
43 | assert(ret == 1); | |
44 | } | |
a39fb9ea | 45 | |
31eca641 BVA |
46 | void helper_reset(void) |
47 | { | |
48 | submit_action(A_RESET); | |
a39fb9ea JA |
49 | } |
50 | ||
31eca641 BVA |
51 | /* |
52 | * May be invoked in signal handler context and hence must only call functions | |
53 | * that are async-signal-safe. See also | |
54 | * https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03. | |
55 | */ | |
a39fb9ea JA |
56 | void helper_do_stat(void) |
57 | { | |
31eca641 | 58 | submit_action(A_DO_STAT); |
a39fb9ea JA |
59 | } |
60 | ||
61 | bool helper_should_exit(void) | |
62 | { | |
63 | if (!helper_data) | |
64 | return true; | |
65 | ||
66 | return helper_data->exit; | |
67 | } | |
68 | ||
69 | void helper_thread_exit(void) | |
70 | { | |
a39fb9ea | 71 | helper_data->exit = 1; |
31eca641 BVA |
72 | submit_action(A_EXIT); |
73 | pthread_join(helper_data->thread, NULL); | |
a39fb9ea JA |
74 | } |
75 | ||
76 | static void *helper_thread_main(void *data) | |
77 | { | |
78 | struct helper_data *hd = data; | |
16e56d25 | 79 | unsigned int msec_to_next_event, next_log, next_ss = STEADYSTATE_MSEC; |
8b6a404c | 80 | struct timespec ts, last_du, last_ss; |
31eca641 | 81 | uint8_t action; |
a39fb9ea JA |
82 | int ret = 0; |
83 | ||
84 | sk_out_assign(hd->sk_out); | |
85 | ||
78b66d32 BVA |
86 | #ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK |
87 | clock_gettime(CLOCK_MONOTONIC, &ts); | |
88 | #else | |
89 | clock_gettime(CLOCK_REALTIME, &ts); | |
90 | #endif | |
8b6a404c VF |
91 | memcpy(&last_du, &ts, sizeof(ts)); |
92 | memcpy(&last_ss, &ts, sizeof(ts)); | |
a39fb9ea | 93 | |
971caeb1 | 94 | fio_sem_up(hd->startup_sem); |
a39fb9ea JA |
95 | |
96 | msec_to_next_event = DISK_UTIL_MSEC; | |
97 | while (!ret && !hd->exit) { | |
16e56d25 | 98 | uint64_t since_du, since_ss = 0; |
31eca641 BVA |
99 | struct timeval timeout = { |
100 | .tv_sec = DISK_UTIL_MSEC / 1000, | |
101 | .tv_usec = (DISK_UTIL_MSEC % 1000) * 1000, | |
102 | }; | |
103 | fd_set rfds, efds; | |
a39fb9ea | 104 | |
8b6a404c | 105 | timespec_add_msec(&ts, msec_to_next_event); |
a39fb9ea | 106 | |
31eca641 BVA |
107 | if (read(hd->pipe[0], &action, sizeof(action)) < 0) { |
108 | FD_ZERO(&rfds); | |
109 | FD_SET(hd->pipe[0], &rfds); | |
110 | FD_ZERO(&efds); | |
111 | FD_SET(hd->pipe[0], &efds); | |
112 | select(1, &rfds, NULL, &efds, &timeout); | |
113 | if (read(hd->pipe[0], &action, sizeof(action)) < 0) | |
114 | action = 0; | |
115 | } | |
a39fb9ea | 116 | |
78b66d32 BVA |
117 | #ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK |
118 | clock_gettime(CLOCK_MONOTONIC, &ts); | |
119 | #else | |
120 | clock_gettime(CLOCK_REALTIME, &ts); | |
121 | #endif | |
a39fb9ea | 122 | |
31eca641 BVA |
123 | if (action == A_RESET) { |
124 | last_du = ts; | |
125 | last_ss = ts; | |
a39fb9ea JA |
126 | } |
127 | ||
8b6a404c | 128 | since_du = mtime_since(&last_du, &ts); |
a39fb9ea JA |
129 | if (since_du >= DISK_UTIL_MSEC || DISK_UTIL_MSEC - since_du < 10) { |
130 | ret = update_io_ticks(); | |
8b6a404c | 131 | timespec_add_msec(&last_du, DISK_UTIL_MSEC); |
a39fb9ea JA |
132 | msec_to_next_event = DISK_UTIL_MSEC; |
133 | if (since_du >= DISK_UTIL_MSEC) | |
134 | msec_to_next_event -= (since_du - DISK_UTIL_MSEC); | |
dd290fb4 VF |
135 | } else |
136 | msec_to_next_event = DISK_UTIL_MSEC - since_du; | |
a39fb9ea | 137 | |
31eca641 | 138 | if (action == A_DO_STAT) |
a39fb9ea | 139 | __show_running_run_stats(); |
a39fb9ea JA |
140 | |
141 | next_log = calc_log_samples(); | |
142 | if (!next_log) | |
143 | next_log = DISK_UTIL_MSEC; | |
144 | ||
84784e07 | 145 | if (steadystate_enabled) { |
8b6a404c | 146 | since_ss = mtime_since(&last_ss, &ts); |
16e56d25 VF |
147 | if (since_ss >= STEADYSTATE_MSEC || STEADYSTATE_MSEC - since_ss < 10) { |
148 | steadystate_check(); | |
8b6a404c | 149 | timespec_add_msec(&last_ss, since_ss); |
16e56d25 VF |
150 | if (since_ss > STEADYSTATE_MSEC) |
151 | next_ss = STEADYSTATE_MSEC - (since_ss - STEADYSTATE_MSEC); | |
152 | else | |
153 | next_ss = STEADYSTATE_MSEC; | |
c27cc65f | 154 | } else |
16e56d25 VF |
155 | next_ss = STEADYSTATE_MSEC - since_ss; |
156 | } | |
157 | ||
158 | msec_to_next_event = min(min(next_log, msec_to_next_event), next_ss); | |
e569ca6b | 159 | dprint(FD_HELPERTHREAD, "since_ss: %llu, next_ss: %u, next_log: %u, msec_to_next_event: %u\n", (unsigned long long)since_ss, next_ss, next_log, msec_to_next_event); |
a39fb9ea JA |
160 | |
161 | if (!is_backend) | |
162 | print_thread_status(); | |
163 | } | |
164 | ||
165 | fio_writeout_logs(false); | |
166 | ||
167 | sk_out_drop(); | |
168 | return NULL; | |
169 | } | |
170 | ||
971caeb1 | 171 | int helper_thread_create(struct fio_sem *startup_sem, struct sk_out *sk_out) |
a39fb9ea JA |
172 | { |
173 | struct helper_data *hd; | |
174 | int ret; | |
175 | ||
b3090ff4 | 176 | hd = scalloc(1, sizeof(*hd)); |
a39fb9ea JA |
177 | |
178 | setup_disk_util(); | |
16e56d25 | 179 | steadystate_setup(); |
a39fb9ea JA |
180 | |
181 | hd->sk_out = sk_out; | |
34febb23 | 182 | |
31eca641 BVA |
183 | #ifdef __linux__ |
184 | ret = pipe2(hd->pipe, O_CLOEXEC); | |
185 | #else | |
186 | ret = pipe(hd->pipe); | |
187 | #endif | |
34febb23 | 188 | if (ret) |
f9e5b5ee | 189 | return 1; |
34febb23 | 190 | |
31eca641 BVA |
191 | ret = fcntl(hd->pipe[0], F_SETFL, O_NONBLOCK); |
192 | assert(ret >= 0); | |
193 | ||
971caeb1 | 194 | hd->startup_sem = startup_sem; |
a39fb9ea | 195 | |
4f37732a BVA |
196 | DRD_IGNORE_VAR(helper_data); |
197 | ||
a39fb9ea JA |
198 | ret = pthread_create(&hd->thread, NULL, helper_thread_main, hd); |
199 | if (ret) { | |
200 | log_err("Can't create helper thread: %s\n", strerror(ret)); | |
201 | return 1; | |
202 | } | |
203 | ||
204 | helper_data = hd; | |
205 | ||
971caeb1 BVA |
206 | dprint(FD_MUTEX, "wait on startup_sem\n"); |
207 | fio_sem_down(startup_sem); | |
208 | dprint(FD_MUTEX, "done waiting on startup_sem\n"); | |
a39fb9ea JA |
209 | return 0; |
210 | } |