diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index a92b758de1..0fb2061907 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am @@ -88,7 +88,8 @@ lib/eina/eina_inline_unicode.x \ lib/eina/eina_thread_queue.h \ lib/eina/eina_matrix.h \ lib/eina/eina_quad.h \ -lib/eina/eina_crc.h +lib/eina/eina_crc.h \ +lib/eina/eina_evlog.h lib_eina_libeina_la_SOURCES = \ lib/eina/eina_abi.c \ @@ -154,7 +155,8 @@ lib/eina/eina_strbuf_common.h \ lib/eina/eina_thread_queue.c \ lib/eina/eina_matrix.c \ lib/eina/eina_quad.c \ -lib/eina/eina_crc.c +lib/eina/eina_crc.c \ +lib/eina/eina_evlog.c # Will be back for developper after 1.2 # lib/eina/eina_model.c \ diff --git a/src/bin/efl/efl_debug.c b/src/bin/efl/efl_debug.c index 461238d35d..6a65178a7f 100644 --- a/src/bin/efl/efl_debug.c +++ b/src/bin/efl/efl_debug.c @@ -44,7 +44,6 @@ _server_add(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_Event_Server { send_svr(svr, "LIST", NULL, 0); expect = "CLST"; - printf("send... expect %s\n", expect); } else if ((!strcmp(my_argv[i], "pon")) && (i < (my_argc - 2))) @@ -68,6 +67,26 @@ _server_add(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_Event_Server send_svr(svr, "PLOF", tmp, sizeof(tmp)); ecore_main_loop_quit(); } + else if ((!strcmp(my_argv[i], "evlogon")) && + (i < (my_argc - 1))) + { + unsigned char tmp[4]; + int pid = atoi(my_argv[i + 1]); + i++; + store_val(tmp, 0, pid); + send_svr(svr, "EVON", tmp, sizeof(tmp)); + ecore_main_loop_quit(); + } + else if ((!strcmp(my_argv[i], "evlogoff")) && + (i < (my_argc - 1))) + { + unsigned char tmp[4]; + int pid = atoi(my_argv[i + 1]); + i++; + store_val(tmp, 0, pid); + send_svr(svr, "EVOF", tmp, sizeof(tmp)); + ecore_main_loop_quit(); + } } return ECORE_CALLBACK_RENEW; } diff --git a/src/bin/efl/efl_debugd.c b/src/bin/efl/efl_debugd.c index b64747f63d..3cfe65d9f6 100644 --- a/src/bin/efl/efl_debugd.c +++ b/src/bin/efl/efl_debugd.c @@ -8,6 +8,11 @@ struct _Client unsigned char *buf; unsigned int buf_size; + Ecore_Timer *evlog_fetch_timer; + int evlog_on; + FILE *evlog_file; + int evlog_inset; + int version; pid_t pid; }; @@ -29,6 +34,14 @@ _client_pid_find(int pid) return NULL; } +static Eina_Bool +_cb_evlog(void *data) +{ + Client *c = data; + send_cli(c->client, "EVLG", NULL, 0); + return EINA_TRUE; +} + static void _do(Client *c, char *op, unsigned char *d, int size) { @@ -84,6 +97,91 @@ _do(Client *c, char *op, unsigned char *d, int size) send_cli(c2->client, "PLOF", NULL, 0); } } + else if (!strcmp(op, "EVON")) + { + int pid; + fetch_val(pid, d, 0); + if ((c2 = _client_pid_find(pid))) + { + c2->evlog_on++; + if (c2->evlog_on == 1) + { + char buf[4096]; + + send_cli(c2->client, "EVON", NULL, 0); + c2->evlog_fetch_timer = ecore_timer_add(0.2, _cb_evlog, c2); + snprintf(buf, sizeof(buf), "%s/efl_debug_evlog-%i.txt", + getenv("HOME"), c->pid); + c2->evlog_file = fopen(buf, "w"); + c->evlog_inset = 0; + } + } + } + else if (!strcmp(op, "EVOF")) + { + int pid; + fetch_val(pid, d, 0); + if ((c2 = _client_pid_find(pid))) + { + c2->evlog_on--; + if (c2->evlog_on == 0) + { + send_cli(c2->client, "EVOF", NULL, 0); + if (c2->evlog_fetch_timer) + { + ecore_timer_del(c2->evlog_fetch_timer); + c2->evlog_fetch_timer = NULL; + } + if (c2->evlog_file) + { + fclose(c2->evlog_file); + c2->evlog_file = NULL; + } + } + else if (c2->evlog_on < 0) + c2->evlog_on = 0; + } + } + else if (!strcmp(op, "EVLG")) + { +// unsigned int *overflow = (unsigned int *)(d + 0); +// unsigned int *stolen = (unsigned int *)(d + 4); + unsigned char *end = d + size; + unsigned char *p = d + 8; + char *event_str, *detail_str; + Eina_Evlog_Item *item; + int i, inset; + + printf("EVLG!!!! %i\n", size); + inset = c->evlog_inset; + if (c->evlog_file) + { + printf(" have out file\n"); + while (p < end) + { + item = (Eina_Evlog_Item *)p; + printf(" have item %p\n", p); + if ((item->event_next > item->detail_offset) && + ((p + item->event_next) < end)) + { + detail_str = ""; + event_str = (char *)(p + item->event_offset); + if (event_str[0] == '+') inset++; + if (item->detail_offset) + detail_str = (char *)(p + item->detail_offset); + for (i = 0; i < inset; i++) fprintf(c->evlog_file, " "); + fprintf(c->evlog_file, + "%1.10f [%s] %1.10f 0x%llx 0x%llx %s\n", + item->tim, event_str, item->srctim, + item->thread, item->obj, + detail_str); + if (event_str[0] == '-') inset--; + } + p += item->event_next; + } + } + c->evlog_inset = inset; + } } static Eina_Bool @@ -106,6 +204,16 @@ _client_del(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_Event_Client if (c) { clients = eina_list_remove(clients, c); + if (c->evlog_fetch_timer) + { + ecore_timer_del(c->evlog_fetch_timer); + c->evlog_fetch_timer = NULL; + } + if (c->evlog_file) + { + fclose(c->evlog_file); + c->evlog_file = NULL; + } free(c); } return ECORE_CALLBACK_RENEW; diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c index 75dc9a6afd..2c772e4b9a 100644 --- a/src/lib/ecore/ecore_anim.c +++ b/src/lib/ecore/ecore_anim.c @@ -125,11 +125,13 @@ _do_tick(void) (!animator->just_added)) { animator_ran = EINA_TRUE; + eina_evlog("+animator", animator, 0.0, NULL); if (!_ecore_call_task_cb(animator->func, animator->data)) { animator->delete_me = EINA_TRUE; animators_delete_me++; } + eina_evlog("-animator", animator, 0.0, NULL); } else animator->just_added = EINA_FALSE; } diff --git a/src/lib/ecore/ecore_events.c b/src/lib/ecore/ecore_events.c index 3405e3d62c..e23ac4231f 100644 --- a/src/lib/ecore/ecore_events.c +++ b/src/lib/ecore/ecore_events.c @@ -436,7 +436,8 @@ _ecore_event_filters_apply() /* recursive main loop, continue from where we were */ event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next; } - + if ((!event_filter_current) && (!event_filters_delete_me) && (!purge_events)) return; + eina_evlog("+event_filter", NULL, 0.0, NULL); while (event_filter_current) { Ecore_Event_Filter *ef = event_filter_current; @@ -481,6 +482,7 @@ _ecore_event_filters_apply() if (event_filter_current) /* may have changed in recursive main loops */ event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next; } + eina_evlog("-event_filter", NULL, 0.0, NULL); if (event_filters_delete_me) { int deleted_in_use = 0; @@ -521,7 +523,8 @@ _ecore_event_call(void) event_current = events; event_handler_current = NULL; } - + if ((!event_current) && (!event_handlers_delete_list)) return; + eina_evlog("+events", NULL, 0.0, NULL); while (event_current) { Ecore_Event *e = event_current; @@ -589,6 +592,7 @@ _ecore_event_call(void) if (event_current) /* may have changed in recursive main loops */ event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next; } + eina_evlog("-events", NULL, 0.0, NULL); ecore_raw_event_type = ECORE_EVENT_NONE; ecore_raw_event_event = NULL; diff --git a/src/lib/ecore/ecore_idle_enterer.c b/src/lib/ecore/ecore_idle_enterer.c index 038b5c9946..45fd601658 100644 --- a/src/lib/ecore/ecore_idle_enterer.c +++ b/src/lib/ecore/ecore_idle_enterer.c @@ -174,10 +174,12 @@ _ecore_idle_enterer_call(void) if (!ie->delete_me) { ie->references++; + eina_evlog("+idle_enterer", ie, 0.0, NULL); if (!_ecore_call_task_cb(ie->func, ie->data)) { if (!ie->delete_me) _ecore_idle_enterer_del(ie->obj); } + eina_evlog("-idle_enterer", ie, 0.0, NULL); ie->references--; } if (idle_enterer_current) /* may have changed in recursive main loops */ diff --git a/src/lib/ecore/ecore_idle_exiter.c b/src/lib/ecore/ecore_idle_exiter.c index b755fc702c..9f7bff34ac 100644 --- a/src/lib/ecore/ecore_idle_exiter.c +++ b/src/lib/ecore/ecore_idle_exiter.c @@ -143,10 +143,12 @@ _ecore_idle_exiter_call(void) if (!ie->delete_me) { ie->references++; + eina_evlog("+idle_exiter", ie, 0.0, NULL); if (!_ecore_call_task_cb(ie->func, ie->data)) { if (!ie->delete_me) _ecore_idle_exiter_del(ie->obj); } + eina_evlog("-idle_exiter", ie, 0.0, NULL); ie->references--; } if (idle_exiter_current) /* may have changed in recursive main loops */ diff --git a/src/lib/ecore/ecore_idler.c b/src/lib/ecore/ecore_idler.c index eef2d10bd7..a61c45c4d5 100644 --- a/src/lib/ecore/ecore_idler.c +++ b/src/lib/ecore/ecore_idler.c @@ -141,10 +141,12 @@ _ecore_idler_all_call(void) if (!ie->delete_me) { ie->references++; + eina_evlog("+idler", ie, 0.0, NULL); if (!_ecore_call_task_cb(ie->func, ie->data)) { if (!ie->delete_me) _ecore_idler_del(ie->obj); } + eina_evlog("-idler", ie, 0.0, NULL); ie->references--; } if (idler_current) /* may have changed in recursive main loops */ diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c index 399f96520a..18ddaff128 100644 --- a/src/lib/ecore/ecore_main.c +++ b/src/lib/ecore/ecore_main.c @@ -972,6 +972,7 @@ EAPI void ecore_main_loop_begin(void) { EINA_MAIN_LOOP_CHECK_RETURN; + eina_evlog("+mainloop", NULL, 0.0, NULL); #ifdef HAVE_SYSTEMD sd_notify(0, "READY=1"); #endif @@ -992,6 +993,7 @@ ecore_main_loop_begin(void) } do_quit = 0; #endif + eina_evlog("-mainloop", NULL, 0.0, NULL); } EAPI void @@ -1453,7 +1455,9 @@ _ecore_main_select(double timeout) if (_ecore_signal_count_get()) return -1; _ecore_unlock(); + eina_evlog("!SLEEP", NULL, 0.0, t ? "timeout" : "forever"); ret = main_loop_select(max_fd + 1, &rfds, &wfds, &exfds, t); + eina_evlog("!WAKE", NULL, 0.0, NULL); _ecore_lock(); _ecore_time_loop_time = ecore_time_get(); @@ -1646,6 +1650,9 @@ _ecore_main_fd_handlers_call(void) fd_handlers_to_call = NULL; } + if (!fd_handlers_to_call_current) return; + eina_evlog("+fd_handlers", NULL, 0.0, NULL); + while (fd_handlers_to_call_current) { Ecore_Fd_Handler *fdh = fd_handlers_to_call_current; @@ -1685,6 +1692,7 @@ _ecore_main_fd_handlers_call(void) fd_handlers_to_call_current = fdh->next_ready; fdh->next_ready = NULL; } + eina_evlog("-fd_handlers", NULL, 0.0, NULL); } static int @@ -1694,6 +1702,8 @@ _ecore_main_fd_handlers_buf_call(void) Eina_List *l, *l2; int ret; + if (!fd_handlers_with_buffer) return 0; + eina_evlog("+fd_handlers_buf", NULL, 0.0, NULL); ret = 0; EINA_LIST_FOREACH_SAFE(fd_handlers_with_buffer, l, l2, fdh) { @@ -1716,6 +1726,7 @@ _ecore_main_fd_handlers_buf_call(void) else fd_handlers_with_buffer = eina_list_remove_list(fd_handlers_with_buffer, l); } + eina_evlog("-fd_handlers_buf", NULL, 0.0, NULL); return ret; } diff --git a/src/lib/ecore/ecore_signal.c b/src/lib/ecore/ecore_signal.c index 033adbc640..60b1ec0dec 100644 --- a/src/lib/ecore/ecore_signal.c +++ b/src/lib/ecore/ecore_signal.c @@ -152,6 +152,7 @@ _ecore_signal_call(void) int tot; if (sig_count == 0) return; + eina_evlog("+signals", NULL, 0.0, NULL); sigemptyset(&newset); sigaddset(&newset, SIGPIPE); sigaddset(&newset, SIGALRM); @@ -456,6 +457,7 @@ _ecore_signal_call(void) sig_count = 0; sigprocmask(SIG_SETMASK, &oldset, NULL); + eina_evlog("-signals", NULL, 0.0, NULL); } static void diff --git a/src/lib/ecore/ecore_throttle.c b/src/lib/ecore/ecore_throttle.c index 0b9e17786b..2fe816ad62 100644 --- a/src/lib/ecore/ecore_throttle.c +++ b/src/lib/ecore/ecore_throttle.c @@ -30,6 +30,8 @@ void _ecore_throttle(void) { if (throttle_val <= 0) return; + eina_evlog("+throttle", NULL, 0.0, NULL); usleep(throttle_val); + eina_evlog("-throttle", NULL, 0.0, NULL); } diff --git a/src/lib/ecore/ecore_timer.c b/src/lib/ecore/ecore_timer.c index 9d20d27685..e119e9612c 100644 --- a/src/lib/ecore/ecore_timer.c +++ b/src/lib/ecore/ecore_timer.c @@ -720,10 +720,12 @@ _ecore_timer_expired_call(double when) } timer->references++; + eina_evlog("+timer", timer, 0.0, NULL); if (!_ecore_call_task_cb(timer->func, timer->data)) { if (!timer->delete_me) _ecore_timer_del(timer->obj); } + eina_evlog("-timer", timer, 0.0, NULL); timer->references--; if (timer_current) /* may have changed in recursive main loops */ diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index b0b24ee09e..c05ab9abee 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -264,6 +264,7 @@ extern "C" { #include #include #include +#include #undef EAPI #define EAPI diff --git a/src/lib/eina/eina_debug_monitor.c b/src/lib/eina/eina_debug_monitor.c index 324759f2a2..c06d5e9df3 100644 --- a/src/lib/eina/eina_debug_monitor.c +++ b/src/lib/eina/eina_debug_monitor.c @@ -1,4 +1,5 @@ #include "eina_debug.h" +#include "eina_evlog.h" #ifdef EINA_HAVE_DEBUG @@ -177,6 +178,38 @@ _eina_debug_monitor(void *data EINA_UNUSED) poll_time = 1000; poll_on = EINA_FALSE; } + // enable evlog + else if (!strcmp(op, "EVON")) + { + eina_evlog_start(); + } + // stop evlog + else if (!strcmp(op, "EVOF")) + { + eina_evlog_stop(); + } + // fetch the evlog + else if (!strcmp(op, "EVLG")) + { + Eina_Evlog_Buf *evlog = eina_evlog_steal(); + if ((evlog) && (evlog->buf)) + { + char tmp[16]; + unsigned int *size = (unsigned int *)(tmp + 0); + char *op2 = "EVLG"; + unsigned int *overflow = (unsigned int *)(tmp + 8); + unsigned int *stolen = (unsigned int *)(tmp + 12); + + *size = (sizeof(tmp) - 4) + evlog->top; + memcpy(tmp + 4, op2, 4); + *overflow = evlog->overflow; + *stolen = evlog->stolen; + write(_eina_debug_monitor_service_fd, + tmp, 16); + write(_eina_debug_monitor_service_fd, + evlog->buf, evlog->top); + } + } // something we don't understand else fprintf(stderr, "EINA DEBUG ERROR: " diff --git a/src/lib/eina/eina_evlog.c b/src/lib/eina/eina_evlog.c new file mode 100644 index 0000000000..4703c962c8 --- /dev/null +++ b/src/lib/eina/eina_evlog.c @@ -0,0 +1,220 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "Eina.h" +#include "eina_evlog.h" +#include "eina_debug.h" + +#ifdef EINA_HAVE_DEBUG + +# ifdef HAVE_MMAP +# include +# endif + +# define EVLOG_BUF_SIZE (4 * (1024 * 1024)) + +static Eina_Spinlock _evlog_lock; +static int _evlog_go = 0; + +static Eina_Evlog_Buf *buf; // current event log we are writing events to +static Eina_Evlog_Buf buffers[2]; // double-buffer our event log buffers + +static inline double +get_time(void) +{ + struct timeval timev; + gettimeofday(&timev, NULL); + return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000.0); +} + +static void +alloc_buf(Eina_Evlog_Buf *b, unsigned int size) +{ + if (b->buf) return; + b->size = size; + b->top = 0; +# ifdef HAVE_MMAP + b->buf = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (b->buf == MAP_FAILED) b->buf = NULL; +# else + b->buf = malloc(size); +# endif + b->overflow = 0; + b->stolen = 0; +} + +static void +free_buf(Eina_Evlog_Buf *b) +{ + if (!b->buf) return; + b->size = 0; + b->top = 0; +# ifdef HAVE_MMAP + munmap(b->buf, b->size); +# else + free(b->buf); +# endif + b->buf = NULL; +} + +static inline void * +push_buf(Eina_Evlog_Buf *b, unsigned int size) +{ + void *ptr; + + if (b->size < size) abort(); + if ((b->top + size) > (b->size)) + { + b->overflow++; + b->top = 0; + } + ptr = (b->buf + b->top); + b->top += size; + return ptr; +} + +EAPI void +eina_evlog(const char *event, void *obj, double srctime, const char *detail) +{ + Eina_Evlog_Item *item; + int size; + char *strings; + double now = get_time(); + unsigned short detail_offset = 0; + unsigned short event_size; + + eina_spinlock_take(&_evlog_lock); + if (!_evlog_go) + { + eina_spinlock_release(&_evlog_lock); + return; + } + size = sizeof(Eina_Evlog_Item); + event_size = strlen(event) + 1; + size += event_size; + if (detail) + { + detail_offset = size; + size += strlen(detail) + 1; + } + size = sizeof(double) * ((size + sizeof(double) - 1) / sizeof(double)); + + strings = push_buf(buf, size); + item = (Eina_Evlog_Item *)strings; + item->tim = now; + item->srctim = srctime; + item->thread = (unsigned long long)pthread_self(); + item->obj = (unsigned long long)obj; + item->event_offset = sizeof(Eina_Evlog_Item); + item->detail_offset = detail_offset; + item->event_next = size; + + strcpy(strings + sizeof(Eina_Evlog_Item), event); + if (detail_offset > 0) strcpy(strings + detail_offset, detail); + + eina_spinlock_release(&_evlog_lock); +} + +EAPI Eina_Evlog_Buf * +eina_evlog_steal(void) +{ + Eina_Evlog_Buf *stolen = NULL; + + eina_spinlock_take(&_evlog_lock); + if (buf == &(buffers[0])) + { + buf = &(buffers[1]); + buf->top = 0; + stolen = &(buffers[0]); + stolen->stolen++; + } + else + { + buf = &(buffers[0]); + buf->top = 0; + stolen = &(buffers[1]); + stolen->stolen++; + } + eina_spinlock_release(&_evlog_lock); + return stolen; +} + +EAPI void +eina_evlog_start(void) +{ + eina_spinlock_take(&_evlog_lock); + _evlog_go++; + if (_evlog_go == 1) + { + // alloc 2 buffers for spinning around in + alloc_buf(&(buffers[0]), EVLOG_BUF_SIZE); + alloc_buf(&(buffers[1]), EVLOG_BUF_SIZE); + } + eina_spinlock_release(&_evlog_lock); +} + +EAPI void +eina_evlog_stop(void) +{ + eina_spinlock_take(&_evlog_lock); + _evlog_go--; + if (_evlog_go == 0) + { + free_buf(&(buffers[0])); + free_buf(&(buffers[1])); + } + eina_spinlock_release(&_evlog_lock); +} + +Eina_Bool +eina_evlog_init(void) +{ + eina_spinlock_new(&_evlog_lock); + buf = &(buffers[0]); + eina_evlog("+eina_init", NULL, 0.0, NULL); + return EINA_TRUE; +} + +Eina_Bool +eina_evlog_shutdown(void) +{ + // yes - we don't free tyhe evlog buffers. they may be in used by debug th + eina_spinlock_free(&_evlog_lock); + return EINA_TRUE; +} +#else +EAPI void +eina_evlog(const char *event EINA_UNUSED, void *obj EINA_UNUSED, double srctime EINA_UNUSED, const char *detail EINA_UNUSED) +{ +} + +EAPI Eina_Evlog_Buf * +eina_evlog_steal(void) +{ + return NULL; +} + +EAPI void +eina_evlog_start(void) +{ +} + +EAPI void +eina_evlog_stop(void) +{ +} + +Eina_Bool +eina_evlog_init(void) +{ + return EINA_TRUE; +} + +Eina_Bool +eina_evlog_shutdown(void) +{ + return EINA_TRUE; +} +#endif diff --git a/src/lib/eina/eina_evlog.h b/src/lib/eina/eina_evlog.h new file mode 100644 index 0000000000..82a8dd6138 --- /dev/null +++ b/src/lib/eina/eina_evlog.h @@ -0,0 +1,121 @@ +#ifndef EINA_EVLOG_H_ +#define EINA_EVLOG_H_ + +/** + * @addtogroup Eina_Evlog Event Log Debugging + * @ingroup Eina + * + * @brief These functions are use internally by EFL in general for profiling + * + * @{ + * + * @since 1.15 + */ + +typedef struct _Eina_Evlog_Item Eina_Evlog_Item; +typedef struct _Eina_Evlog_Buf Eina_Evlog_Buf; + +struct _Eina_Evlog_Item +{ + double tim; // the time when this event happened + double srctim; // if > 0.0, then this is the src event time causing this + unsigned long long thread; // a thread handle/id where this log happened + unsigned long long obj; // an object associated with this event (anything) + unsigned short event_offset; // must be provided - mem pos after item + unsigned short detail_offset; // if not provided, 0, otherwise mem pos + unsigned short event_next; // mem offset in bytes for next event; +}; + +struct _Eina_Evlog_Buf +{ + unsigned char *buf; // current buffer we fill with event logs + unsigned int size; // the max size of the evlog buffer + unsigned int top; // the current top byte for a new evlog item + unsigned int overflow; // how many times this biffer has overflown + unsigned int stolen; // how many times this buffer has been stolen +}; + +/** + * @brief Log an event in our event log for profiling data + * + * Log some interesting event inside of EFL, eg a wakeup (and why etc.). + * The @p event string must alwasy be provided and be of the form: + * + * "+eventname" + * "-eventname" + * "!eventname" + * + * etc. The "+" char means an event is beginning (and any subsequent + * events logged are really children of this event). The "-" char means an + * event is ending and so all child events SHOULD have ended by now. A "!" + * character means the event is a one-off with no beginning or end. Any string + * following this initial character is the eventy name (and must be provided + * in the exact same string at both + and - events). This is what will be + * displayed in a debugger (and may be a well known string thus given a nice + * UI flourish with icons, labels and colors, so don't change this string + * unless you want to impact such visibility of these events). The event + * string after the first character as above can be anything, including white + * space. It is suggested to keep it human readable and as short as feasible. + * + * The @p object is optional, and if not used, pass in NULL. If it is used, + * it can be a pointer to anything. It is intended simply to be of use to + * indicate an event happens on object A vs object B. What this points to + * is irrelevant as the pointer is never de-references or used other than + * as a label to differentiate an event on 2 different objects. + * + * The @p srctime parameter is 0.0 if not used, or if used, contains a + * timepoint for an event that triggered this one. For example, if a device + * or hardware interrupt causes this event, that device may provide a + * timestamp/timepoint as part of the device information to indicate the + * exact time the hardware interrupt happened. This can be useful to have + * more information as to the latency of an actual source of an event such + * as the hardware interrupt time, and when the code actually begins seeing + * or processing it. + * + * The @p detail string is optional (and if unused should be NULL). This is + * for providing more detailed information to log such as perhaps a the + * state at the time of the log events or a series of parameters and input + * that caused this event. + * + * @param event The event string - see above for format + * @param obj An optional object "pointer" to associate + * @param srctime An optional source event timestamp that caused this event + * @param detail An optional event detail string with more info + * + * @since 1.15 + */ +EAPI void +eina_evlog(const char *event, void *obj, double srctime, const char *detail); + +/** + * @brief Steal an event log buffer from the evlog core + * + * Only one buffer can be stolen at any time. If you steal a new buffer, the + * old stolen buffer is "released" back to the evlog core. + * + * @return The stolen evlog buffer + * + * @since 1.15 + */ +EAPI Eina_Evlog_Buf * +eina_evlog_steal(void); + +/** + * @brief Begin logging - until now eina_evlog is a NOOP + */ +EAPI void +eina_evlog_start(void); + +/** + * @brief Stop logging + * + * You must not be using any evlog buffers stolen by eina_evlog_steal() by + * the time you call this function. + */ +EAPI void +eina_evlog_stop(void); + +/** + * @} + */ +#endif diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index 358c3a4bfb..1daa795e87 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c @@ -67,6 +67,7 @@ #include "eina_inlist.h" #include "eina_inarray.h" #include "eina_value.h" +#include "eina_evlog.h" /* no model for now #include "eina_model.h" */ @@ -121,6 +122,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL; #define S(x) extern Eina_Bool eina_ ## x ## _init(void); \ extern Eina_Bool eina_ ## x ## _shutdown(void) S(debug); + S(evlog); S(log); S(error); S(safety_checks); @@ -167,6 +169,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = { #define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown} /* log is a special case as it needs printf */ S(debug), + S(evlog), S(stringshare), S(error), S(safety_checks), @@ -299,6 +302,7 @@ eina_init(void) eina_log_timing(_eina_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT); _eina_main_count = 1; + eina_evlog("-eina_init", NULL, 0.0, NULL); return 1; }