Home | History | Annotate | Download | only in fio
      1 /*
      2  * fio - the flexible io tester
      3  *
      4  * Copyright (C) 2005 Jens Axboe <axboe (at) suse.de>
      5  * Copyright (C) 2006-2012 Jens Axboe <axboe (at) kernel.dk>
      6  *
      7  * The license below covers all files distributed with fio unless otherwise
      8  * noted in the file itself.
      9  *
     10  *  This program is free software; you can redistribute it and/or modify
     11  *  it under the terms of the GNU General Public License version 2 as
     12  *  published by the Free Software Foundation.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     22  *
     23  */
     24 
     25 #include <string.h>
     26 #include <sys/types.h>
     27 #include <signal.h>
     28 #include <stdint.h>
     29 #include <locale.h>
     30 #include <fcntl.h>
     31 
     32 #include "fio.h"
     33 #include "smalloc.h"
     34 #include "os/os.h"
     35 #include "filelock.h"
     36 
     37 /*
     38  * Just expose an empty list, if the OS does not support disk util stats
     39  */
     40 #ifndef FIO_HAVE_DISK_UTIL
     41 FLIST_HEAD(disk_list);
     42 #endif
     43 
     44 unsigned long arch_flags = 0;
     45 
     46 uintptr_t page_mask = 0;
     47 uintptr_t page_size = 0;
     48 
     49 static const char *fio_os_strings[os_nr] = {
     50 	"Invalid",
     51 	"Linux",
     52 	"AIX",
     53 	"FreeBSD",
     54 	"HP-UX",
     55 	"OSX",
     56 	"NetBSD",
     57 	"OpenBSD",
     58 	"Solaris",
     59 	"Windows",
     60 	"Android",
     61 	"DragonFly",
     62 };
     63 
     64 static const char *fio_arch_strings[arch_nr] = {
     65 	"Invalid",
     66 	"x86-64",
     67 	"x86",
     68 	"ppc",
     69 	"ia64",
     70 	"s390",
     71 	"alpha",
     72 	"sparc",
     73 	"sparc64",
     74 	"arm",
     75 	"sh",
     76 	"hppa",
     77 	"generic"
     78 };
     79 
     80 static void reset_io_counters(struct thread_data *td)
     81 {
     82 	int ddir;
     83 
     84 	for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
     85 		td->stat_io_bytes[ddir] = 0;
     86 		td->this_io_bytes[ddir] = 0;
     87 		td->stat_io_blocks[ddir] = 0;
     88 		td->this_io_blocks[ddir] = 0;
     89 		td->rate_bytes[ddir] = 0;
     90 		td->rate_blocks[ddir] = 0;
     91 	}
     92 	td->zone_bytes = 0;
     93 
     94 	td->last_was_sync = 0;
     95 	td->rwmix_issues = 0;
     96 
     97 	/*
     98 	 * reset file done count if we are to start over
     99 	 */
    100 	if (td->o.time_based || td->o.loops || td->o.do_verify)
    101 		td->nr_done_files = 0;
    102 }
    103 
    104 void clear_io_state(struct thread_data *td)
    105 {
    106 	struct fio_file *f;
    107 	unsigned int i;
    108 
    109 	reset_io_counters(td);
    110 
    111 	close_files(td);
    112 	for_each_file(td, f, i) {
    113 		fio_file_clear_done(f);
    114 		f->file_offset = get_start_offset(td, f);
    115 	}
    116 
    117 	/*
    118 	 * Set the same seed to get repeatable runs
    119 	 */
    120 	td_fill_rand_seeds(td);
    121 }
    122 
    123 void reset_all_stats(struct thread_data *td)
    124 {
    125 	struct timeval tv;
    126 	int i;
    127 
    128 	reset_io_counters(td);
    129 
    130 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
    131 		td->io_bytes[i] = 0;
    132 		td->io_blocks[i] = 0;
    133 		td->io_issues[i] = 0;
    134 		td->ts.total_io_u[i] = 0;
    135 		td->ts.runtime[i] = 0;
    136 		td->rwmix_issues = 0;
    137 	}
    138 
    139 	fio_gettime(&tv, NULL);
    140 	memcpy(&td->epoch, &tv, sizeof(tv));
    141 	memcpy(&td->start, &tv, sizeof(tv));
    142 
    143 	lat_target_reset(td);
    144 }
    145 
    146 void reset_fio_state(void)
    147 {
    148 	groupid = 0;
    149 	thread_number = 0;
    150 	stat_number = 0;
    151 	done_secs = 0;
    152 }
    153 
    154 const char *fio_get_os_string(int nr)
    155 {
    156 	if (nr < os_nr)
    157 		return fio_os_strings[nr];
    158 
    159 	return NULL;
    160 }
    161 
    162 const char *fio_get_arch_string(int nr)
    163 {
    164 	if (nr < arch_nr)
    165 		return fio_arch_strings[nr];
    166 
    167 	return NULL;
    168 }
    169 
    170 void td_set_runstate(struct thread_data *td, int runstate)
    171 {
    172 	if (td->runstate == runstate)
    173 		return;
    174 
    175 	dprint(FD_PROCESS, "pid=%d: runstate %d -> %d\n", (int) td->pid,
    176 						td->runstate, runstate);
    177 	td->runstate = runstate;
    178 }
    179 
    180 int td_bump_runstate(struct thread_data *td, int new_state)
    181 {
    182 	int old_state = td->runstate;
    183 
    184 	td_set_runstate(td, new_state);
    185 	return old_state;
    186 }
    187 
    188 void td_restore_runstate(struct thread_data *td, int old_state)
    189 {
    190 	td_set_runstate(td, old_state);
    191 }
    192 
    193 void fio_mark_td_terminate(struct thread_data *td)
    194 {
    195 	fio_gettime(&td->terminate_time, NULL);
    196 	write_barrier();
    197 	td->terminate = 1;
    198 }
    199 
    200 void fio_terminate_threads(int group_id)
    201 {
    202 	struct thread_data *td;
    203 	pid_t pid = getpid();
    204 	int i;
    205 
    206 	dprint(FD_PROCESS, "terminate group_id=%d\n", group_id);
    207 
    208 	for_each_td(td, i) {
    209 		if (group_id == TERMINATE_ALL || groupid == td->groupid) {
    210 			dprint(FD_PROCESS, "setting terminate on %s/%d\n",
    211 						td->o.name, (int) td->pid);
    212 
    213 			if (td->terminate)
    214 				continue;
    215 
    216 			fio_mark_td_terminate(td);
    217 			td->o.start_delay = 0;
    218 
    219 			/*
    220 			 * if the thread is running, just let it exit
    221 			 */
    222 			if (!td->pid || pid == td->pid)
    223 				continue;
    224 			else if (td->runstate < TD_RAMP)
    225 				kill(td->pid, SIGTERM);
    226 			else {
    227 				struct ioengine_ops *ops = td->io_ops;
    228 
    229 				if (ops && ops->terminate)
    230 					ops->terminate(td);
    231 			}
    232 		}
    233 	}
    234 }
    235 
    236 int fio_running_or_pending_io_threads(void)
    237 {
    238 	struct thread_data *td;
    239 	int i;
    240 
    241 	for_each_td(td, i) {
    242 		if (td->flags & TD_F_NOIO)
    243 			continue;
    244 		if (td->runstate < TD_EXITED)
    245 			return 1;
    246 	}
    247 
    248 	return 0;
    249 }
    250 
    251 int fio_set_fd_nonblocking(int fd, const char *who)
    252 {
    253 	int flags;
    254 
    255 	flags = fcntl(fd, F_GETFL);
    256 	if (flags < 0)
    257 		log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno));
    258 	else {
    259 		int new_flags = flags | O_NONBLOCK;
    260 
    261 		new_flags = fcntl(fd, F_SETFL, new_flags);
    262 		if (new_flags < 0)
    263 			log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno));
    264 	}
    265 
    266 	return flags;
    267 }
    268 
    269 static int endian_check(void)
    270 {
    271 	union {
    272 		uint8_t c[8];
    273 		uint64_t v;
    274 	} u;
    275 	int le = 0, be = 0;
    276 
    277 	u.v = 0x12;
    278 	if (u.c[7] == 0x12)
    279 		be = 1;
    280 	else if (u.c[0] == 0x12)
    281 		le = 1;
    282 
    283 #if defined(CONFIG_LITTLE_ENDIAN)
    284 	if (be)
    285 		return 1;
    286 #elif defined(CONFIG_BIG_ENDIAN)
    287 	if (le)
    288 		return 1;
    289 #else
    290 	return 1;
    291 #endif
    292 
    293 	if (!le && !be)
    294 		return 1;
    295 
    296 	return 0;
    297 }
    298 
    299 int initialize_fio(char *envp[])
    300 {
    301 	long ps;
    302 
    303 	/*
    304 	 * We need these to be properly 64-bit aligned, otherwise we
    305 	 * can run into problems on archs that fault on unaligned fp
    306 	 * access (ARM).
    307 	 */
    308 	compiletime_assert((offsetof(struct thread_stat, percentile_list) % 8) == 0, "stat percentile_list");
    309 	compiletime_assert((offsetof(struct thread_stat, total_run_time) % 8) == 0, "total_run_time");
    310 	compiletime_assert((offsetof(struct thread_stat, total_err_count) % 8) == 0, "total_err_count");
    311 	compiletime_assert((offsetof(struct thread_stat, latency_percentile) % 8) == 0, "stat latency_percentile");
    312 	compiletime_assert((offsetof(struct thread_options_pack, zipf_theta) % 8) == 0, "zipf_theta");
    313 	compiletime_assert((offsetof(struct thread_options_pack, pareto_h) % 8) == 0, "pareto_h");
    314 	compiletime_assert((offsetof(struct thread_options_pack, percentile_list) % 8) == 0, "percentile_list");
    315 	compiletime_assert((offsetof(struct thread_options_pack, latency_percentile) % 8) == 0, "latency_percentile");
    316 
    317 	if (endian_check()) {
    318 		log_err("fio: endianness settings appear wrong.\n");
    319 		log_err("fio: please report this to fio (at) vger.kernel.org\n");
    320 		return 1;
    321 	}
    322 
    323 #if !defined(CONFIG_GETTIMEOFDAY) && !defined(CONFIG_CLOCK_GETTIME)
    324 #error "No available clock source!"
    325 #endif
    326 
    327 	arch_init(envp);
    328 
    329 	sinit();
    330 
    331 	if (fio_filelock_init()) {
    332 		log_err("fio: failed initializing filelock subsys\n");
    333 		return 1;
    334 	}
    335 
    336 	/*
    337 	 * We need locale for number printing, if it isn't set then just
    338 	 * go with the US format.
    339 	 */
    340 	if (!getenv("LC_NUMERIC"))
    341 		setlocale(LC_NUMERIC, "en_US");
    342 
    343 	ps = sysconf(_SC_PAGESIZE);
    344 	if (ps < 0) {
    345 		log_err("Failed to get page size\n");
    346 		return 1;
    347 	}
    348 
    349 	page_size = ps;
    350 	page_mask = ps - 1;
    351 
    352 	fio_keywords_init();
    353 	return 0;
    354 }
    355