X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=iolog.c;h=53dad39618288469d5988de3abd36973767e69e5;hp=e674171e5195f71b74b6c03514a33d597ad4312e;hb=0f989d2e18edda0a4aa979ddfafff4d255681a68;hpb=949ae6dce35c81348cfb15f77c9d0a6785fe4053 diff --git a/iolog.c b/iolog.c index e674171e..53dad396 100644 --- a/iolog.c +++ b/iolog.c @@ -18,6 +18,9 @@ #include "verify.h" #include "trim.h" #include "filelock.h" +#include "smalloc.h" + +static int iolog_flush(struct io_log *log); static const char iolog_ver2[] = "fio version 2 iolog"; @@ -574,14 +577,12 @@ void setup_log(struct io_log **log, struct log_params *p, { struct io_log *l; - l = calloc(1, sizeof(*l)); - l->nr_samples = 0; - l->max_samples = 1024; + l = scalloc(1, sizeof(*l)); + INIT_FLIST_HEAD(&l->io_logs); l->log_type = p->log_type; l->log_offset = p->log_offset; l->log_gz = p->log_gz; l->log_gz_store = p->log_gz_store; - l->log = malloc(l->max_samples * log_entry_sz(l)); l->avg_msec = p->avg_msec; l->filename = strdup(filename); l->td = p->td; @@ -629,12 +630,19 @@ static void clear_file_buffer(void *buf) void free_log(struct io_log *log) { - free(log->log); + while (!flist_empty(&log->io_logs)) { + struct io_logs *cur_log; + + cur_log = flist_first_entry(&log->io_logs, struct io_logs, list); + flist_del_init(&cur_log->list); + free(cur_log->log); + } + free(log->filename); - free(log); + sfree(log); } -static void flush_samples(FILE *f, void *samples, uint64_t sample_size) +void flush_samples(FILE *f, void *samples, uint64_t sample_size) { struct io_sample *s; int log_offset; @@ -672,21 +680,10 @@ static void flush_samples(FILE *f, void *samples, uint64_t sample_size) struct iolog_flush_data { struct workqueue_work work; - pthread_mutex_t lock; - pthread_cond_t cv; - int wait; - volatile int done; - volatile int refs; struct io_log *log; void *samples; - uint64_t nr_samples; -}; - -struct iolog_compress { - struct flist_head list; - void *buf; - size_t len; - unsigned int seq; + uint32_t nr_samples; + bool free; }; #define GZ_CHUNK 131072 @@ -764,7 +761,7 @@ static size_t inflate_chunk(struct iolog_compress *ic, int gz_hdr, FILE *f, { size_t ret; - dprint(FD_COMPRESS, "inflate chunk size=%lu, seq=%u", + dprint(FD_COMPRESS, "inflate chunk size=%lu, seq=%u\n", (unsigned long) ic->len, ic->seq); if (ic->seq != iter->seq) { @@ -967,7 +964,13 @@ void flush_log(struct io_log *log, int do_append) inflate_gz_chunks(log, f); - flush_samples(f, log->log, log->nr_samples * log_entry_sz(log)); + while (!flist_empty(&log->io_logs)) { + struct io_logs *cur_log; + + cur_log = flist_first_entry(&log->io_logs, struct io_logs, list); + flist_del_init(&cur_log->list); + flush_samples(f, cur_log->log, cur_log->nr_samples * log_entry_sz(log)); + } fclose(f); clear_file_buffer(buf); @@ -976,7 +979,7 @@ void flush_log(struct io_log *log, int do_append) static int finish_log(struct thread_data *td, struct io_log *log, int trylock) { if (td->flags & TD_F_COMPRESS_LOG) - iolog_flush(log, 1); + iolog_flush(log); if (trylock) { if (fio_trylock_file(log->filename)) @@ -984,7 +987,7 @@ static int finish_log(struct thread_data *td, struct io_log *log, int trylock) } else fio_lock_file(log->filename); - if (td->client_type == FIO_CLIENT_TYPE_GUI) + if (td->client_type == FIO_CLIENT_TYPE_GUI || is_backend) fio_send_iolog(td, log, log->filename); else flush_log(log, !td->o.per_job_logs); @@ -994,30 +997,30 @@ static int finish_log(struct thread_data *td, struct io_log *log, int trylock) return 0; } -#ifdef CONFIG_ZLIB - -static void drop_data_unlock(struct iolog_flush_data *data) +size_t log_chunk_sizes(struct io_log *log) { - int refs; + struct flist_head *entry; + size_t ret; - refs = --data->refs; - pthread_mutex_unlock(&data->lock); + if (flist_empty(&log->chunk_list)) + return 0; - if (!refs) { - free(data); - pthread_mutex_destroy(&data->lock); - pthread_cond_destroy(&data->cv); + ret = 0; + pthread_mutex_lock(&log->chunk_lock); + flist_for_each(entry, &log->chunk_list) { + struct iolog_compress *c; + + c = flist_entry(entry, struct iolog_compress, list); + ret += c->len; } + pthread_mutex_unlock(&log->chunk_lock); + return ret; } -/* - * Invoked from our compress helper thread, when logging would have exceeded - * the specified memory limitation. Compresses the previously stored - * entries. - */ -static int gz_work(struct submit_worker *sw, struct workqueue_work *work) +#ifdef CONFIG_ZLIB + +static int gz_work(struct iolog_flush_data *data) { - struct iolog_flush_data *data; struct iolog_compress *c; struct flist_head list; unsigned int seq; @@ -1027,8 +1030,7 @@ static int gz_work(struct submit_worker *sw, struct workqueue_work *work) INIT_FLIST_HEAD(&list); - data = container_of(work, struct iolog_flush_data, work); - + memset(&stream, 0, sizeof(stream)); stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; @@ -1036,7 +1038,7 @@ static int gz_work(struct submit_worker *sw, struct workqueue_work *work) ret = deflateInit(&stream, Z_DEFAULT_COMPRESSION); if (ret != Z_OK) { log_err("fio: failed to init gz stream\n"); - return 0; + goto err; } seq = ++data->log->chunk_seq; @@ -1096,13 +1098,7 @@ static int gz_work(struct submit_worker *sw, struct workqueue_work *work) ret = 0; done: - if (data->wait) { - pthread_mutex_lock(&data->lock); - data->done = 1; - pthread_cond_signal(&data->cv); - - drop_data_unlock(data); - } else + if (data->free) free(data); return ret; err: @@ -1115,6 +1111,16 @@ err: goto done; } +/* + * Invoked from our compress helper thread, when logging would have exceeded + * the specified memory limitation. Compresses the previously stored + * entries. + */ +static int gz_work_async(struct submit_worker *sw, struct workqueue_work *work) +{ + return gz_work(container_of(work, struct iolog_flush_data, work)); +} + static int gz_init_worker(struct submit_worker *sw) { struct thread_data *td = sw->wq->td; @@ -1131,17 +1137,17 @@ static int gz_init_worker(struct submit_worker *sw) } static struct workqueue_ops log_compress_wq_ops = { - .fn = gz_work, + .fn = gz_work_async, .init_worker_fn = gz_init_worker, - .nice = 1, + .nice = 1, }; -int iolog_compress_init(struct thread_data *td) +int iolog_compress_init(struct thread_data *td, struct sk_out *sk_out) { if (!(td->flags & TD_F_COMPRESS_LOG)) return 0; - workqueue_init(td, &td->log_compress_wq, &log_compress_wq_ops, 1); + workqueue_init(td, &td->log_compress_wq, &log_compress_wq_ops, 1, sk_out); return 0; } @@ -1157,10 +1163,11 @@ void iolog_compress_exit(struct thread_data *td) * Queue work item to compress the existing log entries. We reset the * current log to a small size, and reference the existing log in the * data that we queue for compression. Once compression has been done, - * this old log is freed. If called with wait == 1, will not return until - * the log compression has completed. + * this old log is freed. If called with finish == true, will not return + * until the log compression has completed, and will flush all previous + * logs too */ -int iolog_flush(struct io_log *log, int wait) +static int iolog_flush(struct io_log *log) { struct iolog_flush_data *data; @@ -1169,43 +1176,61 @@ int iolog_flush(struct io_log *log, int wait) return 1; data->log = log; + data->free = false; - data->samples = log->log; - data->nr_samples = log->nr_samples; - - log->nr_samples = 0; - log->max_samples = 128; - log->log = malloc(log->max_samples * log_entry_sz(log)); + while (!flist_empty(&log->io_logs)) { + struct io_logs *cur_log; - data->wait = wait; - if (data->wait) { - pthread_mutex_init(&data->lock, NULL); - pthread_cond_init(&data->cv, NULL); - data->done = 0; - data->refs = 2; - } + cur_log = flist_first_entry(&log->io_logs, struct io_logs, list); + flist_del_init(&cur_log->list); - workqueue_enqueue(&log->td->log_compress_wq, &data->work); + data->samples = cur_log->log; + data->nr_samples = cur_log->nr_samples; - if (wait) { - pthread_mutex_lock(&data->lock); - while (!data->done) - pthread_cond_wait(&data->cv, &data->lock); + cur_log->nr_samples = 0; + cur_log->max_samples = 0; + cur_log->log = NULL; - drop_data_unlock(data); + gz_work(data); } + free(data); return 0; } +int iolog_cur_flush(struct io_log *log, struct io_logs *cur_log) +{ + struct iolog_flush_data *data; + + data = malloc(sizeof(*data)); + if (!data) + return 1; + + data->log = log; + + data->samples = cur_log->log; + data->nr_samples = cur_log->nr_samples; + data->free = true; + + cur_log->nr_samples = cur_log->max_samples = 0; + cur_log->log = NULL; + + workqueue_enqueue(&log->td->log_compress_wq, &data->work); + return 0; +} #else -int iolog_flush(struct io_log *log, int wait) +static int iolog_flush(struct io_log *log) +{ + return 1; +} + +int iolog_cur_flush(struct io_log *log, struct io_logs *cur_log) { return 1; } -int iolog_compress_init(struct thread_data *td) +int iolog_compress_init(struct thread_data *td, struct sk_out *sk_out) { return 0; } @@ -1216,6 +1241,29 @@ void iolog_compress_exit(struct thread_data *td) #endif +struct io_logs *iolog_cur_log(struct io_log *log) +{ + if (flist_empty(&log->io_logs)) + return NULL; + + return flist_last_entry(&log->io_logs, struct io_logs, list); +} + +uint64_t iolog_nr_samples(struct io_log *iolog) +{ + struct flist_head *entry; + uint64_t ret = 0; + + flist_for_each(entry, &iolog->io_logs) { + struct io_logs *cur_log; + + cur_log = flist_entry(entry, struct io_logs, list); + ret += cur_log->nr_samples; + } + + return ret; +} + static int __write_log(struct thread_data *td, struct io_log *log, int try) { if (log) @@ -1224,29 +1272,74 @@ static int __write_log(struct thread_data *td, struct io_log *log, int try) return 0; } -static int write_iops_log(struct thread_data *td, int try) +static int write_iops_log(struct thread_data *td, int try, bool unit_log) { - return __write_log(td, td->iops_log, try); + int ret; + + if (per_unit_log(td->iops_log) != unit_log) + return 0; + + ret = __write_log(td, td->iops_log, try); + if (!ret) + td->iops_log = NULL; + + return ret; } -static int write_slat_log(struct thread_data *td, int try) +static int write_slat_log(struct thread_data *td, int try, bool unit_log) { - return __write_log(td, td->slat_log, try); + int ret; + + if (!unit_log) + return 0; + + ret = __write_log(td, td->slat_log, try); + if (!ret) + td->slat_log = NULL; + + return ret; } -static int write_clat_log(struct thread_data *td, int try) +static int write_clat_log(struct thread_data *td, int try, bool unit_log) { - return __write_log(td, td->clat_log, try); + int ret; + + if (!unit_log) + return 0; + + ret = __write_log(td, td->clat_log, try); + if (!ret) + td->clat_log = NULL; + + return ret; } -static int write_lat_log(struct thread_data *td, int try) +static int write_lat_log(struct thread_data *td, int try, bool unit_log) { - return __write_log(td, td->lat_log, try); + int ret; + + if (!unit_log) + return 0; + + ret = __write_log(td, td->lat_log, try); + if (!ret) + td->lat_log = NULL; + + return ret; } -static int write_bandw_log(struct thread_data *td, int try) +static int write_bandw_log(struct thread_data *td, int try, bool unit_log) { - return __write_log(td, td->bw_log, try); + int ret; + + if (per_unit_log(td->bw_log) != unit_log) + return 0; + + ret = __write_log(td, td->bw_log, try); + if (!ret) + td->bw_log = NULL; + + return ret; } enum { @@ -1261,7 +1354,7 @@ enum { struct log_type { unsigned int mask; - int (*fn)(struct thread_data *, int); + int (*fn)(struct thread_data *, int, bool); }; static struct log_type log_types[] = { @@ -1287,7 +1380,7 @@ static struct log_type log_types[] = { }, }; -void fio_writeout_logs(struct thread_data *td) +void td_writeout_logs(struct thread_data *td, bool unit_logs) { unsigned int log_mask = 0; unsigned int log_left = ALL_LOG_NR; @@ -1295,7 +1388,7 @@ void fio_writeout_logs(struct thread_data *td) old_state = td_bump_runstate(td, TD_FINISHING); - finalize_logs(td); + finalize_logs(td, unit_logs); while (log_left) { int prev_log_left = log_left; @@ -1305,7 +1398,7 @@ void fio_writeout_logs(struct thread_data *td) int ret; if (!(log_mask & lt->mask)) { - ret = lt->fn(td, log_left != 1); + ret = lt->fn(td, log_left != 1, unit_logs); if (!ret) { log_left--; log_mask |= lt->mask; @@ -1319,3 +1412,12 @@ void fio_writeout_logs(struct thread_data *td) td_restore_runstate(td, old_state); } + +void fio_writeout_logs(bool unit_logs) +{ + struct thread_data *td; + int i; + + for_each_td(td, i) + td_writeout_logs(td, unit_logs); +}