Blame libfio.c

Packit 8930e1
/*
Packit 8930e1
 * fio - the flexible io tester
Packit 8930e1
 *
Packit 8930e1
 * Copyright (C) 2005 Jens Axboe <axboe@suse.de>
Packit 8930e1
 * Copyright (C) 2006-2012 Jens Axboe <axboe@kernel.dk>
Packit 8930e1
 *
Packit 8930e1
 * The license below covers all files distributed with fio unless otherwise
Packit 8930e1
 * noted in the file itself.
Packit 8930e1
 *
Packit 8930e1
 *  This program is free software; you can redistribute it and/or modify
Packit 8930e1
 *  it under the terms of the GNU General Public License version 2 as
Packit 8930e1
 *  published by the Free Software Foundation.
Packit 8930e1
 *
Packit 8930e1
 *  This program is distributed in the hope that it will be useful,
Packit 8930e1
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8930e1
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8930e1
 *  GNU General Public License for more details.
Packit 8930e1
 *
Packit 8930e1
 *  You should have received a copy of the GNU General Public License
Packit 8930e1
 *  along with this program; if not, write to the Free Software
Packit 8930e1
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 8930e1
 *
Packit 8930e1
 */
Packit 8930e1
Packit 8930e1
#include <string.h>
Packit 8930e1
#include <signal.h>
Packit 8930e1
#include <stdint.h>
Packit 8930e1
#include <locale.h>
Packit 8930e1
#include <fcntl.h>
Packit 8930e1
Packit 8930e1
#include "fio.h"
Packit 8930e1
#include "smalloc.h"
Packit 8930e1
#include "os/os.h"
Packit 8930e1
#include "filelock.h"
Packit 8930e1
#include "helper_thread.h"
Packit 8930e1
#include "filehash.h"
Packit 8930e1
Packit 8930e1
FLIST_HEAD(disk_list);
Packit 8930e1
Packit 8930e1
unsigned long arch_flags = 0;
Packit 8930e1
Packit 8930e1
uintptr_t page_mask = 0;
Packit 8930e1
uintptr_t page_size = 0;
Packit 8930e1
Packit 8930e1
/* see os/os.h */
Packit 8930e1
static const char *fio_os_strings[os_nr] = {
Packit 8930e1
	"Invalid",
Packit 8930e1
	"Linux",
Packit 8930e1
	"AIX",
Packit 8930e1
	"FreeBSD",
Packit 8930e1
	"HP-UX",
Packit 8930e1
	"OSX",
Packit 8930e1
	"NetBSD",
Packit 8930e1
	"OpenBSD",
Packit 8930e1
	"Solaris",
Packit 8930e1
	"Windows",
Packit 8930e1
	"Android",
Packit 8930e1
	"DragonFly",
Packit 8930e1
};
Packit 8930e1
Packit 8930e1
/* see arch/arch.h */
Packit 8930e1
static const char *fio_arch_strings[arch_nr] = {
Packit 8930e1
	"Invalid",
Packit 8930e1
	"x86-64",
Packit 8930e1
	"x86",
Packit 8930e1
	"ppc",
Packit 8930e1
	"ia64",
Packit 8930e1
	"s390",
Packit 8930e1
	"alpha",
Packit 8930e1
	"sparc",
Packit 8930e1
	"sparc64",
Packit 8930e1
	"arm",
Packit 8930e1
	"sh",
Packit 8930e1
	"hppa",
Packit 8930e1
	"mips",
Packit 8930e1
	"aarch64",
Packit 8930e1
	"generic"
Packit 8930e1
};
Packit 8930e1
Packit 8930e1
static void reset_io_counters(struct thread_data *td, int all)
Packit 8930e1
{
Packit 8930e1
	int ddir;
Packit 8930e1
Packit 8930e1
	if (all) {
Packit 8930e1
		for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
Packit 8930e1
			td->stat_io_bytes[ddir] = 0;
Packit 8930e1
			td->this_io_bytes[ddir] = 0;
Packit 8930e1
			td->stat_io_blocks[ddir] = 0;
Packit 8930e1
			td->this_io_blocks[ddir] = 0;
Packit 8930e1
			td->rate_bytes[ddir] = 0;
Packit 8930e1
			td->rate_blocks[ddir] = 0;
Packit 8930e1
			td->bytes_done[ddir] = 0;
Packit 8930e1
			td->rate_io_issue_bytes[ddir] = 0;
Packit 8930e1
			td->rate_next_io_time[ddir] = 0;
Packit 8930e1
			td->last_usec[ddir] = 0;
Packit 8930e1
		}
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	td->zone_bytes = 0;
Packit 8930e1
Packit 8930e1
	td->last_was_sync = false;
Packit 8930e1
	td->rwmix_issues = 0;
Packit 8930e1
Packit 8930e1
	/*
Packit 8930e1
	 * reset file done count if we are to start over
Packit 8930e1
	 */
Packit 8930e1
	if (td->o.time_based || td->o.loops || td->o.do_verify)
Packit 8930e1
		td->nr_done_files = 0;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void clear_io_state(struct thread_data *td, int all)
Packit 8930e1
{
Packit 8930e1
	struct fio_file *f;
Packit 8930e1
	unsigned int i;
Packit 8930e1
Packit 8930e1
	reset_io_counters(td, all);
Packit 8930e1
Packit 8930e1
	close_files(td);
Packit 8930e1
	for_each_file(td, f, i) {
Packit 8930e1
		fio_file_clear_done(f);
Packit 8930e1
		f->file_offset = get_start_offset(td, f);
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	/*
Packit 8930e1
	 * Re-Seed random number generator if rand_repeatable is true
Packit 8930e1
	 */
Packit 8930e1
	if (td->o.rand_repeatable)
Packit 8930e1
		td_fill_rand_seeds(td);
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void reset_all_stats(struct thread_data *td)
Packit 8930e1
{
Packit 8930e1
	int i;
Packit 8930e1
Packit 8930e1
	reset_io_counters(td, 1);
Packit 8930e1
Packit 8930e1
	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
Packit 8930e1
		td->io_bytes[i] = 0;
Packit 8930e1
		td->io_blocks[i] = 0;
Packit 8930e1
		td->io_issues[i] = 0;
Packit 8930e1
		td->ts.total_io_u[i] = 0;
Packit 8930e1
		td->ts.runtime[i] = 0;
Packit 8930e1
		td->rwmix_issues = 0;
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	set_epoch_time(td, td->o.log_unix_epoch);
Packit 8930e1
	memcpy(&td->start, &td->epoch, sizeof(td->epoch));
Packit 8930e1
	memcpy(&td->iops_sample_time, &td->epoch, sizeof(td->epoch));
Packit 8930e1
	memcpy(&td->bw_sample_time, &td->epoch, sizeof(td->epoch));
Packit 8930e1
	memcpy(&td->ss.prev_time, &td->epoch, sizeof(td->epoch));
Packit 8930e1
Packit 8930e1
	lat_target_reset(td);
Packit 8930e1
	clear_rusage_stat(td);
Packit 8930e1
	helper_reset();
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void reset_fio_state(void)
Packit 8930e1
{
Packit 8930e1
	groupid = 0;
Packit 8930e1
	thread_number = 0;
Packit 8930e1
	stat_number = 0;
Packit 8930e1
	done_secs = 0;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
const char *fio_get_os_string(int nr)
Packit 8930e1
{
Packit 8930e1
	if (nr < os_nr)
Packit 8930e1
		return fio_os_strings[nr];
Packit 8930e1
Packit 8930e1
	return NULL;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
const char *fio_get_arch_string(int nr)
Packit 8930e1
{
Packit 8930e1
	if (nr < arch_nr)
Packit 8930e1
		return fio_arch_strings[nr];
Packit 8930e1
Packit 8930e1
	return NULL;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
static const char *td_runstates[] = {
Packit 8930e1
	"NOT_CREATED",
Packit 8930e1
	"CREATED",
Packit 8930e1
	"INITIALIZED",
Packit 8930e1
	"RAMP",
Packit 8930e1
	"SETTING_UP",
Packit 8930e1
	"RUNNING",
Packit 8930e1
	"PRE_READING",
Packit 8930e1
	"VERIFYING",
Packit 8930e1
	"FSYNCING",
Packit 8930e1
	"FINISHING",
Packit 8930e1
	"EXITED",
Packit 8930e1
	"REAPED",
Packit 8930e1
};
Packit 8930e1
Packit 8930e1
const char *runstate_to_name(int runstate)
Packit 8930e1
{
Packit 8930e1
	compiletime_assert(TD_LAST == 12, "td runstate list");
Packit 8930e1
	if (runstate >= 0 && runstate < TD_LAST)
Packit 8930e1
		return td_runstates[runstate];
Packit 8930e1
Packit 8930e1
	return "invalid";
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void td_set_runstate(struct thread_data *td, int runstate)
Packit 8930e1
{
Packit 8930e1
	if (td->runstate == runstate)
Packit 8930e1
		return;
Packit 8930e1
Packit 8930e1
	dprint(FD_PROCESS, "pid=%d: runstate %s -> %s\n", (int) td->pid,
Packit 8930e1
						runstate_to_name(td->runstate),
Packit 8930e1
						runstate_to_name(runstate));
Packit 8930e1
	td->runstate = runstate;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
int td_bump_runstate(struct thread_data *td, int new_state)
Packit 8930e1
{
Packit 8930e1
	int old_state = td->runstate;
Packit 8930e1
Packit 8930e1
	td_set_runstate(td, new_state);
Packit 8930e1
	return old_state;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void td_restore_runstate(struct thread_data *td, int old_state)
Packit 8930e1
{
Packit 8930e1
	td_set_runstate(td, old_state);
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void fio_mark_td_terminate(struct thread_data *td)
Packit 8930e1
{
Packit 8930e1
	fio_gettime(&td->terminate_time, NULL);
Packit 8930e1
	write_barrier();
Packit 8930e1
	td->terminate = true;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void fio_terminate_threads(unsigned int group_id, unsigned int terminate)
Packit 8930e1
{
Packit 8930e1
	struct thread_data *td;
Packit 8930e1
	pid_t pid = getpid();
Packit 8930e1
	int i;
Packit 8930e1
Packit 8930e1
	dprint(FD_PROCESS, "terminate group_id=%d\n", group_id);
Packit 8930e1
Packit 8930e1
	for_each_td(td, i) {
Packit 8930e1
		if ((terminate == TERMINATE_GROUP && group_id == TERMINATE_ALL) ||
Packit 8930e1
		    (terminate == TERMINATE_GROUP && group_id == td->groupid) ||
Packit 8930e1
		    (terminate == TERMINATE_STONEWALL && td->runstate >= TD_RUNNING) ||
Packit 8930e1
		    (terminate == TERMINATE_ALL)) {
Packit 8930e1
			dprint(FD_PROCESS, "setting terminate on %s/%d\n",
Packit 8930e1
						td->o.name, (int) td->pid);
Packit 8930e1
Packit 8930e1
			if (td->terminate)
Packit 8930e1
				continue;
Packit 8930e1
Packit 8930e1
			fio_mark_td_terminate(td);
Packit 8930e1
			td->o.start_delay = 0;
Packit 8930e1
Packit 8930e1
			/*
Packit 8930e1
			 * if the thread is running, just let it exit
Packit 8930e1
			 */
Packit 8930e1
			if (!td->pid || pid == td->pid)
Packit 8930e1
				continue;
Packit 8930e1
			else if (td->runstate < TD_RAMP)
Packit 8930e1
				kill(td->pid, SIGTERM);
Packit 8930e1
			else {
Packit 8930e1
				struct ioengine_ops *ops = td->io_ops;
Packit 8930e1
Packit 8930e1
				if (ops && ops->terminate)
Packit 8930e1
					ops->terminate(td);
Packit 8930e1
			}
Packit 8930e1
		}
Packit 8930e1
	}
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
int fio_running_or_pending_io_threads(void)
Packit 8930e1
{
Packit 8930e1
	struct thread_data *td;
Packit 8930e1
	int i;
Packit 8930e1
	int nr_io_threads = 0;
Packit 8930e1
Packit 8930e1
	for_each_td(td, i) {
Packit 8930e1
		if (td->io_ops_init && td_ioengine_flagged(td, FIO_NOIO))
Packit 8930e1
			continue;
Packit 8930e1
		nr_io_threads++;
Packit 8930e1
		if (td->runstate < TD_EXITED)
Packit 8930e1
			return 1;
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	if (!nr_io_threads)
Packit 8930e1
		return -1; /* we only had cpuio threads to begin with */
Packit 8930e1
	return 0;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
int fio_set_fd_nonblocking(int fd, const char *who)
Packit 8930e1
{
Packit 8930e1
	int flags;
Packit 8930e1
Packit 8930e1
	flags = fcntl(fd, F_GETFL);
Packit 8930e1
	if (flags < 0)
Packit 8930e1
		log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno));
Packit 8930e1
	else {
Packit 8930e1
		int new_flags = flags | O_NONBLOCK;
Packit 8930e1
Packit 8930e1
		new_flags = fcntl(fd, F_SETFL, new_flags);
Packit 8930e1
		if (new_flags < 0)
Packit 8930e1
			log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno));
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	return flags;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
enum {
Packit 8930e1
	ENDIAN_INVALID_BE = 1,
Packit 8930e1
	ENDIAN_INVALID_LE,
Packit 8930e1
	ENDIAN_INVALID_CONFIG,
Packit 8930e1
	ENDIAN_BROKEN,
Packit 8930e1
};
Packit 8930e1
Packit 8930e1
static int endian_check(void)
Packit 8930e1
{
Packit 8930e1
	union {
Packit 8930e1
		uint8_t c[8];
Packit 8930e1
		uint64_t v;
Packit 8930e1
	} u;
Packit 8930e1
	int le = 0, be = 0;
Packit 8930e1
Packit 8930e1
	u.v = 0x12;
Packit 8930e1
	if (u.c[7] == 0x12)
Packit 8930e1
		be = 1;
Packit 8930e1
	else if (u.c[0] == 0x12)
Packit 8930e1
		le = 1;
Packit 8930e1
Packit 8930e1
#if defined(CONFIG_LITTLE_ENDIAN)
Packit 8930e1
	if (be)
Packit 8930e1
		return ENDIAN_INVALID_BE;
Packit 8930e1
#elif defined(CONFIG_BIG_ENDIAN)
Packit 8930e1
	if (le)
Packit 8930e1
		return ENDIAN_INVALID_LE;
Packit 8930e1
#else
Packit 8930e1
	return ENDIAN_INVALID_CONFIG;
Packit 8930e1
#endif
Packit 8930e1
Packit 8930e1
	if (!le && !be)
Packit 8930e1
		return ENDIAN_BROKEN;
Packit 8930e1
Packit 8930e1
	return 0;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
int initialize_fio(char *envp[])
Packit 8930e1
{
Packit 8930e1
	long ps;
Packit 8930e1
	int err;
Packit 8930e1
Packit 8930e1
	/*
Packit 8930e1
	 * We need these to be properly 64-bit aligned, otherwise we
Packit 8930e1
	 * can run into problems on archs that fault on unaligned fp
Packit 8930e1
	 * access (ARM).
Packit 8930e1
	 */
Packit 8930e1
	compiletime_assert((offsetof(struct thread_data, ts) % sizeof(void *)) == 0, "ts");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_stat, percentile_list) % 8) == 0, "stat percentile_list");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_stat, total_run_time) % 8) == 0, "total_run_time");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_stat, total_err_count) % 8) == 0, "total_err_count");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_stat, latency_percentile) % 8) == 0, "stat latency_percentile");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_data, ts.clat_stat) % 8) == 0, "ts.clat_stat");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_options_pack, zipf_theta) % 8) == 0, "zipf_theta");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_options_pack, pareto_h) % 8) == 0, "pareto_h");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_options_pack, percentile_list) % 8) == 0, "percentile_list");
