Tracing support
This commit is contained in:
parent
0c754affd9
commit
6605a1c3c2
9 changed files with 222 additions and 5 deletions
|
@ -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 )
|
||||
|
|
12
src/init.c
12
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
|
||||
}
|
||||
|
|
11
src/main.c
11
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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
164
src/tracing.c
Normal 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
15
src/tracing.h
Normal 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
|
|
@ -4,3 +4,5 @@
|
|||
#define ENABLE_BATTERY 1
|
||||
#define ENABLE_UEVENT 1
|
||||
#define GETTEXT_PACKAGE
|
||||
#define HAVE_TRACING
|
||||
#define ENABLE_EXECINFO
|
||||
|
|
|
@ -235,3 +235,5 @@ src/init.h
|
|||
src/init.c
|
||||
src/signals.c
|
||||
src/signals.h
|
||||
src/tracing.c
|
||||
src/tracing.h
|
||||
|
|
Loading…
Reference in a new issue