libsysprof-analyze: add symbol kind property for symbols

Additionally, add the pid as the binary nick for processes so that we can
show them in the callgraph with the process name.
This commit is contained in:
Christian Hergert
2023-06-14 12:08:23 -07:00
parent 21766d275c
commit 2a65bf30af
13 changed files with 134 additions and 61 deletions

View File

@ -208,11 +208,26 @@ sysprof_bundled_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
} }
if (ret->offset < (self->endptr - self->beginptr)) if (ret->offset < (self->endptr - self->beginptr))
return _sysprof_symbol_new (sysprof_strings_get (strings, &self->beginptr[ret->offset]), {
NULL, const char *name = &self->beginptr[ret->offset];
g_steal_pointer (&tag), SysprofSymbolKind kind;
ret->addr_begin,
ret->addr_end); if (g_str_has_prefix (name, "- -"))
kind = SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH;
else if (context == SYSPROF_ADDRESS_CONTEXT_KERNEL)
kind = SYSPROF_SYMBOL_KIND_KERNEL;
else if (name[0] == '[')
kind = SYSPROF_SYMBOL_KIND_PROCESS;
else
kind = SYSPROF_SYMBOL_KIND_USER;
return _sysprof_symbol_new (sysprof_strings_get (strings, name),
NULL,
g_steal_pointer (&tag),
ret->addr_begin,
ret->addr_end,
kind);
}
return NULL; return NULL;
} }

View File

