summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-10-21 20:06:23 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-10-21 20:16:06 +0900
commit7cc41473a30236b11f0c7b57425e273d2874e30e (patch)
tree21f0f28ef791e15fa82fc61711ef330f4b1cf86d
parentb7d2f4f81468b90a09c977dbefd6f75908719ab9 (diff)
efl - eo - massively improve eo cal resolv and data scope get with cache
BEWARE! this breaks eo ABI. _eo_call_resolve and _eo_data_scope_get are 2 of the biggest cpu users in eo. they easily consume like 10-15% cpu between them on tests that drive a lot of api - like simply scrolling a genlist around. this is a lot of overhead for efl. this fixes that to make them far leaner. In fact this got an overall 10% cpu usage drop and that includes all of the actual rendering, and code work, so this would drop the eo overhead of these functions incredibly low. using this much cpu just on doing call marshalling is a bug and thus - this is a fix, but ... with an abi break to boot. more abi breaks may happen before release to try and get them all in this release so we don't have to do them again later. note i actually tested 4, 3, 2, and 1 cache slots, and 1 was the fastest. 2 was very close behind and then it got worse. all were better than with no cache though. benchmark test method: export ELM_ENGINE=gl export ELM_TEST_AUTOBOUNCE=1 while [ 1 ]; do sync; sync; sync; time elementary_test -to genlist; sleep 1; done take the 2nd to the 8th results (7 runs) and total up system and user time. copmpare this to the same without the cache. with the cache cpu time used is 90.3% of the cpu time used without - thus a win. at least in my tests. @fix
-rw-r--r--src/lib/eo/Eo.h55
-rw-r--r--src/lib/eo/eo.c68
2 files changed, 90 insertions, 33 deletions
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 6ddc2381a0..a16c872b16 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -437,26 +437,39 @@ EAPI Eina_Bool eo_shutdown(void);
437typedef struct _Eo_Op_Call_Data 437typedef struct _Eo_Op_Call_Data
438{ 438{
439 Eo *obj; 439 Eo *obj;
440 Eo_Class *klass; // remove this not necessary in Eo_Hook_Call
441 void *func; 440 void *func;
442 void *data; 441 void *data;
443} Eo_Op_Call_Data; 442} Eo_Op_Call_Data;
444 443
445typedef void (*Eo_Hook_Call)(const Eo_Class *klass_id, const Eo *obj, const char *eo_func_name, void *func, ...); 444#define EO_CALL_CACHE_SIZE 1
446 445
447EAPI extern Eo_Hook_Call eo_hook_call_pre; 446typedef struct _Eo_Call_Cache_Index
448EAPI extern Eo_Hook_Call eo_hook_call_post; 447{
448 const void *klass;
449} Eo_Call_Cache_Index;
449 450
450// to pass the internal function call to EO_FUNC_BODY (as Func parameter) 451typedef struct _Eo_Call_Cache_Entry
451#define EO_FUNC_CALL(...) __VA_ARGS__ 452{
453 const void *func;
454} Eo_Call_Cache_Entry;
455
456typedef struct _Eo_Call_Cache_Off
457{
458 int off;
459} Eo_Call_Cache_Off;
452 460
453#define EO_HOOK_CALL_PREPARE(Hook, FuncName) \ 461typedef struct _Eo_Call_Cache
454 if (Hook) \ 462{
455 Hook(___call.klass, ___call.obj, FuncName, ___call.func); 463 Eo_Call_Cache_Index index[EO_CALL_CACHE_SIZE];
464 Eo_Call_Cache_Entry entry[EO_CALL_CACHE_SIZE];
465 Eo_Call_Cache_Off off [EO_CALL_CACHE_SIZE];
466#if EO_CALL_CACHE_SIZE > 1
467 int next_slot;
468#endif
469} Eo_Call_Cache;
456 470
457#define EO_HOOK_CALL_PREPAREV(Hook, FuncName, ...) \ 471// to pass the internal function call to EO_FUNC_BODY (as Func parameter)
458 if (Hook) \ 472#define EO_FUNC_CALL(...) __VA_ARGS__
459 Hook(___call.klass, ___call.obj, FuncName, ___call.func, __VA_ARGS__);
460 473
461#ifndef _WIN32 474#ifndef _WIN32
462# define EO_FUNC_COMMON_OP_FUNC(Name) ((const void *) Name) 475# define EO_FUNC_COMMON_OP_FUNC(Name) ((const void *) Name)
@@ -466,11 +479,13 @@ EAPI extern Eo_Hook_Call eo_hook_call_post;
466 479
467// cache OP id, get real fct and object data then do the call 480// cache OP id, get real fct and object data then do the call
468#define EO_FUNC_COMMON_OP(Name, DefRet) \ 481#define EO_FUNC_COMMON_OP(Name, DefRet) \
469 Eo_Op_Call_Data ___call; \ 482 static Eo_Call_Cache ___callcache = { 0 }; \
470 static Eo_Op ___op = EO_NOOP; \ 483 static Eo_Op ___op = EO_NOOP; \
484 Eo_Op_Call_Data ___call; \
471 if (___op == EO_NOOP) \ 485 if (___op == EO_NOOP) \
472 ___op = _eo_api_op_id_get(EO_FUNC_COMMON_OP_FUNC(Name)); \ 486 ___op = _eo_api_op_id_get(EO_FUNC_COMMON_OP_FUNC(Name)); \
473 if (!_eo_call_resolve(#Name, ___op, &___call, __FILE__, __LINE__)) return DefRet; \ 487 if (!_eo_call_resolve(#Name, ___op, &___call, &___callcache, \
488 __FILE__, __LINE__)) return DefRet; \
474 _Eo_##Name##_func _func_ = (_Eo_##Name##_func) ___call.func; \ 489 _Eo_##Name##_func _func_ = (_Eo_##Name##_func) ___call.func; \
475 490
476// to define an EAPI function 491// to define an EAPI function
@@ -481,9 +496,7 @@ EAPI extern Eo_Hook_Call eo_hook_call_post;
481 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \ 496 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data); \
482 Ret _r; \ 497 Ret _r; \
483 EO_FUNC_COMMON_OP(Name, DefRet); \ 498 EO_FUNC_COMMON_OP(Name, DefRet); \
484 EO_HOOK_CALL_PREPARE(eo_hook_call_pre, #Name); \
485 _r = _func_(___call.obj, ___call.data); \ 499 _r = _func_(___call.obj, ___call.data); \
486 EO_HOOK_CALL_PREPARE(eo_hook_call_post, #Name); \
487 return _r; \ 500 return _r; \
488 } 501 }
489 502
@@ -493,9 +506,7 @@ EAPI extern Eo_Hook_Call eo_hook_call_post;
493 { \ 506 { \
494 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \ 507 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data); \
495 EO_FUNC_COMMON_OP(Name, ); \ 508 EO_FUNC_COMMON_OP(Name, ); \
496 EO_HOOK_CALL_PREPARE(eo_hook_call_pre, #Name); \
497 _func_(___call.obj, ___call.data); \ 509 _func_(___call.obj, ___call.data); \
498 EO_HOOK_CALL_PREPARE(eo_hook_call_post, #Name); \
499 } 510 }
500 511
501#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) \ 512#define EO_FUNC_BODYV(Name, Ret, DefRet, Arguments, ...) \
@@ -505,9 +516,7 @@ EAPI extern Eo_Hook_Call eo_hook_call_post;
505 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ 516 typedef Ret (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \
506 Ret _r; \ 517 Ret _r; \
507 EO_FUNC_COMMON_OP(Name, DefRet); \ 518 EO_FUNC_COMMON_OP(Name, DefRet); \
508 EO_HOOK_CALL_PREPAREV(eo_hook_call_pre, #Name, Arguments); \
509 _r = _func_(___call.obj, ___call.data, Arguments); \ 519 _r = _func_(___call.obj, ___call.data, Arguments); \
510 EO_HOOK_CALL_PREPAREV(eo_hook_call_post, #Name, Arguments); \
511 return _r; \ 520 return _r; \
512 } 521 }
513 522
@@ -517,9 +526,7 @@ EAPI extern Eo_Hook_Call eo_hook_call_post;
517 { \ 526 { \
518 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \ 527 typedef void (*_Eo_##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \
519 EO_FUNC_COMMON_OP(Name, ); \ 528 EO_FUNC_COMMON_OP(Name, ); \
520 EO_HOOK_CALL_PREPAREV(eo_hook_call_pre, #Name, Arguments); \
521 _func_(___call.obj, ___call.data, Arguments); \ 529 _func_(___call.obj, ___call.data, Arguments); \
522 EO_HOOK_CALL_PREPAREV(eo_hook_call_post, #Name, Arguments); \
523 } 530 }
524 531
525#ifndef _WIN32 532#ifndef _WIN32
@@ -537,7 +544,7 @@ EAPI extern Eo_Hook_Call eo_hook_call_post;
537EAPI Eo_Op _eo_api_op_id_get(const void *api_func); 544EAPI Eo_Op _eo_api_op_id_get(const void *api_func);
538 545
539// gets the real function pointer and the object data 546// gets the real function pointer and the object data
540EAPI Eina_Bool _eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, const char *file, int line); 547EAPI Eina_Bool _eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, Eo_Call_Cache *callcache, const char *file, int line);
541 548
542// start of eo_do barrier, gets the object pointer and ref it, put it on the stask 549// start of eo_do barrier, gets the object pointer and ref it, put it on the stask
543 EAPI Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, void *eo_stack); 550 EAPI Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, void *eo_stack);
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 34713f32c9..b147ba56fd 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -243,9 +243,6 @@ _eo_kls_itr_next(const _Eo_Class *orig_kls, const _Eo_Class *cur_klass, Eo_Op op
243 243
244/************************************ EO ************************************/ 244/************************************ EO ************************************/
245 245
246EAPI Eo_Hook_Call eo_hook_call_pre = NULL;
247EAPI Eo_Hook_Call eo_hook_call_post = NULL;
248
249#define EO_INVALID_DATA (void *) -1 246#define EO_INVALID_DATA (void *) -1
250// 1024 entries == 16k or 32k (32 or 64bit) for eo call stack. that's 1023 247// 1024 entries == 16k or 32k (32 or 64bit) for eo call stack. that's 1023
251// imbricated/recursive calls it can handle before barfing. i'd say that's ok 248// imbricated/recursive calls it can handle before barfing. i'd say that's ok
@@ -524,11 +521,13 @@ _eo_do_end(void *eo_stack)
524 _eo_call_stack_resize(stack, EINA_FALSE); 521 _eo_call_stack_resize(stack, EINA_FALSE);
525} 522}
526 523
524#define EO_CALL_RESOLVE_CACHE 1
525
527EAPI Eina_Bool 526EAPI Eina_Bool
528_eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, const char *file, int line) 527_eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, Eo_Call_Cache *callcache, const char *file, int line)
529{ 528{
530 Eo_Stack_Frame *fptr; 529 Eo_Stack_Frame *fptr;
531 const _Eo_Class *klass; 530 const _Eo_Class *klass, *inputklass;
532 const op_type_funcs *func; 531 const op_type_funcs *func;
533 Eina_Bool is_obj; 532 Eina_Bool is_obj;
534 533
@@ -539,7 +538,7 @@ _eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, c
539 538
540 is_obj = !_eo_is_a_class(fptr->eo_id); 539 is_obj = !_eo_is_a_class(fptr->eo_id);
541 540
542 klass = (is_obj) ? fptr->o.obj->klass : fptr->o.kls; 541 inputklass = klass = (is_obj) ? fptr->o.obj->klass : fptr->o.kls;
543 542
544 if (op == EO_NOOP) 543 if (op == EO_NOOP)
545 { 544 {
@@ -550,6 +549,43 @@ _eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, c
550 return EINA_FALSE; 549 return EINA_FALSE;
551 } 550 }
552 551
552#ifdef EO_CALL_RESOLVE_CACHE
553 if (!fptr->cur_klass)
554 {
555# if EO_CALL_CACHE_SIZE > 1
556 int i;
557
558 for (i = 0; i < EO_CALL_CACHE_SIZE; i++)
559# else
560 const int i = 0;
561# endif
562 {
563 if ((const void *)inputklass == callcache->index[i].klass)
564 {
565 func = (const op_type_funcs *)callcache->entry[i].func;
566 call->func = func->func;
567 if (is_obj)
568 {
569 call->obj = (Eo *)fptr->eo_id;
570 if (func->src == fptr->o.obj->klass)
571 {
572 if (fptr->obj_data == EO_INVALID_DATA)
573 fptr->obj_data = (char *)fptr->o.obj + callcache->off[i].off;
574 call->data = fptr->obj_data;
575 }
576 else
577 call->data = (char *)fptr->o.obj + callcache->off[i].off;
578 }
579 else
580 {
581 call->data = NULL;
582 }
583 return EINA_TRUE;
584 }
585 }
586 }
587#endif
588
553 /* If we have a current class, we need to itr to the next. */ 589 /* If we have a current class, we need to itr to the next. */
554 if (fptr->cur_klass) 590 if (fptr->cur_klass)
555 { 591 {
@@ -571,7 +607,6 @@ _eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, c
571 if (EINA_LIKELY(func->func && func->src)) 607 if (EINA_LIKELY(func->func && func->src))
572 { 608 {
573 call->func = func->func; 609 call->func = func->func;
574 call->klass = _eo_class_id_get(klass);
575 610
576 if (is_obj) 611 if (is_obj)
577 { 612 {
@@ -588,10 +623,26 @@ _eo_call_resolve(const char *func_name, const Eo_Op op, Eo_Op_Call_Data *call, c
588 } 623 }
589 else 624 else
590 { 625 {
591 call->obj = call->klass;
592 call->data = NULL; 626 call->data = NULL;
593 } 627 }
594 628
629#ifdef EO_CALL_RESOLVE_CACHE
630 if (!fptr->cur_klass)
631 {
632# if EO_CALL_CACHE_SIZE > 1
633 const int slot = callcache->next_slot;
634# else
635 const int slot = 0;
636# endif
637 callcache->index[slot].klass = (const void *)inputklass;
638 callcache->entry[slot].func = (const void *)func;
639 callcache->off[slot].off = (int)((long)((char *)call->data - (char *)fptr->o.obj));
640# if EO_CALL_CACHE_SIZE > 1
641 callcache->next_slot = (slot + 1) % EO_CALL_CACHE_SIZE;
642# endif
643 }
644#endif
645
595 return EINA_TRUE; 646 return EINA_TRUE;
596 } 647 }
597 648
@@ -623,7 +674,6 @@ end:
623 if (EINA_LIKELY(func->func && func->src)) 674 if (EINA_LIKELY(func->func && func->src))
624 { 675 {
625 call->obj = _eo_id_get(emb_obj); 676 call->obj = _eo_id_get(emb_obj);
626 call->klass = _eo_class_id_get(emb_obj->klass);
627 call->func = func->func; 677 call->func = func->func;
628 call->data = _eo_data_scope_get(emb_obj, func->src); 678 call->data = _eo_data_scope_get(emb_obj, func->src);
629 679