Commit 6f131e28 authored by Alessandro Rubini's avatar Alessandro Rubini

buffers/zio-buf-vmalloc.c: add a "merge-data" attribute, document it

The merge-data attribute tells the buffer to try a merge of a
newly-stored block with the previous one. When this is possible, the
buffer updates the previous block (nsamples, datalen) and releases the
new control immediately. This allows saving some memory without
breaking the ZIO data model. The feature only makes sense for input,
but there is no policy in place to enforce that.

When user space reads this new block, it will get attributes (and
timestamp) for the first data items, but all available items are
returned in this bigger block.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
Acked-by: 's avatarFederico Vaga <federico.vaga@gmail.com>
parent f36638ea
......@@ -34,9 +34,12 @@ struct zbk_instance {
struct zio_ffa *ffa;
void *data;
unsigned long size;
unsigned long flags;
};
#define to_zbki(bi) container_of(bi, struct zbk_instance, bi)
#define ZBK_FLAG_MERGE_DATA 1
static struct kmem_cache *zbk_slab;
......@@ -50,18 +53,43 @@ struct zbk_item {
};
#define to_item(block) container_of(block, struct zbk_item, block);
enum {
ZBK_ATTR_MERGE_DATA = ZIO_MAX_STD_ATTR,
};
static ZIO_ATTR_DEFINE_STD(ZIO_BUF, zbk_std_zattr) = {
ZIO_ATTR(zbuf, ZIO_ATTR_ZBUF_MAXKB, S_IRUGO | S_IWUGO, 0x0, 128),
};
static struct zio_attribute zbk_ext_attr[] = {
ZIO_ATTR_EXT("merge-data", S_IRUGO | S_IWUGO,
ZBK_ATTR_MERGE_DATA, 0),
};
static int zbk_conf_set(struct device *dev, struct zio_attribute *zattr,
uint32_t usr_val)
{
if (0) {
zattr->value = usr_val;
} else {
/* Temporarily, until I keep track of active maps */
return -EBUSY;
struct zio_bi *bi = to_zio_bi(dev);
struct zbk_instance *zbki = to_zbki(bi);
switch(zattr->id) {
case ZIO_ATTR_ZBUF_MAXKB:
if (0) {
zattr->value = usr_val;
} else {
/* Temporarily, until I keep track of active maps */
return -EBUSY;
}
break;
case ZBK_ATTR_MERGE_DATA:
printk("write merge data: %i\n", usr_val);
if (usr_val)
zbki->flags |= ZBK_FLAG_MERGE_DATA;
else
zbki->flags &= ~ZBK_FLAG_MERGE_DATA;
break;
default:
return -EINVAL;
}
return 0;
}
......@@ -121,6 +149,30 @@ static void zbk_free_block(struct zio_bi *bi, struct zio_block *block)
kmem_cache_free(zbk_slab, item);
}
/* An helper for store_block() if we are trying to merge data runs */
static void zbk_try_merge(struct zbk_instance *zbki, struct zbk_item *item)
{
struct zbk_item *prev;
struct zio_control *ctrl, *prevc;
/* Called while locked and already part of the list */
prev = list_entry(item->list.prev, struct zbk_item, list);
if (prev->begin + prev->len != item->begin)
return; /* no, thanks */
/* merge: remove from list, fix prev block, remove new control */
list_del(&item->list);
ctrl = zio_get_ctrl(&item->block);
prevc = zio_get_ctrl(&prev->block);
prev->len += item->len; /* for the allocator */
prev->block.datalen += item->block.datalen; /* for copying */
prevc->nsamples += ctrl->nsamples; /* meta information */
zio_free_control(ctrl);
kmem_cache_free(zbk_slab, item);
}
/* When write() stores the first block, we try pushing it */
static inline int __try_push(struct zio_bi *bi, struct zio_channel *chan,
struct zio_block *block)
......@@ -171,6 +223,8 @@ static int zbk_store_block(struct zio_bi *bi, struct zio_block *block)
}
if (pushed)
list_del(&item->list);
if (!first && zbki->flags & ZBK_FLAG_MERGE_DATA)
zbk_try_merge(zbki, item);
spin_unlock(&bi->lock);
/* if first input, awake user space */
......@@ -319,6 +373,8 @@ static struct zio_buffer_type zbk_buffer = {
.owner = THIS_MODULE,
.zattr_set = {
.std_zattr = zbk_std_zattr,
.ext_zattr = zbk_ext_attr,
.n_ext_attr = ARRAY_SIZE(zbk_ext_attr),
},
.s_op = &zbk_sysfs_ops,
.b_op = &zbk_buffer_ops,
......
......@@ -1404,31 +1404,27 @@ in @ref{fig:mmap}.
@end float
@sp 1
Another option, offered by a buffer called @i{circ} is sticking
several data blocks together to immediately release some control
structures. The user may choose this buffer if the application knows
An attribute of the @i{vmalloc} buffer, can turn it into a
real circular buffer: individual buffer instances can merge
(sticks together)
several data blocks, in order to immediately release some control
structures. The user may activate the attribute if the application knows
it won't need meta-data for every block: if you know you acquire at
1kHz, for example, time-stamping the first sample may be enough,
whereas further streaming is self-timed. This buffer doesn't break
the ZIO data model because whenever a new data block arrives, it is
whereas further streaming is self-timed. The attribute doesn't break
the ZIO data model because whenever a new data block arrives it is
stuck to the previous data by releasing the new control and increasing
the block size of the previous block; when a block enters an empty
buffer, its own control is preserved (but its @t{nsmaples} field may
be increased later, before the user reads the block). The @i{control +
buffer, its own control is preserved (but its own @t{nsmaples} field may
be increased later if another data blob is merged to it). The @i{control +
data} abstraction will thus continue working towards user space. This
buffer is shown in @ref{fig:circ}
situation is shown in @ref{fig:circ}.
@float Figure,fig:circ
@image{img/zio-buffer-data, 15cm, , the circular buffer and char devices, gif}
@end float
@sp 1
@c FIXME: merge circular buffer
This buffer is not yet merged to the official distribution at this point,
because we need to upgrade it and perform more testing to ensure there are
no bugs left.
@c ==========================================================================
@node User Space Utilities
@section User Space Utilities
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment