mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
sysprof: start on symbol categorization
This will end up getting moved a bit to CallgraphNode so that we can look at the parents, but for now just do this so I can test things out a bit and see how we like it. Eventually, the goal would be to categorize the callgraph and show that information in the sidebar for quick overviews of where time is spent. It's a bit laborious to keep up and add symbols for this sort of stuff, but I think the "at a glance" value is pretty huge.
This commit is contained in:
@ -3,6 +3,7 @@ sysprof_sources = [
|
||||
'sysprof-application.c',
|
||||
'sysprof-axis.c',
|
||||
'sysprof-callgraph-view.c',
|
||||
'sysprof-category-icon.c',
|
||||
'sysprof-chart-layer.c',
|
||||
'sysprof-chart.c',
|
||||
'sysprof-color-iter.c',
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "sysprof-resources.h"
|
||||
|
||||
#include "sysprof-callgraph-view-private.h"
|
||||
#include "sysprof-category-icon.h"
|
||||
#include "sysprof-symbol-label-private.h"
|
||||
#include "sysprof-tree-expander.h"
|
||||
|
||||
@ -451,6 +452,7 @@ sysprof_callgraph_view_class_init (SysprofCallgraphViewClass *klass)
|
||||
g_resources_register (sysprof_get_resource ());
|
||||
|
||||
g_type_ensure (PANEL_TYPE_PANED);
|
||||
g_type_ensure (SYSPROF_TYPE_CATEGORY_ICON);
|
||||
g_type_ensure (SYSPROF_TYPE_SYMBOL_LABEL);
|
||||
g_type_ensure (SYSPROF_TYPE_TREE_EXPANDER);
|
||||
}
|
||||
|
||||
@ -207,6 +207,19 @@
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="SysprofCategoryIcon">
|
||||
<property name="width-request">9</property>
|
||||
<property name="height-request">9</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="halign">center</property>
|
||||
<binding name="symbol">
|
||||
<lookup name="symbol" type="SysprofCallgraphFrame">
|
||||
<lookup name="item">expander</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
324
src/sysprof/sysprof-category-icon.c
Normal file
324
src/sysprof/sysprof-category-icon.c
Normal file
@ -0,0 +1,324 @@
|
||||
/* sysprof-category-icon.c
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysprof-category-icon.h"
|
||||
#include "sysprof-symbol-private.h"
|
||||
|
||||
struct _SysprofCategoryIcon
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
SysprofSymbol *symbol;
|
||||
guint category;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SYMBOL,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (SysprofCategoryIcon, sysprof_category_icon, GTK_TYPE_WIDGET)
|
||||
|
||||
enum {
|
||||
CATEGORY_0,
|
||||
CATEGORY_A11Y,
|
||||
CATEGORY_ACTIONS,
|
||||
CATEGORY_CONSTRUCTORS,
|
||||
CATEGORY_CONTEXT_SWITCH,
|
||||
CATEGORY_KERNEL,
|
||||
CATEGORY_LAYOUT,
|
||||
CATEGORY_MAIN_LOOP,
|
||||
CATEGORY_PAINT,
|
||||
CATEGORY_SIGNALS,
|
||||
CATEGORY_TEMPLATES,
|
||||
CATEGORY_WINDOWING,
|
||||
N_CATEGORIES
|
||||
};
|
||||
|
||||
enum {
|
||||
RULE_PREFIX = 1,
|
||||
RULE_EXACT,
|
||||
};
|
||||
|
||||
typedef struct _Rule
|
||||
{
|
||||
guint8 kind : 2;
|
||||
guint8 inherit : 1;
|
||||
guint category;
|
||||
const char *match;
|
||||
} Rule;
|
||||
|
||||
typedef struct _RuleGroup
|
||||
{
|
||||
const char *nick;
|
||||
const Rule *rules;
|
||||
} RuleGroup;
|
||||
|
||||
static GParamSpec *properties [N_PROPS];
|
||||
static GdkRGBA category_colors[N_CATEGORIES];
|
||||
static RuleGroup rule_groups[] = {
|
||||
{ "EGL",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_PAINT, "egl" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "FontConfig",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_LAYOUT, "" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "GLib",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_MAIN_LOOP, "g_main_loop_" },
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_MAIN_LOOP, "g_main_context_" },
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_MAIN_LOOP, "g_wakeup_" },
|
||||
{ RULE_EXACT, FALSE, CATEGORY_MAIN_LOOP, "g_main_dispatch" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "GObject",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_SIGNALS, "g_signal_emit" },
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_SIGNALS, "g_signal_emit" },
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_SIGNALS, "g_object_notify" },
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_CONSTRUCTORS, "g_object_new" },
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_CONSTRUCTORS, "g_type_create_instance" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "GTK 4",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_LAYOUT, "gtk_css_" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_LAYOUT, "gtk_widget_measure" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_PAINT, "gdk_snapshot" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_PAINT, "gtk_snapshot" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_LAYOUT, "gtk_widget_reposition" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_WINDOWING, "gtk_window_present" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_ACTIONS, "gtk_action_muxer_" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_A11Y, "gtk_accessible_" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_A11Y, "gtk_at_" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_TEMPLATES, "gtk_builder_" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_TEMPLATES, "gtk_buildable_" },
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_LAYOUT, "gtk_widget_root" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "libc",
|
||||
(const Rule[]) {
|
||||
{ RULE_EXACT, TRUE, CATEGORY_MAIN_LOOP, "poll" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "Pango",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, FALSE, CATEGORY_LAYOUT, "" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "Wayland Client",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_WINDOWING, "wl_" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
|
||||
{ "Wayland Server",
|
||||
(const Rule[]) {
|
||||
{ RULE_PREFIX, TRUE, CATEGORY_WINDOWING, "wl_" },
|
||||
{ 0 }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static guint
|
||||
categorize_symbol (SysprofSymbol *symbol)
|
||||
{
|
||||
if (symbol->kind == SYSPROF_SYMBOL_KIND_KERNEL)
|
||||
return CATEGORY_KERNEL;
|
||||
else if (symbol->kind == SYSPROF_SYMBOL_KIND_CONTEXT_SWITCH)
|
||||
return CATEGORY_CONTEXT_SWITCH;
|
||||
else if (symbol->kind != SYSPROF_SYMBOL_KIND_USER ||
|
||||
symbol->binary_nick == NULL)
|
||||
return CATEGORY_0;
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (rule_groups); i++)
|
||||
{
|
||||
if (strcmp (rule_groups[i].nick, symbol->binary_nick) != 0)
|
||||
continue;
|
||||
|
||||
for (guint j = 0; rule_groups[i].rules[j].kind; j++)
|
||||
{
|
||||
if (rule_groups[i].rules[j].kind == RULE_PREFIX)
|
||||
{
|
||||
if (g_str_has_prefix (symbol->name, rule_groups[i].rules[j].match))
|
||||
return rule_groups[i].rules[j].category;
|
||||
}
|
||||
else if (rule_groups[i].rules[j].kind == RULE_EXACT)
|
||||
{
|
||||
if (strcmp (symbol->name, rule_groups[i].rules[j].match) == 0)
|
||||
return rule_groups[i].rules[j].category;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return CATEGORY_0;
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_category_icon_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
SysprofCategoryIcon *self = (SysprofCategoryIcon *)widget;
|
||||
const GdkRGBA *color = NULL;
|
||||
|
||||
g_assert (SYSPROF_IS_CATEGORY_ICON (self));
|
||||
g_assert (GTK_IS_SNAPSHOT (snapshot));
|
||||
|
||||
color = &category_colors[self->category];
|
||||
|
||||
if (color->alpha == 0)
|
||||
return;
|
||||
|
||||
gtk_snapshot_append_color (snapshot,
|
||||
color,
|
||||
&GRAPHENE_RECT_INIT (0, 0,
|
||||
gtk_widget_get_width (widget),
|
||||
gtk_widget_get_height (widget)));
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_category_icon_finalize (GObject *object)
|
||||
{
|
||||
SysprofCategoryIcon *self = (SysprofCategoryIcon *)object;
|
||||
|
||||
g_clear_object (&self->symbol);
|
||||
|
||||
G_OBJECT_CLASS (sysprof_category_icon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_category_icon_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCategoryIcon *self = SYSPROF_CATEGORY_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SYMBOL:
|
||||
g_value_set_object (value, sysprof_category_icon_get_symbol (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_category_icon_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SysprofCategoryIcon *self = SYSPROF_CATEGORY_ICON (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SYMBOL:
|
||||
sysprof_category_icon_set_symbol (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_category_icon_class_init (SysprofCategoryIconClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = sysprof_category_icon_finalize;
|
||||
object_class->get_property = sysprof_category_icon_get_property;
|
||||
object_class->set_property = sysprof_category_icon_set_property;
|
||||
|
||||
widget_class->snapshot = sysprof_category_icon_snapshot;
|
||||
|
||||
properties[PROP_SYMBOL] =
|
||||
g_param_spec_object ("symbol", NULL, NULL,
|
||||
SYSPROF_TYPE_SYMBOL,
|
||||
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_A11Y], "#000");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_ACTIONS], "#f66151");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_CONSTRUCTORS], "#613583");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_CONSTRUCTORS], "#62a0ea");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_CONTEXT_SWITCH], "#ffbe6f");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_KERNEL], "#a51d2d");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_LAYOUT], "#9141ac");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_MAIN_LOOP], "#5e5c64");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_PAINT], "#2ec27e");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_SIGNALS], "#e5a50a");
|
||||
gdk_rgba_parse (&category_colors[CATEGORY_TEMPLATES], "#77767b");
|
||||
}
|
||||
|
||||
static void
|
||||
sysprof_category_icon_init (SysprofCategoryIcon *self)
|
||||
{
|
||||
}
|
||||
|
||||
SysprofSymbol *
|
||||
sysprof_category_icon_get_symbol (SysprofCategoryIcon *self)
|
||||
{
|
||||
g_return_val_if_fail (SYSPROF_IS_CATEGORY_ICON (self), NULL);
|
||||
|
||||
return self->symbol;
|
||||
}
|
||||
|
||||
void
|
||||
sysprof_category_icon_set_symbol (SysprofCategoryIcon *self,
|
||||
SysprofSymbol *symbol)
|
||||
{
|
||||
g_return_if_fail (SYSPROF_IS_CATEGORY_ICON (self));
|
||||
|
||||
if (g_set_object (&self->symbol, symbol))
|
||||
{
|
||||
self->category = symbol ? categorize_symbol (symbol) : 0;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SYMBOL]);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
37
src/sysprof/sysprof-category-icon.h
Normal file
37
src/sysprof/sysprof-category-icon.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* sysprof-category-icon.h
|
||||
*
|
||||
* Copyright 2023 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <sysprof.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define SYSPROF_TYPE_CATEGORY_ICON (sysprof_category_icon_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SysprofCategoryIcon, sysprof_category_icon, SYSPROF, CATEGORY_ICON, GtkWidget)
|
||||
|
||||
SysprofSymbol *sysprof_category_icon_get_symbol (SysprofCategoryIcon *self);
|
||||
void sysprof_category_icon_set_symbol (SysprofCategoryIcon *self,
|
||||
SysprofSymbol *symbol);
|
||||
|
||||
G_END_DECLS
|
||||
Reference in New Issue
Block a user