130 lines
2.1 KiB
C
130 lines
2.1 KiB
C
#include "fio.h"
|
|
#include "mutex.h"
|
|
#include "smalloc.h"
|
|
#include "flist.h"
|
|
|
|
struct fio_flow {
|
|
unsigned int refs;
|
|
struct flist_head list;
|
|
unsigned int id;
|
|
long long int flow_counter;
|
|
};
|
|
|
|
static struct flist_head *flow_list;
|
|
static struct fio_mutex *flow_lock;
|
|
|
|
int flow_threshold_exceeded(struct thread_data *td)
|
|
{
|
|
struct fio_flow *flow = td->flow;
|
|
int sign;
|
|
|
|
if (!flow)
|
|
return 0;
|
|
|
|
sign = td->o.flow > 0 ? 1 : -1;
|
|
if (sign * flow->flow_counter > td->o.flow_watermark) {
|
|
if (td->o.flow_sleep) {
|
|
io_u_quiesce(td);
|
|
usleep(td->o.flow_sleep);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* No synchronization needed because it doesn't
|
|
* matter if the flow count is slightly inaccurate */
|
|
flow->flow_counter += td->o.flow;
|
|
return 0;
|
|
}
|
|
|
|
static struct fio_flow *flow_get(unsigned int id)
|
|
{
|
|
struct fio_flow *flow = NULL;
|
|
struct flist_head *n;
|
|
|
|
if (!flow_lock)
|
|
return NULL;
|
|
|
|
fio_mutex_down(flow_lock);
|
|
|
|
flist_for_each(n, flow_list) {
|
|
flow = flist_entry(n, struct fio_flow, list);
|
|
if (flow->id == id)
|
|
break;
|
|
|
|
flow = NULL;
|
|
}
|
|
|
|
if (!flow) {
|
|
flow = smalloc(sizeof(*flow));
|
|
if (!flow) {
|
|
fio_mutex_up(flow_lock);
|
|
return NULL;
|
|
}
|
|
flow->refs = 0;
|
|
INIT_FLIST_HEAD(&flow->list);
|
|
flow->id = id;
|
|
flow->flow_counter = 0;
|
|
|
|
flist_add_tail(&flow->list, flow_list);
|
|
}
|
|
|
|
flow->refs++;
|
|
fio_mutex_up(flow_lock);
|
|
return flow;
|
|
}
|
|
|
|
static void flow_put(struct fio_flow *flow)
|
|
{
|
|
if (!flow_lock)
|
|
return;
|
|
|
|
fio_mutex_down(flow_lock);
|
|
|
|
if (!--flow->refs) {
|
|
flist_del(&flow->list);
|
|
sfree(flow);
|
|
}
|
|
|
|
fio_mutex_up(flow_lock);
|
|
}
|
|
|
|
void flow_init_job(struct thread_data *td)
|
|
{
|
|
if (td->o.flow)
|
|
td->flow = flow_get(td->o.flow_id);
|
|
}
|
|
|
|
void flow_exit_job(struct thread_data *td)
|
|
{
|
|
if (td->flow) {
|
|
flow_put(td->flow);
|
|
td->flow = NULL;
|
|
}
|
|
}
|
|
|
|
void flow_init(void)
|
|
{
|
|
flow_list = smalloc(sizeof(*flow_list));
|
|
if (!flow_list) {
|
|
log_err("fio: smalloc pool exhausted\n");
|
|
return;
|
|
}
|
|
|
|
flow_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
|
|
if (!flow_lock) {
|
|
log_err("fio: failed to allocate flow lock\n");
|
|
sfree(flow_list);
|
|
return;
|
|
}
|
|
|
|
INIT_FLIST_HEAD(flow_list);
|
|
}
|
|
|
|
void flow_exit(void)
|
|
{
|
|
if (flow_lock)
|
|
fio_mutex_remove(flow_lock);
|
|
if (flow_list)
|
|
sfree(flow_list);
|
|
}
|