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 \
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 \
{
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)))
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;
}
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;
};
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)
{
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
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;
(!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;
}
/* 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;
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;
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;
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;
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 */
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 */
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 */
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
}
do_quit = 0;
#endif
+ eina_evlog("-mainloop", NULL, 0.0, NULL);
}
EAPI void
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();
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;
fd_handlers_to_call_current = fdh->next_ready;
fdh->next_ready = NULL;
}
+ eina_evlog("-fd_handlers", NULL, 0.0, NULL);
}
static int
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)
{
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;
}
int tot;
if (sig_count == 0) return;
+ eina_evlog("+signals", NULL, 0.0, NULL);
sigemptyset(&newset);
sigaddset(&newset, SIGPIPE);
sigaddset(&newset, SIGALRM);
sig_count = 0;
sigprocmask(SIG_SETMASK, &oldset, NULL);
+ eina_evlog("-signals", NULL, 0.0, NULL);
}
static 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);
}
}
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 */
#include <eina_thread_queue.h>
#include <eina_matrix.h>
#include <eina_crc.h>
+#include <eina_evlog.h>
#undef EAPI
#define EAPI
#include "eina_debug.h"
+#include "eina_evlog.h"
#ifdef EINA_HAVE_DEBUG
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: "
--- /dev/null
+#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
--- /dev/null
+#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
#include "eina_inlist.h"
#include "eina_inarray.h"
#include "eina_value.h"
+#include "eina_evlog.h"
/* no model for now
#include "eina_model.h"
*/
#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);
#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),
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;
}