evas/textblock: optmize textblock format parsing.

Summary:
 textblock format parsing creates/delets eina_TempStr for each
 token. Eina_TempStr is even worse than malloc/free because it also
 takes a lock/unlock along with malloc/free each time we create it.
 Just use a stack bufefr and create string in it if the string is too big
 then it will fall back to heap which is anyway we are doing right now.

 Tested this in Tizen List view the number of allocation reduced by 16000.

Reviewers: Hermet, ali.alzyod, woohyun

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D9534
This commit is contained in:
subhransu mohanty 2019-08-09 17:36:35 +09:00 committed by Hermet Park
parent 1b94d90d53
commit 9e3a046661
1 changed files with 97 additions and 18 deletions

View File

@ -1728,13 +1728,13 @@ _format_command_shutdown(void)
* @param[in] src the source string - Should not be NULL.
*/
static int
_format_clean_param(Eina_Tmpstr *s)
_format_clean_param(char *s)
{
Eina_Tmpstr *ss;
char *ss;
char *ds;
int len = 0;
ds = (char*) s;
ds = s;
for (ss = s; *ss; ss++, ds++, len++)
{
if ((*ss == '\\') && *(ss + 1)) ss++;
@ -1752,10 +1752,10 @@ _format_clean_param(Eina_Tmpstr *s)
* @param obj the evas object - should not be NULL.
* @param fmt The format to populate - should not be NULL.
* @param[in] cmd the command to process, should be stringshared.
* @param[in] param the parameter of the command.
* @param[in] param the parameter of the command. may modify the string.
*/
static void
_format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const char *cmd, Eina_Tmpstr *param)
_format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const char *cmd, char *param)
{
int len;
@ -2847,6 +2847,77 @@ _format_command(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const ch
}
}
/*
* @internal
* just to create a constant without using marco
* 2 cacheline is enough for the string we parse
* usually color or color_class strings.
* reduce it if this number is too high.
*/
enum _Internal{ ALLOCATOR_SIZE = 120 };
/*
* @internal
* A simple stack allocator which first
* tries to create a string in the stack (buffer
* it holds). if the string size is bigger than its
* buffer capacity it will fall back to creating the
* string on heap.
* USAGE :
* Allocator a;
* _allocator_init(&a);
* _allocator_make_string(&a, "hello world", 11);
* ... //use the string
* ._allocator_reset(&a);
* Always call _allocator_reset() after
* you done with the string.
*/
typedef struct _Allocator
{
char stack[ALLOCATOR_SIZE];
char *heap;
} Allocator;
static inline void
_allocator_init(Allocator* allocator)
{
if (allocator) allocator->heap = NULL;
}
static inline void
_allocator_reset(Allocator* allocator)
{
if (allocator && allocator->heap)
{
free(allocator->heap);
allocator->heap = NULL;
}
}
static char *
_allocator_make_string(Allocator* allocator, const char* str, size_t size)
{
if (!allocator) return NULL;
if (!size) return NULL;
if (size + 1 < ALLOCATOR_SIZE)
{
memcpy(allocator->stack, str, size);
allocator->stack[size] = '\0';
return allocator->stack;
}
//fallback to heap
if (allocator->heap) free(allocator->heap);
allocator->heap = malloc(size + 1);
if (!allocator->heap) return NULL;
memcpy(allocator->heap, str, size);
allocator->heap[size] = '\0';
return allocator->heap;
}
/**
* @internal
* Returns @c EINA_TRUE if the item is a format parameter, @c EINA_FALSE
@ -2872,15 +2943,15 @@ _format_is_param(const char *item)
* @param[out] key where to store the key at - Not NULL.
* @param[out] val where to store the value at - Not NULL.
*/
static void
_format_param_parse(const char *item, const char **key, Eina_Tmpstr **val)
static Eina_Bool
_format_param_parse(const char *item, const char **key, char **val, Allocator *allocator)
{
const char *start, *end;
char *tmp, *s, *d;
size_t len;
start = strchr(item, '=');
if (!start) return ;
if (!start) return EINA_FALSE;
*key = eina_stringshare_add_length(item, start - item);
start++; /* Advance after the '=' */
/* If we can find a quote as the first non-space char,
@ -2906,7 +2977,7 @@ _format_param_parse(const char *item, const char **key, Eina_Tmpstr **val)
if (end) len = end - start;
else len = strlen(start);
tmp = (char*) eina_tmpstr_add_length(start, len);
tmp = _allocator_make_string(allocator, start, len);
if (!tmp) goto end;
for (d = tmp, s = tmp; *s; s++)
@ -2921,6 +2992,8 @@ _format_param_parse(const char *item, const char **key, Eina_Tmpstr **val)
end:
*val = tmp;
return EINA_TRUE;
}
/**
@ -2989,22 +3062,23 @@ _format_fill(Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt, const char
/* get rid of any spaces at the start of the string */
while (*s == ' ') s++;
Allocator allocator;
_allocator_init(&allocator);
while ((item = _format_parse(&s)))
{
if (_format_is_param(item))
const char *key = NULL;
char *val = NULL;
if (_format_param_parse(item, &key, &val, &allocator))
{
const char *key = NULL;
Eina_Tmpstr *val = NULL;
_format_param_parse(item, &key, &val);
if ((key) && (val)) _format_command(eo_obj, fmt, key, val);
eina_stringshare_del(key);
eina_tmpstr_del(val);
}
else
{
/* immediate - not handled here */
}
_allocator_reset(&allocator);
}
}
@ -3715,12 +3789,17 @@ static void
_layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item)
{
const char *key = NULL;
Eina_Tmpstr *val = NULL;
char *val = NULL;
Allocator allocator;
_allocator_init(&allocator);
_format_param_parse(item, &key, &val);
_format_param_parse(item, &key, &val, &allocator);
if ((key) && (val)) _format_command(c->obj, fmt, key, val);
if (key) eina_stringshare_del(key);
if (val) eina_tmpstr_del(val);
_allocator_reset(&allocator);
c->align = fmt->halign;
c->align_auto = fmt->halign_auto;
c->marginl = fmt->margin.l;