eina - begin event log infra we can get from the new debug monitor
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Sun, 10 May 2015 10:05:54 +0000 (19:05 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Sun, 10 May 2015 10:05:54 +0000 (19:05 +0900)
we can down dump event logs. some ecore mainloop bits are logging at
the moment.

17 files changed:
src/Makefile_Eina.am
src/bin/efl/efl_debug.c
src/bin/efl/efl_debugd.c
src/lib/ecore/ecore_anim.c
src/lib/ecore/ecore_events.c
src/lib/ecore/ecore_idle_enterer.c
src/lib/ecore/ecore_idle_exiter.c
src/lib/ecore/ecore_idler.c
src/lib/ecore/ecore_main.c
src/lib/ecore/ecore_signal.c
src/lib/ecore/ecore_throttle.c
src/lib/ecore/ecore_timer.c
src/lib/eina/Eina.h
src/lib/eina/eina_debug_monitor.c
src/lib/eina/eina_evlog.c [new file with mode: 0644]
src/lib/eina/eina_evlog.h [new file with mode: 0644]
src/lib/eina/eina_main.c

index a92b758..0fb2061 100644 (file)
@@ -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 \
index 461238d..6a65178 100644 (file)
@@ -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;
 }
index b64747f..3cfe65d 100644 (file)
@@ -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;
index 75dc9a6..2c772e4 100644 (file)
@@ -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;
      }
index 3405e3d..e23ac42 100644 (file)
@@ -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;
index 038b5c9..45fd601 100644 (file)
@@ -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 */
index b755fc7..9f7bff3 100644 (file)
@@ -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 */
index eef2d10..a61c45c 100644 (file)
@@ -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 */
index 399f965..18ddaff 100644 (file)
@@ -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;
 }
 
index 033adbc..60b1ec0 100644 (file)
@@ -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
index 0b9e177..2fe816a 100644 (file)
@@ -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);
 }
 
index 9d20d27..e119e96 100644 (file)
@@ -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 */
index b0b24ee..c05ab9a 100644 (file)
@@ -264,6 +264,7 @@ extern "C" {
 #include <eina_thread_queue.h>
 #include <eina_matrix.h>
 #include <eina_crc.h>
+#include <eina_evlog.h>
 
 #undef EAPI
 #define EAPI
index 324759f..c06d5e9 100644 (file)
@@ -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 (file)
index 0000000..4703c96
--- /dev/null
@@ -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 <sys/mman.h>
+# 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 (file)
index 0000000..82a8dd6
--- /dev/null
@@ -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
index 358c3a4..1daa795 100644 (file)
@@ -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;
 }