On 1/20/2018 1:29 AM, Muhammad Faiz wrote: > Help avoiding malloc-free cycles when allocating-freeing common > structures. > > Signed-off-by: Muhammad Faiz <mfc...@gmail.com> > --- > libavutil/staticpool.h | 117 > +++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 117 insertions(+) > create mode 100644 libavutil/staticpool.h > > diff --git a/libavutil/staticpool.h b/libavutil/staticpool.h > new file mode 100644 > index 0000000000..9c9b2784bc > --- /dev/null > +++ b/libavutil/staticpool.h > @@ -0,0 +1,117 @@ > +/* > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#ifndef AVUTIL_STATICPOOL_H > +#define AVUTIL_STATICPOOL_H > + > +#include <stdatomic.h> > +#include "avassert.h" > +#include "mem.h" > + > +/** > + * FF_STATICPOOL allocate memory without av_malloc if possible > + * @param size must be 2^n between 64 and 4096 > + */ > +#define FF_STATICPOOL_DECLARE(type, size) > \ > +typedef struct type##_StaticPoolWrapper { > \ > + type buf; > \ > + unsigned index; > \ > + atomic_uint next; > \ > +} type##_StaticPoolWrapper; > \ > + > \ > +static atomic_uint type##_staticpool_next; > \ > +static atomic_uint type##_staticpool_last; > \ > +static type##_StaticPoolWrapper type##_staticpool_table[size]; > \ > + > \ > +static type *type##_staticpool_malloc(void) > \ > +{ > \ > + unsigned val, index, serial, new_val; > \ > + > \ > + av_assert0((size) >= 64 && (size) <= 4096 && !((size) & ((size) - 1))); > \ > + > \ > + /* use serial, avoid spinlock */ > \ > + /* acquire, so we don't get stalled table[index].next */ > \ > + val = atomic_load_explicit(&type##_staticpool_next, > memory_order_acquire); \ > + do { > \ > + index = val & ((size) - 1); > \ > + serial = val & ~((size) - 1); > \ > + new_val = atomic_load_explicit(&type##_staticpool_table[index].next, > memory_order_relaxed) | (serial + (size)); \ > + } while > (!atomic_compare_exchange_strong_explicit(&type##_staticpool_next, &val, > new_val, \
The wrappers for atomic_compare_exchange_* in the compat folder are not really working and fixing them is supposedly not trivial, so this will only work with GCC and Clang but not with for example MSVC or SunCC. Can you implement this using mutexes instead, or otherwise avoid using atomic_compare_exchange_*? You can even use static mutex initialization now for all targets, and not just native pthreads. > + memory_order_acquire, > memory_order_acquire)); \ > + > \ > + index = val & ((size) - 1); > \ > + if (index) > \ > + return &type##_staticpool_table[index].buf; > \ > + > \ > + index = atomic_fetch_add_explicit(&type##_staticpool_last, 1, > memory_order_relaxed) + 1; \ > + if (index < (size)) { > \ > + type##_staticpool_table[index].index = index; > \ > + return &type##_staticpool_table[index].buf; > \ > + } > \ > + > \ > + atomic_fetch_add_explicit(&type##_staticpool_last, -1, > memory_order_relaxed); \ > + return av_malloc(sizeof(type)); > \ > +} > \ > + > \ > +static inline type *type##_staticpool_mallocz(void) > \ > +{ > \ > + type *ptr = type##_staticpool_malloc(); > \ > + if (ptr) > \ > + memset(ptr, 0, sizeof(*ptr)); > \ > + return ptr; > \ > +} > \ > + > \ > +static void type##_staticpool_free(type *ptr) > \ > +{ > \ > + type##_StaticPoolWrapper *entry = (type##_StaticPoolWrapper *) ptr; > \ > + unsigned val, serial, index, new_val; > \ > + > \ > + if ((uintptr_t)ptr <= (uintptr_t)(type##_staticpool_table) || > \ > + (uintptr_t)ptr >= (uintptr_t)(type##_staticpool_table + size)) { > \ > + av_free(ptr); > \ > + return; > \ > + } > \ > + > \ > + if (CONFIG_MEMORY_POISONING) > \ > + memset(&entry->buf, FF_MEMORY_POISON, sizeof(entry->buf)); > \ > + > \ > + val = atomic_load_explicit(&type##_staticpool_next, > memory_order_relaxed); \ > + do { > \ > + index = val & ((size) - 1); > \ > + serial = val & ~((size) - 1); > \ > + atomic_store_explicit(&entry->next, index, memory_order_relaxed); > \ > + new_val = entry->index | (serial + (size)); > \ > + } while > (!atomic_compare_exchange_strong_explicit(&type##_staticpool_next, &val, > new_val, \ > + memory_order_release, > memory_order_relaxed)); \ > +} > \ > + > \ > +static inline void type##_staticpool_freep(type **ptr) > \ > +{ > \ > + if (ptr) { > \ > + type##_staticpool_free(*ptr); > \ > + *ptr = NULL; > \ > + } > \ > +} > \ > +/* FF_STATICPOOL_DECLARE */ > + > +#define FF_STATICPOOL_MALLOC(type) type##_staticpool_malloc() > +#define FF_STATICPOOL_MALLOCZ(type) type##_staticpool_mallocz() > +#define FF_STATICPOOL_FREE(type, v) type##_staticpool_free(v) > +#define FF_STATICPOOL_FREEP(type, v) type##_staticpool_freep(v) > + > +#endif > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel