From 6605a1c3c286d0eec6f8a3971931fc58cccb3c36 Mon Sep 17 00:00:00 2001 From: o9000 Date: Thu, 31 Aug 2017 21:46:04 +0200 Subject: [PATCH] Tracing support --- CMakeLists.txt | 19 ++++-- src/init.c | 12 +++- src/main.c | 11 ++++ src/panel.h | 1 + src/server.c | 1 + src/tracing.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ src/tracing.h | 15 +++++ tint2.config | 2 + tint2.files | 2 + 9 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 src/tracing.c create mode 100644 src/tracing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a41815..81cc0c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ option( ENABLE_TINT2CONF "Enable tint2conf build, a GTK+2 theme configurator for option( ENABLE_EXTRA_THEMES "Install additional tint2 themes" ON ) option( ENABLE_RSVG "Rsvg support (launcher only)" ON ) option( ENABLE_SN "Startup notification support" ON ) +option( ENABLE_TRACING "Build tint2 with tracing instrumentation" OFF ) option( ENABLE_ASAN "Build tint2 with AddressSanitizer" OFF ) option( ENABLE_BACKTRACE "Dump a backtrace in case of fatal errors (e.g. X11 I/O error)" OFF ) option( ENABLE_BACKTRACE_ON_SIGNAL "Dump a backtrace also when receiving signals such as SIGSEGV" OFF ) @@ -119,6 +120,7 @@ set( SOURCES src/config.c src/main.c src/init.c src/signals.c + src/tracing.c src/mouse_actions.c src/drag_and_drop.c src/clock/clock.c @@ -215,13 +217,22 @@ if( ENABLE_TINT2CONF ) endif( ENABLE_TINT2CONF ) if( ENABLE_ASAN ) - SET(ASAN_C_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -Wshadow") - SET(ASAN_L_FLAGS " -O0 -g3 -gdwarf-2 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -fuse-ld=gold ") + SET(ASAN_C_FLAGS " -O0 -g3 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -Wshadow") + SET(ASAN_L_FLAGS " -O0 -g3 -fsanitize=address -fno-common -fno-omit-frame-pointer -rdynamic -fuse-ld=gold ") else() SET(ASAN_C_FLAGS "") SET(ASAN_L_FLAGS "") endif() +if( ENABLE_TRACING ) + add_definitions( -DHAVE_TRACING ) + SET(TRACING_C_FLAGS " -finstrument-functions -finstrument-functions-exclude-file-list=tracing.c -finstrument-functions-exclude-function-list=get_time,gettime -O0 -g3 -fno-common -fno-omit-frame-pointer -rdynamic") + SET(TRACING_L_FLAGS " -O0 -g3 -fno-common -fno-omit-frame-pointer -rdynamic") +else() + SET(TRACING_C_FLAGS "") + SET(TRACING_L_FLAGS "") +endif() + add_custom_target( version ALL "${PROJECT_SOURCE_DIR}/get_version.sh" -- "\"${PROJECT_SOURCE_DIR}/\"" ) link_directories( ${X11_LIBRARY_DIRS} @@ -256,8 +267,8 @@ endif( RT_LIBRARY ) target_link_libraries( tint2 m ) add_dependencies( tint2 version ) -set_target_properties( tint2 PROPERTIES COMPILE_FLAGS "-Wall -Wpointer-arith -fno-strict-aliasing -pthread -std=c99 ${ASAN_C_FLAGS}" ) -set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS}" ) +set_target_properties( tint2 PROPERTIES COMPILE_FLAGS "-Wall -Wpointer-arith -fno-strict-aliasing -pthread -std=c99 ${ASAN_C_FLAGS} ${TRACING_C_FLAGS}" ) +set_target_properties( tint2 PROPERTIES LINK_FLAGS "-pthread -fno-strict-aliasing ${ASAN_L_FLAGS} ${BACKTRACE_L_FLAGS} ${TRACING_L_FLAGS}" ) install( TARGETS tint2 DESTINATION bin ) install( FILES tint2.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps ) diff --git a/src/init.c b/src/init.c index e6d7134..6176b6a 100644 --- a/src/init.c +++ b/src/init.c @@ -12,6 +12,7 @@ #include "server.h" #include "signals.h" #include "tooltip.h" +#include "tracing.h" #include "uevent.h" #include "version.h" @@ -83,8 +84,13 @@ void handle_env_vars() debug_gradients = getenv("DEBUG_GRADIENTS") != NULL; debug_fps = getenv("DEBUG_FPS") != NULL; debug_frames = getenv("DEBUG_FRAMES") != NULL; - if (debug_fps) + if (debug_fps) { init_fps_distribution(); + char *s = getenv("TRACING_FPS_THRESHOLD"); + if (!s || sscanf(s, "%lf", &tracing_fps_threshold) != 1) { + tracing_fps_threshold = 60; + } + } } static timeout *detect_compositor_timer = NULL; @@ -269,4 +275,8 @@ void cleanup() uevent_cleanup(); cleanup_fps_distribution(); + +#ifdef HAVE_TRACING + cleanup_tracing(); +#endif } diff --git a/src/main.c b/src/main.c index b4afec2..88a0e96 100644 --- a/src/main.c +++ b/src/main.c @@ -57,6 +57,7 @@ #include "taskbar.h" #include "tooltip.h" #include "timer.h" +#include "tracing.h" #include "uevent.h" #include "version.h" #include "window.h" @@ -69,6 +70,7 @@ XSettingsClient *xsettings_client = NULL; gboolean debug_fps = FALSE; gboolean debug_frames = FALSE; static int frame = 0; +double tracing_fps_threshold = 60; static double ts_event_read; static double ts_event_processed; static double ts_render_finished; @@ -711,6 +713,12 @@ void handle_panel_refresh() proc_ratio * 100, render_ratio * 100, flush_ratio * 100); +#ifdef HAVE_TRACING + stop_tracing(); + if (fps <= tracing_fps_threshold) { + print_tracing_events(); + } +#endif } if (debug_frames) { for (int i = 0; i < num_panels; i++) { @@ -741,6 +749,9 @@ void run_tint2_event_loop() // Wait for an event and handle it ts_event_read = 0; if (XPending(server.display) > 0 || select(max_fd + 1, &fd_set, 0, 0, get_next_timeout()) >= 0) { +#ifdef HAVE_TRACING + start_tracing((void*)run_tint2_event_loop); +#endif uevent_handler(); handle_sigchld_events(); handle_execp_events(); diff --git a/src/panel.h b/src/panel.h index 87b8ca3..2d440e3 100644 --- a/src/panel.h +++ b/src/panel.h @@ -92,6 +92,7 @@ extern XSettingsClient *xsettings_client; extern gboolean startup_notifications; extern gboolean debug_geometry; extern gboolean debug_fps; +extern double tracing_fps_threshold; extern gboolean debug_frames; typedef struct Panel { diff --git a/src/server.c b/src/server.c index 226a87f..71f880d 100644 --- a/src/server.c +++ b/src/server.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/src/tracing.c b/src/tracing.c new file mode 100644 index 0000000..f202b99 --- /dev/null +++ b/src/tracing.c @@ -0,0 +1,164 @@ +#include "timer.h" + +#ifdef HAVE_TRACING + +#ifdef ENABLE_EXECINFO +#include +#endif +#include +#include +#include +#include + +#define GREEN "\033[1;32m" +#define YELLOW "\033[1;33m" +#define RED "\033[1;31m" +#define BLUE "\033[1;34m" +#define RESET "\033[0m" + +static GList *tracing_events = NULL; +static sig_atomic_t tracing = FALSE; + +typedef struct TracingEvent { + void *address; + void *caller; + double time; + gboolean enter; +} TracingEvent; + +void __attribute__ ((constructor)) init_tracing() +{ + tracing_events = NULL; + tracing = FALSE; +} + +void cleanup_tracing() +{ + g_list_free_full(tracing_events, free); + tracing_events = NULL; + tracing = FALSE; +} + +char *addr2name(void *func) +{ +#ifdef ENABLE_EXECINFO + void *array[1]; + array[0] = func; + char **strings = backtrace_symbols(array, 1); + char *result = strdup(strings[0] ? strings[0] : "??"); + free(strings); + return result; +#else + char *result = (char*) calloc(32, 1); + sprintf(result, "%p", func); + return result; +#endif +} + +void add_tracing_event(void *func, void *caller, gboolean enter) +{ + TracingEvent *entry = (TracingEvent *)calloc(sizeof(TracingEvent), 1); + entry->address = func; + entry->caller = caller; + entry->time = get_time(); + entry->enter = enter; + tracing_events = g_list_append(tracing_events, entry); +} + +void start_tracing(void *root) +{ + if (tracing_events) + cleanup_tracing(); + add_tracing_event(root, NULL, TRUE); + tracing = TRUE; +} + +void stop_tracing() +{ + tracing = FALSE; +} + +void __cyg_profile_func_enter(void *func, void *caller) +{ + if (tracing) + add_tracing_event(func, caller, TRUE); +} + +void __cyg_profile_func_exit(void *func, void *caller) +{ + if (tracing) + add_tracing_event(func, caller, FALSE); +} + +void print_tracing_events() +{ + GList *stack = NULL; + int depth = 0; + double now = get_time(); + for (GList *i = tracing_events; i; i = i->next) { + TracingEvent *e = (TracingEvent *)i->data; + if (e->enter) { + // Push a new function on the stack + for (int d = 0; d < depth; d++) + fprintf(stderr, " "); + char *name = addr2name(e->address); + char *caller = addr2name(e->caller); + fprintf(stderr, + "%s called from %s\n", + name, + caller); + stack = g_list_append(stack, e); + depth++; + } else { + // Pop a function from the stack, if matching, and print + if (stack) { + TracingEvent *old = (TracingEvent *)g_list_last(stack)->data; + if (old->address == e->address) { + depth--; + for (int d = 0; d < depth; d++) + fprintf(stderr, " "); + char *name = addr2name(e->address); + double duration = (e->time - old->time) * 1.0e3; + fprintf(stderr, + "-- %s exited after %.1f ms", + name, + duration); + if (duration >= 1.0) { + fprintf(stderr, YELLOW " "); + for (int d = 0; d < duration; d++) { + fprintf(stderr, "#"); + } + fprintf(stderr, RESET); + } + fprintf(stderr, "\n"); + free(name); + stack = g_list_delete_link(stack, g_list_last(stack)); + } + } + } + } + while (stack) { + TracingEvent *old = (TracingEvent *)g_list_last(stack)->data; + depth--; + for (int d = 0; d < depth; d++) + fprintf(stderr, " "); + char *name = addr2name(old->address); + double duration = (now - old->time) * 1.0e3; + fprintf(stderr, + "-- %s exited after %.1f ms", + name, + duration); + if (duration >= 1.0) { + fprintf(stderr, YELLOW " "); + for (int d = 0; d < duration; d++) { + fprintf(stderr, "#"); + } + fprintf(stderr, RESET); + } + fprintf(stderr, "\n"); + free(name); + stack = g_list_delete_link(stack, g_list_last(stack)); + } +} + +#endif diff --git a/src/tracing.h b/src/tracing.h new file mode 100644 index 0000000..3b3294e --- /dev/null +++ b/src/tracing.h @@ -0,0 +1,15 @@ +#ifndef TRACING_H +#define TRACING_H + +#ifdef HAVE_TRACING + +void init_tracing(); +void cleanup_tracing(); + +void start_tracing(void *root); +void stop_tracing(); +void print_tracing_events(); + +#endif + +#endif diff --git a/tint2.config b/tint2.config index 42b9d11..daca821 100644 --- a/tint2.config +++ b/tint2.config @@ -4,3 +4,5 @@ #define ENABLE_BATTERY 1 #define ENABLE_UEVENT 1 #define GETTEXT_PACKAGE +#define HAVE_TRACING +#define ENABLE_EXECINFO diff --git a/tint2.files b/tint2.files index 330dea5..aafafc8 100644 --- a/tint2.files +++ b/tint2.files @@ -235,3 +235,5 @@ src/init.h src/init.c src/signals.c src/signals.h +src/tracing.c +src/tracing.h