@ -402,10 +402,8 @@ sysprof_callgraph_frame_list_traceables_async (SysprofCallgraphFrame *self,
SysprofCallgraphSummary *summary = node->summary; SysprofCallgraphSummary *summary = node->summary;
SysprofSymbol *symbol = summary->symbol; SysprofSymbol *symbol = summary->symbol;
if (symbol->is_context_switch || if (symbol->kind != SYSPROF_SYMBOL_KIND_USER &&
symbol->is_everything || symbol->kind != SYSPROF_SYMBOL_KIND_KERNEL)
symbol->is_untraceable ||
symbol->is_process)
continue; continue;
if (bitset == NULL) if (bitset == NULL)

View File

@ -168,11 +168,12 @@ sysprof_callgraph_class_init (SysprofCallgraphClass *klass)
object_class->dispose = sysprof_callgraph_dispose; object_class->dispose = sysprof_callgraph_dispose;
object_class->finalize = sysprof_callgraph_finalize; object_class->finalize = sysprof_callgraph_finalize;
everything = _sysprof_symbol_new (g_ref_string_new_intern ("[Everything]"), NULL, NULL, 0, 0); everything = _sysprof_symbol_new (g_ref_string_new_intern ("All Processes"),
everything->is_everything = TRUE; NULL, NULL, 0, 0,
SYSPROF_SYMBOL_KIND_ROOT);
untraceable = _sysprof_symbol_new (g_ref_string_new_intern ("[Unwindable]"), NULL, NULL, 0, 0); untraceable = _sysprof_symbol_new (g_ref_string_new_intern ("Unwindable"),
everything->is_untraceable = TRUE; NULL, NULL, 0, 0,
SYSPROF_SYMBOL_KIND_UNWINDABLE);
} }
static void static void
@ -197,9 +198,11 @@ sysprof_callgraph_populate_callers (SysprofCallgraph *self,
if (iter->parent != NULL) if (iter->parent != NULL)
{ {
SysprofSymbol *parent_symbol = iter->parent->summary->symbol; SysprofSymbol *parent_symbol = iter->parent->summary->symbol;
SysprofSymbolKind parent_kind = sysprof_symbol_get_kind (parent_symbol);
guint pos; guint pos;
if (!(parent_symbol->is_process || parent_symbol->is_everything) && if (parent_kind != SYSPROF_SYMBOL_KIND_PROCESS &&
parent_kind != SYSPROF_SYMBOL_KIND_ROOT &&
!g_ptr_array_find (iter->summary->callers, parent_symbol, &pos)) !g_ptr_array_find (iter->summary->callers, parent_symbol, &pos))
g_ptr_array_add (iter->summary->callers, parent_symbol); g_ptr_array_add (iter->summary->callers, parent_symbol);
} }
@ -308,12 +311,12 @@ sysprof_callgraph_add_traceable (SysprofCallgraph *self,
* that it was a corrupted unwind when recording. * that it was a corrupted unwind when recording.
*/ */
if (n_symbols == 1 && if (n_symbols == 1 &&
symbols[0]->is_context_switch && _sysprof_symbol_is_context_switch (symbols[0]) &&
final_context == SYSPROF_ADDRESS_CONTEXT_USER) final_context == SYSPROF_ADDRESS_CONTEXT_USER)
symbols[0] = untraceable; symbols[0] = untraceable;
/* We saved 3 extra spaces for these above so that we can /* We saved 3 extra spaces for these above so that we can
* tack on the "Process" symbol and the "Everything" symbol. * tack on the "Process" symbol and the "All Processes" symbol.
* If the final address context places us in Kernel, we want * If the final address context places us in Kernel, we want
* to add a "- - Kernel - -" symbol to ensure that we are * to add a "- - Kernel - -" symbol to ensure that we are
* accounting cost to the kernel for the process. * accounting cost to the kernel for the process.

View File

@ -148,6 +148,7 @@ sysprof_document_symbols_worker (GTask *task,
{ "- - Guest Kernel - -", SYSPROF_ADDRESS_CONTEXT_GUEST_KERNEL }, { "- - Guest Kernel - -", SYSPROF_ADDRESS_CONTEXT_GUEST_KERNEL },
{ "- - Guest User - -", SYSPROF_ADDRESS_CONTEXT_GUEST_USER }, { "- - Guest User - -", SYSPROF_ADDRESS_CONTEXT_GUEST_USER },
}; };
g_autoptr(GRefString) context_switch = g_ref_string_new_intern ("Context Switch");
Symbolize *state = task_data; Symbolize *state = task_data;
EggBitsetIter iter; EggBitsetIter iter;
EggBitset *bitset; EggBitset *bitset;
@ -168,9 +169,11 @@ sysprof_document_symbols_worker (GTask *task,
/* Create static symbols for context switch use */ /* Create static symbols for context switch use */
for (guint cs = 0; cs < G_N_ELEMENTS (context_switches); cs++) for (guint cs = 0; cs < G_N_ELEMENTS (context_switches); cs++)
{ {
g_autoptr(SysprofSymbol) symbol = _sysprof_symbol_new (g_ref_string_new_intern (context_switches[cs].name), NULL, NULL, 0, 0); g_autoptr(SysprofSymbol) symbol = _sysprof_symbol_new (g_ref_string_new_intern (context_switches[cs].name),
NULL,
symbol->is_context_switch = TRUE; g_ref_string_acquire (context_switch),
0, 0,
SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH);
/* TODO: It would be nice if we had enough insight from the capture header /* TODO: It would be nice if we had enough insight from the capture header
* as to the host system, so we can show "vmlinuz" and "Linux" respectively * as to the host system, so we can show "vmlinuz" and "Linux" respectively

View File

@ -486,13 +486,13 @@ sysprof_document_load_processes (SysprofDocument *self)
if ((parts = g_strsplit (cmdline , " ", 2))) if ((parts = g_strsplit (cmdline , " ", 2)))
{ {
g_autofree char *wrapped = g_strdup_printf ("[%s]", parts[0]); GRefString *nick = g_ref_string_acquire (process_info->fallback_symbol->binary_nick);
g_clear_object (&process_info->symbol); g_clear_object (&process_info->symbol);
process_info->symbol = process_info->symbol =
_sysprof_symbol_new (sysprof_strings_get (self->strings, wrapped), _sysprof_symbol_new (sysprof_strings_get (self->strings, parts[0]),
NULL, NULL, 0, 0); NULL, g_steal_pointer (&nick), 0, 0,
process_info->symbol->is_process = TRUE; SYSPROF_SYMBOL_KIND_PROCESS);
} }
} }
} }
@ -1334,7 +1334,7 @@ sysprof_document_list_symbols_in_traceable (SysprofDocument *self,
symbols = g_alloca (sizeof (SysprofSymbol *) * stack_depth); symbols = g_alloca (sizeof (SysprofSymbol *) * stack_depth);
n_symbols = sysprof_document_symbolize_traceable (self, traceable, symbols, stack_depth, &final_context); n_symbols = sysprof_document_symbolize_traceable (self, traceable, symbols, stack_depth, &final_context);
if (n_symbols > 0 && symbols[0]->is_context_switch) if (n_symbols > 0 && _sysprof_symbol_is_context_switch (symbols[0]))
{ {
symbols++; symbols++;
n_symbols--; n_symbols--;

View File

@ -134,7 +134,8 @@ sysprof_elf_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
sysprof_strings_get (strings, path), sysprof_strings_get (strings, path),
sysprof_strings_get (strings, sysprof_elf_get_nick (elf)), sysprof_strings_get (strings, sysprof_elf_get_nick (elf)),
map_begin + (begin_address - file_offset), map_begin + (begin_address - file_offset),
map_begin + (end_address - file_offset)); map_begin + (end_address - file_offset),
SYSPROF_SYMBOL_KIND_USER);
fallback: fallback:
/* Fallback, we failed to locate the symbol within a file we can /* Fallback, we failed to locate the symbol within a file we can
@ -148,7 +149,8 @@ fallback:
end_address = address + 1; end_address = address + 1;
return _sysprof_symbol_new (sysprof_strings_get (strings, name), return _sysprof_symbol_new (sysprof_strings_get (strings, name),
NULL, NULL, begin_address, end_address); NULL, NULL, begin_address, end_address,
SYSPROF_SYMBOL_KIND_USER);
} }
static void static void

View File

@ -210,7 +210,8 @@ create_symbol:
NULL, NULL,
NULL, NULL,
match->address, match->address,
match->address + 1); match->address + 1,
SYSPROF_SYMBOL_KIND_USER);
} }
static void static void

View File

@ -279,7 +279,8 @@ sysprof_kallsyms_symbolizer_symbolize (SysprofSymbolizer *symbolizer,
NULL, NULL,
g_ref_string_acquire (linux_string), g_ref_string_acquire (linux_string),
ksym->address, ksym->address,
next->address ? next->address : ksym->address + LAST_SYMBOL_LEN); next->address ? next->address : ksym->address + LAST_SYMBOL_LEN,
SYSPROF_SYMBOL_KIND_KERNEL);
if (address < ksym->address) if (address < ksym->address)
right = mid; right = mid;
@ -298,7 +299,8 @@ failure:
NULL, NULL,
g_ref_string_acquire (linux_string), g_ref_string_acquire (linux_string),
address, address,
address + 1); address + 1,
SYSPROF_SYMBOL_KIND_KERNEL);
} }
} }

View File

@ -33,17 +33,22 @@ sysprof_process_info_new (SysprofMountNamespace *mount_namespace,
int pid) int pid)
{ {
SysprofProcessInfo *self; SysprofProcessInfo *self;
char pidstr[32];
char symname[32]; char symname[32];
g_snprintf (symname, sizeof symname, "[Process %d]", pid); g_snprintf (symname, sizeof symname, "Process %d", pid);
g_snprintf (pidstr, sizeof pidstr, "(%d)", pid);
self = g_atomic_rc_box_new0 (SysprofProcessInfo); self = g_atomic_rc_box_new0 (SysprofProcessInfo);
self->pid = pid; self->pid = pid;
self->address_layout = sysprof_address_layout_new (); self->address_layout = sysprof_address_layout_new ();
self->symbol_cache = sysprof_symbol_cache_new (); self->symbol_cache = sysprof_symbol_cache_new ();
self->mount_namespace = mount_namespace; self->mount_namespace = mount_namespace;
self->fallback_symbol = _sysprof_symbol_new (g_ref_string_new (symname), NULL, NULL, 0, 0); self->fallback_symbol = _sysprof_symbol_new (g_ref_string_new (symname),
self->fallback_symbol->is_process = TRUE; NULL,
g_ref_string_new (pidstr),
0, 0,
SYSPROF_SYMBOL_KIND_PROCESS);
return self; return self;
} }

View File

@ -38,17 +38,15 @@ struct _SysprofSymbol
SysprofAddress begin_address; SysprofAddress begin_address;
SysprofAddress end_address; SysprofAddress end_address;
guint is_context_switch : 1; guint kind : 3;
guint is_everything : 1;
guint is_untraceable : 1;
guint is_process : 1;
}; };
SysprofSymbol *_sysprof_symbol_new (GRefString *name, SysprofSymbol *_sysprof_symbol_new (GRefString *name,
GRefString *binary_path, GRefString *binary_path,
GRefString *binary_nick, GRefString *binary_nick,
SysprofAddress begin_address, SysprofAddress begin_address,
SysprofAddress end_address); SysprofAddress end_address,
SysprofSymbolKind kind);
static inline SysprofSymbol * static inline SysprofSymbol *
_sysprof_symbol_copy (SysprofSymbol *self) _sysprof_symbol_copy (SysprofSymbol *self)
@ -59,11 +57,8 @@ _sysprof_symbol_copy (SysprofSymbol *self)
self->binary_path ? g_ref_string_acquire (self->binary_path) : NULL, self->binary_path ? g_ref_string_acquire (self->binary_path) : NULL,
self->binary_nick ? g_ref_string_acquire (self->binary_nick) : NULL, self->binary_nick ? g_ref_string_acquire (self->binary_nick) : NULL,
self->begin_address, self->begin_address,
self->end_address); self->end_address,
copy->is_context_switch = self->is_context_switch; self->kind);
copy->is_everything = self->is_everything;
copy->is_untraceable = self->is_untraceable;
copy->is_process = self->is_process;
return copy; return copy;
} }
@ -78,13 +73,16 @@ _sysprof_symbol_equal (const SysprofSymbol *a,
if (a->hash != b->hash) if (a->hash != b->hash)
return FALSE; return FALSE;
if (a->kind != b->kind)
return FALSE;
return strcmp (a->name, b->name) == 0; return strcmp (a->name, b->name) == 0;
} }
static inline gboolean static inline gboolean
_sysprof_symbol_is_context_switch (SysprofSymbol *symbol) _sysprof_symbol_is_context_switch (SysprofSymbol *symbol)
{ {
return symbol->is_context_switch; return symbol->kind == SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH;
} }
G_END_DECLS G_END_DECLS

View File

@ -27,9 +27,10 @@ G_DEFINE_FINAL_TYPE (SysprofSymbol, sysprof_symbol, G_TYPE_OBJECT)
enum { enum {
PROP_0, PROP_0,
PROP_NAME,
PROP_BINARY_NICK, PROP_BINARY_NICK,
PROP_BINARY_PATH, PROP_BINARY_PATH,
PROP_KIND,
PROP_NAME,
N_PROPS N_PROPS
}; };
@ -69,6 +70,10 @@ sysprof_symbol_get_property (GObject *object,
g_value_set_string (value, sysprof_symbol_get_binary_path (self)); g_value_set_string (value, sysprof_symbol_get_binary_path (self));
break; break;
case PROP_KIND:
g_value_set_enum (value, sysprof_symbol_get_kind (self));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@ -97,12 +102,19 @@ sysprof_symbol_class_init (SysprofSymbolClass *klass)
NULL, NULL,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
properties [PROP_KIND] =
g_param_spec_enum ("kind", NULL, NULL,
SYSPROF_TYPE_SYMBOL_KIND,
SYSPROF_SYMBOL_KIND_USER,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties); g_object_class_install_properties (object_class, N_PROPS, properties);
} }
static void static void
sysprof_symbol_init (SysprofSymbol *self) sysprof_symbol_init (SysprofSymbol *self)
{ {
self->kind = SYSPROF_SYMBOL_KIND_USER;
} }
const char * const char *
@ -130,11 +142,12 @@ sysprof_symbol_get_binary_path (SysprofSymbol *self)
} }
SysprofSymbol * SysprofSymbol *
_sysprof_symbol_new (GRefString *name, _sysprof_symbol_new (GRefString *name,
GRefString *binary_path, GRefString *binary_path,
GRefString *binary_nick, GRefString *binary_nick,
SysprofAddress begin_address, SysprofAddress begin_address,
SysprofAddress end_address) SysprofAddress end_address,
SysprofSymbolKind kind)
{ {
SysprofSymbol *self; SysprofSymbol *self;
@ -145,6 +158,7 @@ _sysprof_symbol_new (GRefString *name,
self->begin_address = begin_address; self->begin_address = begin_address;
self->end_address = end_address; self->end_address = end_address;
self->hash = g_str_hash (name); self->hash = g_str_hash (name);
self->kind = kind;
/* If we got a path for the symbol, add that to the hash so that we /* If we got a path for the symbol, add that to the hash so that we
* can be sure that we're working with a symbol in the same file when * can be sure that we're working with a symbol in the same file when
@ -161,6 +175,9 @@ _sysprof_symbol_new (GRefString *name,
self->hash ^= g_str_hash (base); self->hash ^= g_str_hash (base);
} }
if (binary_nick != NULL)
self->hash ^= g_str_hash (binary_nick);
return self; return self;
} }
@ -176,3 +193,17 @@ sysprof_symbol_hash (const SysprofSymbol *self)
{ {
return self->hash; return self->hash;
} }
SysprofSymbolKind
sysprof_symbol_get_kind (SysprofSymbol *self)
{
return self ? self->kind : 0;
}
G_DEFINE_ENUM_TYPE (SysprofSymbolKind, sysprof_symbol_kind,
G_DEFINE_ENUM_VALUE (SYSPROF_SYMBOL_KIND_ROOT, "root"),
G_DEFINE_ENUM_VALUE (SYSPROF_SYMBOL_KIND_PROCESS, "process"),
G_DEFINE_ENUM_VALUE (SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH, "context-switch"),
G_DEFINE_ENUM_VALUE (SYSPROF_SYMBOL_KIND_USER, "user"),
G_DEFINE_ENUM_VALUE (SYSPROF_SYMBOL_KIND_KERNEL, "kernel"),
G_DEFINE_ENUM_VALUE (SYSPROF_SYMBOL_KIND_UNWINDABLE, "unwindable"))

View File

@ -27,21 +27,36 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum _SysprofSymbolKind
{
SYSPROF_SYMBOL_KIND_ROOT = 1,
SYSPROF_SYMBOL_KIND_PROCESS,
SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH,
SYSPROF_SYMBOL_KIND_USER,
SYSPROF_SYMBOL_KIND_KERNEL,
SYSPROF_SYMBOL_KIND_UNWINDABLE,
} SysprofSymbolKind;
#define SYSPROF_TYPE_SYMBOL (sysprof_symbol_get_type()) #define SYSPROF_TYPE_SYMBOL (sysprof_symbol_get_type())
#define SYSPROF_TYPE_SYMBOL_KIND (sysprof_symbol_kind_get_type())
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofSymbol, sysprof_symbol, SYSPROF, SYMBOL, GObject) G_DECLARE_FINAL_TYPE (SysprofSymbol, sysprof_symbol, SYSPROF, SYMBOL, GObject)
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
const char *sysprof_symbol_get_name (SysprofSymbol *self); GType sysprof_symbol_kind_get_type (void) G_GNUC_CONST;
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
const char *sysprof_symbol_get_binary_nick (SysprofSymbol *self); const char *sysprof_symbol_get_name (SysprofSymbol *self);
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
const char *sysprof_symbol_get_binary_path (SysprofSymbol *self); const char *sysprof_symbol_get_binary_nick (SysprofSymbol *self);
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
guint sysprof_symbol_hash (const SysprofSymbol *self); const char *sysprof_symbol_get_binary_path (SysprofSymbol *self);
SYSPROF_AVAILABLE_IN_ALL SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_symbol_equal (const SysprofSymbol *a, SysprofSymbolKind sysprof_symbol_get_kind (SysprofSymbol *self);
const SysprofSymbol *b); SYSPROF_AVAILABLE_IN_ALL
guint sysprof_symbol_hash (const SysprofSymbol *self);
SYSPROF_AVAILABLE_IN_ALL
gboolean sysprof_symbol_equal (const SysprofSymbol *a,
const SysprofSymbol *b);
G_END_DECLS G_END_DECLS

View File

@ -42,7 +42,7 @@ create_symbol (const char *name,
{ {
g_assert (begin < end); g_assert (begin < end);
return _sysprof_symbol_new (g_ref_string_new (name), NULL, NULL, begin, end); return _sysprof_symbol_new (g_ref_string_new (name), NULL, NULL, begin, end, SYSPROF_SYMBOL_KIND_USER);
} }
static int static int