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