Tracing support

This commit is contained in:
o9000 2017-08-31 21:46:04 +02:00
parent 0c754affd9
commit 6605a1c3c2
9 changed files with 222 additions and 5 deletions

View file

@ -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 )

View file

@ -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
}

View file

@ -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();

View file

@ -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 {

View file

@ -23,6 +23,7 @@
#include <X11/extensions/Xrandr.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

164
src/tracing.c Normal file
View file

@ -0,0 +1,164 @@
#include "timer.h"
#ifdef HAVE_TRACING
#ifdef ENABLE_EXECINFO
#include <execinfo.h>
#endif
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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

15
src/tracing.h Normal file
View file

@ -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

View file

@ -4,3 +4,5 @@
#define ENABLE_BATTERY 1
#define ENABLE_UEVENT 1
#define GETTEXT_PACKAGE
#define HAVE_TRACING
#define ENABLE_EXECINFO

View file

@ -235,3 +235,5 @@ src/init.h
src/init.c
src/signals.c
src/signals.h
src/tracing.c
src/tracing.h