Packit 8930e1
	compiletime_assert((offsetof(struct thread_options_pack, latency_percentile) % 8) == 0, "latency_percentile");
Packit 8930e1
	compiletime_assert((offsetof(struct jobs_eta, m_rate) % 8) == 0, "m_rate");
Packit 8930e1
Packit 8930e1
	compiletime_assert(__TD_F_LAST <= TD_ENG_FLAG_SHIFT, "TD_ENG_FLAG_SHIFT");
Packit 8930e1
	compiletime_assert(BSSPLIT_MAX <= ZONESPLIT_MAX, "bsssplit/zone max");
Packit 8930e1
Packit 8930e1
	err = endian_check();
Packit 8930e1
	if (err) {
Packit 8930e1
		log_err("fio: endianness settings appear wrong.\n");
Packit 8930e1
		switch (err) {
Packit 8930e1
		case ENDIAN_INVALID_BE:
Packit 8930e1
			log_err("fio: got big-endian when configured for little\n");
Packit 8930e1
			break;
Packit 8930e1
		case ENDIAN_INVALID_LE:
Packit 8930e1
			log_err("fio: got little-endian when configured for big\n");
Packit 8930e1
			break;
Packit 8930e1
		case ENDIAN_INVALID_CONFIG:
Packit 8930e1
			log_err("fio: not configured to any endianness\n");
Packit 8930e1
			break;
Packit 8930e1
		case ENDIAN_BROKEN:
Packit 8930e1
			log_err("fio: failed to detect endianness\n");
Packit 8930e1
			break;
Packit 8930e1
		default:
Packit 8930e1
			assert(0);
Packit 8930e1
			break;
Packit 8930e1
		}
Packit 8930e1
		log_err("fio: please report this to fio@vger.kernel.org\n");
Packit 8930e1
		return 1;
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
#if !defined(CONFIG_GETTIMEOFDAY) && !defined(CONFIG_CLOCK_GETTIME)
Packit 8930e1
#error "No available clock source!"
Packit 8930e1
#endif
Packit 8930e1
Packit 8930e1
	arch_init(envp);
Packit 8930e1
Packit 8930e1
	sinit();
Packit 8930e1
Packit 8930e1
	if (fio_filelock_init()) {
Packit 8930e1
		log_err("fio: failed initializing filelock subsys\n");
Packit 8930e1
		return 1;
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	file_hash_init();
Packit 8930e1
Packit 8930e1
	/*
Packit 8930e1
	 * We need locale for number printing, if it isn't set then just
Packit 8930e1
	 * go with the US format.
Packit 8930e1
	 */
Packit 8930e1
	if (!getenv("LC_NUMERIC"))
Packit 8930e1
		setlocale(LC_NUMERIC, "en_US");
Packit 8930e1
Packit 8930e1
	ps = sysconf(_SC_PAGESIZE);
Packit 8930e1
	if (ps < 0) {
Packit 8930e1
		log_err("Failed to get page size\n");
Packit 8930e1
		return 1;
Packit 8930e1
	}
Packit 8930e1
Packit 8930e1
	page_size = ps;
Packit 8930e1
	page_mask = ps - 1;
Packit 8930e1
Packit 8930e1
	fio_keywords_init();
Packit 8930e1
	return 0;
Packit 8930e1
}
Packit 8930e1
Packit 8930e1
void deinitialize_fio(void)
Packit 8930e1
{
Packit 8930e1
	fio_keywords_exit();
Packit 8930e1
}