Home | History | Annotate | Download | only in fio
      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