From 6f131e284178ad3aaf9dd348adce7c6fc495fe12 Mon Sep 17 00:00:00 2001 From: Alessandro Rubini <rubini@gnudd.com> Date: Fri, 4 Jan 2013 19:09:29 +0100 Subject: [PATCH] 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 <rubini@gnudd.com> Acked-by: Federico Vaga <federico.vaga@gmail.com> --- buffers/zio-buf-vmalloc.c | 66 ++++++++++++++++++++++++++++++++++++--- doc/zio-manual.in | 24 ++++++-------- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/buffers/zio-buf-vmalloc.c b/buffers/zio-buf-vmalloc.c index 636eac0..1985c4d 100644 --- a/buffers/zio-buf-vmalloc.c +++ b/buffers/zio-buf-vmalloc.c @@ -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, diff --git a/doc/zio-manual.in b/doc/zio-manual.in index 2d84e70..586f1e6 100644 --- a/doc/zio-manual.in +++ b/doc/zio-manual.in @@ -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 -- GitLab