projects
/
fio.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Fix assert
[fio.git]
/
fio.c
diff --git
a/fio.c
b/fio.c
index 63d9a1b7ab434ca4eba416ab2fe71bbc9e71385a..7b03250bd22ddce7b01c6a3e8e306ca108ef447e 100644
(file)
--- a/
fio.c
+++ b/
fio.c
@@
-38,7
+38,11
@@
#include "hash.h"
#include "smalloc.h"
#include "verify.h"
#include "hash.h"
#include "smalloc.h"
#include "verify.h"
+#include "trim.h"
#include "diskutil.h"
#include "diskutil.h"
+#include "cgroup.h"
+#include "profile.h"
+#include "lib/rand.h"
unsigned long page_mask;
unsigned long page_size;
unsigned long page_mask;
unsigned long page_size;
@@
-60,6
+64,8
@@
static volatile int fio_abort;
static int exit_value;
static struct itimerval itimer;
static pthread_t gtod_thread;
static int exit_value;
static struct itimerval itimer;
static pthread_t gtod_thread;
+static struct flist_head *cgroup_list;
+static char *cgroup_mnt;
struct io_log *agg_io_log[2];
struct io_log *agg_io_log[2];
@@
-131,23
+137,12
@@
static void sig_quit(int sig)
static void sig_int(int sig)
{
if (threads) {
static void sig_int(int sig)
{
if (threads) {
-
printf
("\nfio: terminating on signal %d\n", sig);
+
log_info
("\nfio: terminating on signal %d\n", sig);
fflush(stdout);
terminate_threads(TERMINATE_ALL);
}
}
fflush(stdout);
terminate_threads(TERMINATE_ALL);
}
}
-static void sig_ill(int fio_unused sig)
-{
- if (!threads)
- return;
-
- log_err("fio: illegal instruction. your cpu does not support "
- "the sse4.2 instruction for crc32c\n");
- terminate_threads(TERMINATE_ALL);
- exit(4);
-}
-
static void set_sig_handlers(void)
{
struct sigaction act;
static void set_sig_handlers(void)
{
struct sigaction act;
@@
-162,11
+157,6
@@
static void set_sig_handlers(void)
act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, NULL);
act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, NULL);
- memset(&act, 0, sizeof(act));
- act.sa_handler = sig_ill;
- act.sa_flags = SA_RESTART;
- sigaction(SIGILL, &act, NULL);
-
memset(&act, 0, sizeof(act));
act.sa_handler = sig_quit;
act.sa_flags = SA_RESTART;
memset(&act, 0, sizeof(act));
act.sa_handler = sig_quit;
act.sa_flags = SA_RESTART;
@@
-187,6
+177,8
@@
static int __check_min_rate(struct thread_data *td, struct timeval *now,
unsigned int rate_iops = 0;
unsigned int rate_iops_min = 0;
unsigned int rate_iops = 0;
unsigned int rate_iops_min = 0;
+ assert(ddir_rw(ddir));
+
if (!td->o.ratemin[ddir] && !td->o.rate_iops_min[ddir])
return 0;
if (!td->o.ratemin[ddir] && !td->o.rate_iops_min[ddir])
return 0;
@@
-223,7
+215,7
@@
static int __check_min_rate(struct thread_data *td, struct timeval *now,
if (rate < ratemin ||
bytes < td->rate_bytes[ddir]) {
log_err("%s: min rate %u not met, got"
if (rate < ratemin ||
bytes < td->rate_bytes[ddir]) {
log_err("%s: min rate %u not met, got"
- " %luK
i
B/sec\n", td->o.name,
+ " %luKB/sec\n", td->o.name,
ratemin, rate);
return 1;
}
ratemin, rate);
return 1;
}
@@
-388,21
+380,29
@@
static int break_on_this_error(struct thread_data *td, int *retptr)
else
err = td->error;
else
err = td->error;
- update_error_count(td, err);
-
if (td_non_fatal_error(err)) {
/*
* Continue with the I/Os in case of
* a non fatal error.
*/
if (td_non_fatal_error(err)) {
/*
* Continue with the I/Os in case of
* a non fatal error.
*/
+ update_error_count(td, err);
td_clear_error(td);
*retptr = 0;
return 0;
td_clear_error(td);
*retptr = 0;
return 0;
+ } else if (td->o.fill_device && err == ENOSPC) {
+ /*
+ * We expect to hit this error if
+ * fill_device option is set.
+ */
+ td_clear_error(td);
+ td->terminate = 1;
+ return 1;
} else {
/*
* Stop the I/O in case of a fatal
* error.
*/
} else {
/*
* Stop the I/O in case of a fatal
* error.
*/
+ update_error_count(td, err);
return 1;
}
}
return 1;
}
}
@@
-421,6
+421,8
@@
static void do_verify(struct thread_data *td)
int ret, min_events;
unsigned int i;
int ret, min_events;
unsigned int i;
+ dprint(FD_VERIFY, "starting loop\n");
+
/*
* sync io first and invalidate cache, to make sure we really
* read from disk.
/*
* sync io first and invalidate cache, to make sure we really
* read from disk.
@@
-464,7
+466,10
@@
static void do_verify(struct thread_data *td)
break;
}
break;
}
- io_u->end_io = verify_io_u;
+ if (td->o.verify_async)
+ io_u->end_io = verify_io_u_async;
+ else
+ io_u->end_io = verify_io_u;
ret = td_io_queue(td, io_u);
switch (ret) {
ret = td_io_queue(td, io_u);
switch (ret) {
@@
-489,7
+494,8
@@
static void do_verify(struct thread_data *td)
io_u->xfer_buf += bytes;
io_u->offset += bytes;
io_u->xfer_buf += bytes;
io_u->offset += bytes;
- td->ts.short_io_u[io_u->ddir]++;
+ if (ddir_rw(io_u->ddir))
+ td->ts.short_io_u[io_u->ddir]++;
if (io_u->offset == f->real_file_size)
goto sync_done;
if (io_u->offset == f->real_file_size)
goto sync_done;
@@
-525,7
+531,8
@@
sync_done:
*/
full = queue_full(td) || ret == FIO_Q_BUSY;
if (full || !td->o.iodepth_batch_complete) {
*/
full = queue_full(td) || ret == FIO_Q_BUSY;
if (full || !td->o.iodepth_batch_complete) {
- min_events = td->o.iodepth_batch_complete;
+ min_events = min(td->o.iodepth_batch_complete,
+ td->cur_depth);
if (full && !min_events)
min_events = 1;
if (full && !min_events)
min_events = 1;
@@
-554,6
+561,8
@@
sync_done:
cleanup_pending_aio(td);
td_set_runstate(td, TD_RUNNING);
cleanup_pending_aio(td);
td_set_runstate(td, TD_RUNNING);
+
+ dprint(FD_VERIFY, "exiting loop\n");
}
/*
}
/*
@@
-570,7
+579,9
@@
static void do_io(struct thread_data *td)
else
td_set_runstate(td, TD_RUNNING);
else
td_set_runstate(td, TD_RUNNING);
- while ((td->this_io_bytes[0] + td->this_io_bytes[1]) < td->o.size) {
+ while ( (td->o.read_iolog_file && !flist_empty(&td->io_log_list)) ||
+ (!flist_empty(&td->trim_list)) ||
+ ((td->this_io_bytes[0] + td->this_io_bytes[1]) < td->o.size) ) {
struct timeval comp_time;
unsigned long bytes_done[2] = { 0, 0 };
int min_evts = 0;
struct timeval comp_time;
unsigned long bytes_done[2] = { 0, 0 };
int min_evts = 0;
@@
-595,8
+606,12
@@
static void do_io(struct thread_data *td)
* Add verification end_io handler, if asked to verify
* a previously written file.
*/
* Add verification end_io handler, if asked to verify
* a previously written file.
*/
- if (td->o.verify != VERIFY_NONE && io_u->ddir == DDIR_READ) {
- io_u->end_io = verify_io_u;
+ if (td->o.verify != VERIFY_NONE && io_u->ddir == DDIR_READ &&
+ !td_rw(td)) {
+ if (td->o.verify_async)
+ io_u->end_io = verify_io_u_async;
+ else
+ io_u->end_io = verify_io_u;
td_set_runstate(td, TD_VERIFYING);
} else if (in_ramp_time(td))
td_set_runstate(td, TD_RAMP);
td_set_runstate(td, TD_VERIFYING);
} else if (in_ramp_time(td))
td_set_runstate(td, TD_RAMP);
@@
-626,7
+641,8
@@
static void do_io(struct thread_data *td)
io_u->xfer_buf += bytes;
io_u->offset += bytes;
io_u->xfer_buf += bytes;
io_u->offset += bytes;
- td->ts.short_io_u[io_u->ddir]++;
+ if (ddir_rw(io_u->ddir))
+ td->ts.short_io_u[io_u->ddir]++;
if (io_u->offset == f->real_file_size)
goto sync_done;
if (io_u->offset == f->real_file_size)
goto sync_done;
@@
-672,7
+688,8
@@
sync_done:
*/
full = queue_full(td) || ret == FIO_Q_BUSY;
if (full || !td->o.iodepth_batch_complete) {
*/
full = queue_full(td) || ret == FIO_Q_BUSY;
if (full || !td->o.iodepth_batch_complete) {
- min_evts = td->o.iodepth_batch_complete;
+ min_evts = min(td->o.iodepth_batch_complete,
+ td->cur_depth);
if (full && !min_evts)
min_evts = 1;
if (full && !min_evts)
min_evts = 1;
@@
-719,6
+736,9
@@
sync_done:
}
}
}
}
+ if (td->trim_entries)
+ printf("trim entries %ld\n", td->trim_entries);
+
if (td->o.fill_device && td->error == ENOSPC) {
td->error = 0;
td->terminate = 1;
if (td->o.fill_device && td->error == ENOSPC) {
td->error = 0;
td->terminate = 1;
@@
-791,7
+811,7
@@
static int init_io_u(struct thread_data *td)
if (allocate_io_mem(td))
return 1;
if (allocate_io_mem(td))
return 1;
- if (td->o.mem_align)
+ if (td->o.
odirect || td->o.
mem_align)
p = PAGE_ALIGN(td->orig_buffer) + td->o.mem_align;
else
p = td->orig_buffer;
p = PAGE_ALIGN(td->orig_buffer) + td->o.mem_align;
else
p = td->orig_buffer;
@@
-820,6
+840,13
@@
static int init_io_u(struct thread_data *td)
if (td_write(td) && !td->o.refill_buffers)
io_u_fill_buffer(td, io_u, max_bs);
if (td_write(td) && !td->o.refill_buffers)
io_u_fill_buffer(td, io_u, max_bs);
+ else if (td_write(td) && td->o.verify_pattern_bytes) {
+ /*
+ * Fill the buffer with the pattern if we are
+ * going to be doing writes.
+ */
+ fill_pattern(td, io_u->buf, max_bs, io_u);
+ }
}
io_u->index = i;
}
io_u->index = i;
@@
-984,6
+1011,7
@@
static void *thread_main(void *data)
{
unsigned long long runtime[2], elapsed;
struct thread_data *td = data;
{
unsigned long long runtime[2], elapsed;
struct thread_data *td = data;
+ pthread_condattr_t attr;
int clear_state;
if (!td->o.use_thread)
int clear_state;
if (!td->o.use_thread)
@@
-998,8
+1026,15
@@
static void *thread_main(void *data)
INIT_FLIST_HEAD(&td->io_u_requeues);
INIT_FLIST_HEAD(&td->io_log_list);
INIT_FLIST_HEAD(&td->io_hist_list);
INIT_FLIST_HEAD(&td->io_u_requeues);
INIT_FLIST_HEAD(&td->io_log_list);
INIT_FLIST_HEAD(&td->io_hist_list);
+ INIT_FLIST_HEAD(&td->verify_list);
+ INIT_FLIST_HEAD(&td->trim_list);
+ pthread_mutex_init(&td->io_u_lock, NULL);
td->io_hist_tree = RB_ROOT;
td->io_hist_tree = RB_ROOT;
+ pthread_condattr_init(&attr);
+ pthread_cond_init(&td->verify_cond, &attr);
+ pthread_cond_init(&td->free_cond, &attr);
+
td_set_runstate(td, TD_INITIALIZED);
dprint(FD_MUTEX, "up startup_mutex\n");
fio_mutex_up(startup_mutex);
td_set_runstate(td, TD_INITIALIZED);
dprint(FD_MUTEX, "up startup_mutex\n");
fio_mutex_up(startup_mutex);
@@
-1013,6
+1048,15
@@
static void *thread_main(void *data)
*/
fio_mutex_remove(td->mutex);
*/
fio_mutex_remove(td->mutex);
+ if (td->o.uid != -1U && setuid(td->o.uid)) {
+ td_verror(td, errno, "setuid");
+ goto err;
+ }
+ if (td->o.gid != -1U && setgid(td->o.gid)) {
+ td_verror(td, errno, "setgid");
+ goto err;
+ }
+
/*
* May alter parameters that init_io_u() will use, so we need to
* do this first.
/*
* May alter parameters that init_io_u() will use, so we need to
* do this first.
@@
-1023,7
+1067,10
@@
static void *thread_main(void *data)
if (init_io_u(td))
goto err;
if (init_io_u(td))
goto err;
- if (td->o.cpumask_set && fio_setaffinity(td) == -1) {
+ if (td->o.verify_async && verify_async_init(td))
+ goto err;
+
+ if (td->o.cpumask_set && fio_setaffinity(td->pid, td->o.cpumask) == -1) {
td_verror(td, errno, "cpu_set_affinity");
goto err;
}
td_verror(td, errno, "cpu_set_affinity");
goto err;
}
@@
-1034,7
+1081,7
@@
static void *thread_main(void *data)
*/
if (td->o.gtod_cpu) {
fio_cpu_clear(&td->o.cpumask, td->o.gtod_cpu);
*/
if (td->o.gtod_cpu) {
fio_cpu_clear(&td->o.cpumask, td->o.gtod_cpu);
- if (fio_setaffinity(td) == -1) {
+ if (fio_setaffinity(td
->pid, td->o.cpumask
) == -1) {
td_verror(td, errno, "cpu_set_affinity");
goto err;
}
td_verror(td, errno, "cpu_set_affinity");
goto err;
}
@@
-1047,6
+1094,9
@@
static void *thread_main(void *data)
}
}
}
}
+ if (td->o.cgroup_weight && cgroup_setup(td, cgroup_list, &cgroup_mnt))
+ goto err;
+
if (nice(td->o.nice) == -1) {
td_verror(td, errno, "nice");
goto err;
if (nice(td->o.nice) == -1) {
td_verror(td, errno, "nice");
goto err;
@@
-1081,7
+1131,10
@@
static void *thread_main(void *data)
clear_state = 0;
while (keep_running(td)) {
fio_gettime(&td->start, NULL);
clear_state = 0;
while (keep_running(td)) {
fio_gettime(&td->start, NULL);
- memcpy(&td->ts.stat_sample_time, &td->start, sizeof(td->start));
+ memcpy(&td->ts.stat_sample_time[0], &td->start,
+ sizeof(td->start));
+ memcpy(&td->ts.stat_sample_time[1], &td->start,
+ sizeof(td->start));
memcpy(&td->tv_cache, &td->start, sizeof(td->start));
if (td->o.ratemin[0] || td->o.ratemin[1])
memcpy(&td->tv_cache, &td->start, sizeof(td->start));
if (td->o.ratemin[0] || td->o.ratemin[1])
@@
-1141,6
+1194,13
@@
static void *thread_main(void *data)
} else
finish_log(td, td->ts.bw_log, "bw");
}
} else
finish_log(td, td->ts.bw_log, "bw");
}
+ if (td->ts.lat_log) {
+ if (td->o.lat_log_file) {
+ finish_log_named(td, td->ts.lat_log,
+ td->o.lat_log_file, "lat");
+ } else
+ finish_log(td, td->ts.lat_log, "lat");
+ }
if (td->ts.slat_log) {
if (td->o.lat_log_file) {
finish_log_named(td, td->ts.slat_log,
if (td->ts.slat_log) {
if (td->o.lat_log_file) {
finish_log_named(td, td->ts.slat_log,
@@
-1164,11
+1224,16
@@
static void *thread_main(void *data)
err:
if (td->error)
err:
if (td->error)
-
printf
("fio: pid=%d, err=%d/%s\n", (int) td->pid, td->error,
+
log_info
("fio: pid=%d, err=%d/%s\n", (int) td->pid, td->error,
td->verror);
td->verror);
+
+ if (td->o.verify_async)
+ verify_async_exit(td);
+
close_and_free_files(td);
close_ioengine(td);
cleanup_io_u(td);
close_and_free_files(td);
close_ioengine(td);
cleanup_io_u(td);
+ cgroup_shutdown(td, &cgroup_mnt);
if (td->o.cpumask_set) {
int ret = fio_cpuset_exit(&td->o.cpumask);
if (td->o.cpumask_set) {
int ret = fio_cpuset_exit(&td->o.cpumask);
@@
-1325,9
+1390,13
@@
static void *gtod_thread_main(void *data)
static int fio_start_gtod_thread(void)
{
static int fio_start_gtod_thread(void)
{
+ pthread_attr_t attr;
int ret;
int ret;
- ret = pthread_create(>od_thread, NULL, gtod_thread_main, NULL);
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+ ret = pthread_create(>od_thread, &attr, gtod_thread_main, NULL);
+ pthread_attr_destroy(&attr);
if (ret) {
log_err("Can't create gtod thread: %s\n", strerror(ret));
return 1;
if (ret) {
log_err("Can't create gtod thread: %s\n", strerror(ret));
return 1;
@@
-1361,17
+1430,17
@@
static void run_threads(void)
return;
if (!terse_output) {
return;
if (!terse_output) {
-
printf
("Starting ");
+
log_info
("Starting ");
if (nr_thread)
if (nr_thread)
-
printf
("%d thread%s", nr_thread,
+
log_info
("%d thread%s", nr_thread,
nr_thread > 1 ? "s" : "");
if (nr_process) {
if (nr_thread)
printf(" and ");
nr_thread > 1 ? "s" : "");
if (nr_process) {
if (nr_thread)
printf(" and ");
-
printf
("%d process%s", nr_process,
+
log_info
("%d process%s", nr_process,
nr_process > 1 ? "es" : "");
}
nr_process > 1 ? "es" : "");
}
-
printf
("\n");
+
log_info
("\n");
fflush(stdout);
}
fflush(stdout);
}
@@
-1492,7
+1561,13
@@
static void run_threads(void)
*fio_debug_jobp = pid;
}
dprint(FD_MUTEX, "wait on startup_mutex\n");
*fio_debug_jobp = pid;
}
dprint(FD_MUTEX, "wait on startup_mutex\n");
- fio_mutex_down(startup_mutex);
+ if (fio_mutex_down_timeout(startup_mutex, 10)) {
+ log_err("fio: job startup hung? exiting.\n");
+ terminate_threads(TERMINATE_ALL);
+ fio_abort = 1;
+ nr_started--;
+ break;
+ }
dprint(FD_MUTEX, "done waiting on startup_mutex\n");
}
dprint(FD_MUTEX, "done waiting on startup_mutex\n");
}
@@
-1574,6
+1649,7
@@
int main(int argc, char *argv[])
long ps;
sinit();
long ps;
sinit();
+ init_rand(&__fio_rand_state);
/*
* We need locale for number printing, if it isn't set then just
/*
* We need locale for number printing, if it isn't set then just
@@
-1582,12
+1658,6
@@
int main(int argc, char *argv[])
if (!getenv("LC_NUMERIC"))
setlocale(LC_NUMERIC, "en_US");
if (!getenv("LC_NUMERIC"))
setlocale(LC_NUMERIC, "en_US");
- if (parse_options(argc, argv))
- return 1;
-
- if (!thread_number)
- return 0;
-
ps = sysconf(_SC_PAGESIZE);
if (ps < 0) {
log_err("Failed to get page size\n");
ps = sysconf(_SC_PAGESIZE);
if (ps < 0) {
log_err("Failed to get page size\n");
@@
-1597,6
+1667,17
@@
int main(int argc, char *argv[])
page_size = ps;
page_mask = ps - 1;
page_size = ps;
page_mask = ps - 1;
+ fio_keywords_init();
+
+ if (parse_options(argc, argv))
+ return 1;
+
+ if (exec_profile && load_profile(exec_profile))
+ return 1;
+
+ if (!thread_number)
+ return 0;
+
if (write_bw_log) {
setup_log(&agg_io_log[DDIR_READ]);
setup_log(&agg_io_log[DDIR_WRITE]);
if (write_bw_log) {
setup_log(&agg_io_log[DDIR_READ]);
setup_log(&agg_io_log[DDIR_WRITE]);
@@
-1609,6
+1690,9
@@
int main(int argc, char *argv[])
status_timer_arm();
status_timer_arm();
+ cgroup_list = smalloc(sizeof(*cgroup_list));
+ INIT_FLIST_HEAD(cgroup_list);
+
run_threads();
if (!fio_abort) {
run_threads();
if (!fio_abort) {
@@
-1620,6
+1704,10
@@
int main(int argc, char *argv[])
}
}
}
}
+ cgroup_kill(cgroup_list);
+ sfree(cgroup_list);
+ sfree(cgroup_mnt);
+
fio_mutex_remove(startup_mutex);
fio_mutex_remove(writeout_mutex);
return exit_value;
fio_mutex_remove(startup_mutex);
fio_mutex_remove(writeout_mutex);
return exit_value;