mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-05 13:30:02 -05:00
pw-dot: improve allocation of the DOT data string
This changes avoids constantly reallocating the DOT data string every time someting is added. We now always allocate a DOT data string of size 2048, and we only reallocate by size * 2 if we need more data.
This commit is contained in:
parent
30419c37df
commit
0b5cdf3fd8
1 changed files with 281 additions and 162 deletions
|
|
@ -21,12 +21,19 @@
|
||||||
|
|
||||||
#define GLOBAL_ID_NONE UINT32_MAX
|
#define GLOBAL_ID_NONE UINT32_MAX
|
||||||
#define DEFAULT_DOT_PATH "pw.dot"
|
#define DEFAULT_DOT_PATH "pw.dot"
|
||||||
|
#define DEFAULT_DOT_DATA_SIZE 2048
|
||||||
|
|
||||||
struct global;
|
struct global;
|
||||||
|
|
||||||
typedef void (*draw_t)(struct global *g);
|
typedef void (*draw_t)(struct global *g);
|
||||||
typedef void *(*info_update_t) (void *info, const void *update);
|
typedef void *(*info_update_t) (void *info, const void *update);
|
||||||
|
|
||||||
|
struct dot_data {
|
||||||
|
char *data;
|
||||||
|
size_t size;
|
||||||
|
size_t max_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct data {
|
struct data {
|
||||||
struct pw_main_loop *loop;
|
struct pw_main_loop *loop;
|
||||||
struct pw_context *context;
|
struct pw_context *context;
|
||||||
|
|
@ -38,7 +45,7 @@ struct data {
|
||||||
struct spa_hook registry_listener;
|
struct spa_hook registry_listener;
|
||||||
|
|
||||||
struct spa_list globals;
|
struct spa_list globals;
|
||||||
char *dot_str;
|
struct dot_data dot_data;
|
||||||
const char *dot_rankdir;
|
const char *dot_rankdir;
|
||||||
bool dot_orthoedges;
|
bool dot_orthoedges;
|
||||||
|
|
||||||
|
|
@ -72,95 +79,80 @@ struct global {
|
||||||
struct spa_hook object_listener;
|
struct spa_hook object_listener;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *dot_str_new(void)
|
static bool dot_data_init(struct dot_data * dd, size_t size)
|
||||||
{
|
{
|
||||||
return strdup("");
|
if (size <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dd->data = malloc(sizeof (char) * size);
|
||||||
|
dd->data[0] = '\0';
|
||||||
|
dd->size = 0;
|
||||||
|
dd->max_size = size;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dot_str_clear(char **str)
|
static void dot_data_clear(struct dot_data * dd)
|
||||||
{
|
{
|
||||||
if (str && *str) {
|
if (dd->data) {
|
||||||
free(*str);
|
free(dd->data);
|
||||||
*str = NULL;
|
dd->data = NULL;
|
||||||
|
}
|
||||||
|
dd->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dot_data_ensure_max_size (struct dot_data * dd, size_t size)
|
||||||
|
{
|
||||||
|
size_t new_size = dd->size + size + 1;
|
||||||
|
if (new_size > dd->max_size) {
|
||||||
|
size_t next_size = new_size * 2;
|
||||||
|
dd->data = realloc (dd->data, next_size);
|
||||||
|
dd->max_size = next_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SPA_PRINTF_FUNC(2,0) void dot_str_vadd(char **str, const char *fmt, va_list varargs)
|
static void dot_data_add_uint32 (struct dot_data * dd, uint32_t value)
|
||||||
{
|
{
|
||||||
char *res = NULL;
|
int size;
|
||||||
char *fmt2 = NULL;
|
dot_data_ensure_max_size (dd, 16);
|
||||||
|
size = snprintf (dd->data + dd->size, dd->max_size - dd->size, "%u", value);
|
||||||
spa_return_if_fail(str != NULL);
|
dd->size += size;
|
||||||
spa_return_if_fail(fmt != NULL);
|
|
||||||
|
|
||||||
if (asprintf(&fmt2, "%s%s", *str, fmt) < 0) {
|
|
||||||
spa_assert_not_reached();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vasprintf(&res, fmt2, varargs) < 0) {
|
|
||||||
free (fmt2);
|
|
||||||
spa_assert_not_reached();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
free (fmt2);
|
|
||||||
|
|
||||||
free(*str);
|
|
||||||
*str = res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SPA_PRINTF_FUNC(2,3) void dot_str_add(char **str, const char *fmt, ...)
|
static void dot_data_add_string (struct dot_data * dd, const char *value)
|
||||||
{
|
{
|
||||||
va_list varargs;
|
int size;
|
||||||
va_start(varargs, fmt);
|
dot_data_ensure_max_size (dd, strlen (value));
|
||||||
dot_str_vadd(str, fmt, varargs);
|
size = snprintf (dd->data + dd->size, dd->max_size - dd->size, "%s", value);
|
||||||
va_end(varargs);
|
dd->size += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_dict(char **str, const char *title,
|
static void draw_dict(struct dot_data * dd, const char *title,
|
||||||
const struct spa_dict *props)
|
const struct spa_dict *props)
|
||||||
{
|
{
|
||||||
const struct spa_dict_item *item;
|
const struct spa_dict_item *item;
|
||||||
|
|
||||||
dot_str_add(str, "%s:\\l", title);
|
dot_data_add_string(dd, title);
|
||||||
|
dot_data_add_string(dd, ":\\l");
|
||||||
if (props == NULL || props->n_items == 0) {
|
if (props == NULL || props->n_items == 0) {
|
||||||
dot_str_add(str, "- none\\l");
|
dot_data_add_string(dd, "- none\\l");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spa_dict_for_each(item, props) {
|
spa_dict_for_each(item, props) {
|
||||||
if (item->value)
|
if (item->value) {
|
||||||
dot_str_add(str, "- %s: %s\\l", item->key, item->value);
|
dot_data_add_string(dd, "- ");
|
||||||
else
|
dot_data_add_string(dd, item->key);
|
||||||
dot_str_add(str, "- %s: (null)\\l", item->key);
|
dot_data_add_string(dd, ": ");
|
||||||
|
dot_data_add_string(dd, item->value);
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
} else {
|
||||||
|
dot_data_add_string(dd, "- ");
|
||||||
|
dot_data_add_string(dd, item->key);
|
||||||
|
dot_data_add_string(dd, ": (null)\\l");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static SPA_PRINTF_FUNC(6,0) void draw_vlabel(char **str, const char *name, uint32_t id, bool detail,
|
|
||||||
const struct spa_dict *props, const char *fmt, va_list varargs)
|
|
||||||
{
|
|
||||||
/* draw the label header */
|
|
||||||
dot_str_add(str, "%s_%u [label=\"", name, id);
|
|
||||||
|
|
||||||
/* draw the label body */
|
|
||||||
dot_str_vadd(str, fmt, varargs);
|
|
||||||
|
|
||||||
if (detail)
|
|
||||||
draw_dict(str, "properties", props);
|
|
||||||
|
|
||||||
/*draw the label footer */
|
|
||||||
dot_str_add(str, "%s", "\"];\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static SPA_PRINTF_FUNC(6,7) void draw_label(char **str, const char *name, uint32_t id, bool detail,
|
|
||||||
const struct spa_dict *props, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list varargs;
|
|
||||||
va_start(varargs, fmt);
|
|
||||||
draw_vlabel(str, name, id, detail, props, fmt, varargs);
|
|
||||||
va_end(varargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void draw_port(struct global *g)
|
static void draw_port(struct global *g)
|
||||||
{
|
{
|
||||||
spa_assert(g != NULL);
|
spa_assert(g != NULL);
|
||||||
|
|
@ -168,26 +160,37 @@ static void draw_port(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Port);
|
spa_assert(g->type == INTERFACE_Port);
|
||||||
|
|
||||||
struct pw_port_info *info = g->info;
|
struct pw_port_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
|
const char *port_name = spa_dict_lookup(info->props, PW_KEY_PORT_NAME);
|
||||||
|
|
||||||
/* draw the box */
|
/* draw the box */
|
||||||
dot_str_add(dot_str,
|
dot_data_add_string(dd, "port_");
|
||||||
"port_%u [shape=box style=filled fillcolor=%s];\n",
|
dot_data_add_uint32(dd, g->id);
|
||||||
g->id,
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=");
|
||||||
info->direction == PW_DIRECTION_INPUT ? "lightslateblue" : "lightcoral"
|
dot_data_add_string(dd, info->direction == PW_DIRECTION_INPUT ? "lightslateblue" : "lightcoral");
|
||||||
);
|
dot_data_add_string(dd, "];");
|
||||||
|
|
||||||
/* draw the label */
|
/* draw the label header */
|
||||||
draw_label(dot_str,
|
dot_data_add_string(dd, "port_");
|
||||||
"port", g->id, g->data->show_detail, info->props,
|
dot_data_add_uint32(dd, g->id);
|
||||||
"port_id: %u\\lname: %s\\ldirection: %s\\l",
|
dot_data_add_string(dd, " [label=\"");
|
||||||
g->id,
|
|
||||||
spa_dict_lookup(info->props, PW_KEY_PORT_NAME),
|
/* draw the label body */
|
||||||
pw_direction_as_string(info->direction)
|
dot_data_add_string(dd, "port_id: ");
|
||||||
);
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, "\\lname: ");
|
||||||
|
dot_data_add_string(dd, port_name ? port_name : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\ldirection: ");
|
||||||
|
dot_data_add_string(dd, pw_direction_as_string(info->direction));
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
if (g->data->show_detail)
|
||||||
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
|
/* draw the label footer */
|
||||||
|
dot_data_add_string(dd, "\"];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void draw_node(struct global *g)
|
static void draw_node(struct global *g)
|
||||||
{
|
{
|
||||||
spa_assert(g != NULL);
|
spa_assert(g != NULL);
|
||||||
|
|
@ -195,34 +198,40 @@ static void draw_node(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Node);
|
spa_assert(g->type == INTERFACE_Node);
|
||||||
|
|
||||||
struct pw_node_info *info = g->info;
|
struct pw_node_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
const char *client_id_str, *factory_id_str;
|
const char *node_name, *media_class, *client_id_str, *factory_id_str;
|
||||||
uint32_t client_id, factory_id;
|
uint32_t client_id, factory_id;
|
||||||
|
|
||||||
|
node_name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME);
|
||||||
|
media_class = spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS);
|
||||||
client_id_str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID);
|
client_id_str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID);
|
||||||
factory_id_str = spa_dict_lookup(info->props, PW_KEY_FACTORY_ID);
|
factory_id_str = spa_dict_lookup(info->props, PW_KEY_FACTORY_ID);
|
||||||
client_id = client_id_str ? (uint32_t)atoi(client_id_str) : GLOBAL_ID_NONE;
|
client_id = client_id_str ? (uint32_t)atoi(client_id_str) : GLOBAL_ID_NONE;
|
||||||
factory_id = factory_id_str ? (uint32_t)atoi(factory_id_str) : GLOBAL_ID_NONE;
|
factory_id = factory_id_str ? (uint32_t)atoi(factory_id_str) : GLOBAL_ID_NONE;
|
||||||
|
|
||||||
/* draw the node header */
|
/* draw the node header */
|
||||||
dot_str_add(dot_str, "subgraph cluster_node_%u {\n", g->id);
|
dot_data_add_string(dd, "subgraph cluster_node_");
|
||||||
dot_str_add(dot_str, "bgcolor=palegreen;\n");
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, "{\n");
|
||||||
|
dot_data_add_string(dd, "bgcolor=palegreen;\n");
|
||||||
|
|
||||||
/* draw the label header */
|
/* draw the label header */
|
||||||
dot_str_add(dot_str, "label=\"");
|
dot_data_add_string(dd, "label=\"");
|
||||||
|
|
||||||
/* draw the label body */
|
/* draw the label body */
|
||||||
dot_str_add(dot_str, "node_id: %u\\lname: %s\\lmedia_class: %s\\l",
|
dot_data_add_string(dd, "node_id: ");
|
||||||
g->id,
|
dot_data_add_uint32(dd, g->id);
|
||||||
spa_dict_lookup(info->props, PW_KEY_NODE_NAME),
|
dot_data_add_string(dd, "\\lname: ");
|
||||||
spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS));
|
dot_data_add_string(dd, node_name ? node_name : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\lmedia_class: ");
|
||||||
|
dot_data_add_string(dd, media_class ? media_class : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
if (g->data->show_detail)
|
if (g->data->show_detail)
|
||||||
draw_dict(dot_str, "properties", info->props);
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
/*draw the label footer */
|
/* draw the label footer */
|
||||||
dot_str_add(dot_str, "%s", "\"\n");
|
dot_data_add_string(dd, "\"\n");
|
||||||
|
|
||||||
/* draw all node ports */
|
/* draw all node ports */
|
||||||
struct global *p;
|
struct global *p;
|
||||||
|
|
@ -243,17 +252,33 @@ static void draw_node(struct global *g)
|
||||||
|
|
||||||
/* draw the client/factory box if all option is enabled */
|
/* draw the client/factory box if all option is enabled */
|
||||||
if (g->data->show_all) {
|
if (g->data->show_all) {
|
||||||
dot_str_add(dot_str, "node_%u [shape=box style=filled fillcolor=white];\n", g->id);
|
dot_data_add_string(dd, "node_");
|
||||||
dot_str_add(dot_str, "node_%u [label=\"client_id: %u\\lfactory_id: %u\\l\"];\n", g->id, client_id, factory_id);
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=white];\n");
|
||||||
|
dot_data_add_string(dd, "node_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [label=\"client_id: ");
|
||||||
|
dot_data_add_uint32(dd, client_id);
|
||||||
|
dot_data_add_string(dd, "\\lfactory_id: ");
|
||||||
|
dot_data_add_uint32(dd, factory_id);
|
||||||
|
dot_data_add_string(dd, "\\l\"];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw the node footer */
|
/* draw the node footer */
|
||||||
dot_str_add(dot_str, "}\n");
|
dot_data_add_string(dd, "}\n");
|
||||||
|
|
||||||
/* draw the client/factory arrows if all option is enabled */
|
/* draw the client/factory arrows if all option is enabled */
|
||||||
if (g->data->show_all) {
|
if (g->data->show_all) {
|
||||||
dot_str_add(dot_str, "node_%u -> client_%u [style=dashed];\n", g->id, client_id);
|
dot_data_add_string(dd, "node_");
|
||||||
dot_str_add(dot_str, "node_%u -> factory_%u [style=dashed];\n", g->id, factory_id);
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " -> client_");
|
||||||
|
dot_data_add_uint32(dd, client_id);
|
||||||
|
dot_data_add_string(dd, " [style=dashed];\n");
|
||||||
|
dot_data_add_string(dd, "node_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " -> factory_");
|
||||||
|
dot_data_add_uint32(dd, factory_id);
|
||||||
|
dot_data_add_string(dd, " [style=dashed];\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,25 +289,46 @@ static void draw_link(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Link);
|
spa_assert(g->type == INTERFACE_Link);
|
||||||
|
|
||||||
struct pw_link_info *info = g->info;
|
struct pw_link_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
/* draw the box */
|
/* draw the box */
|
||||||
dot_str_add(dot_str, "link_%u [shape=box style=filled fillcolor=lightblue];\n", g->id);
|
dot_data_add_string(dd, "link_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=lightblue];\n");
|
||||||
|
|
||||||
/* draw the label */
|
/* draw the label header */
|
||||||
draw_label(dot_str,
|
dot_data_add_string(dd, "link_");
|
||||||
"link", g->id, g->data->show_detail, info->props,
|
dot_data_add_uint32(dd, g->id);
|
||||||
"link_id: %u\\loutput_node_id: %u\\linput_node_id: %u\\loutput_port_id: %u\\linput_port_id: %u\\lstate: %s\\l",
|
dot_data_add_string(dd, " [label=\"");
|
||||||
g->id,
|
|
||||||
info->output_node_id,
|
/* draw the label body */
|
||||||
info->input_node_id,
|
dot_data_add_string(dd, "link_id: ");
|
||||||
info->output_port_id,
|
dot_data_add_uint32(dd, g->id);
|
||||||
info->input_port_id,
|
dot_data_add_string(dd, "\\loutput_node_id: ");
|
||||||
pw_link_state_as_string(info->state)
|
dot_data_add_uint32(dd, info->output_node_id);
|
||||||
);
|
dot_data_add_string(dd, "\\linput_node_id: ");
|
||||||
|
dot_data_add_uint32(dd, info->output_node_id);
|
||||||
|
dot_data_add_string(dd, "\\loutput_port_id: ");
|
||||||
|
dot_data_add_uint32(dd, info->output_port_id);
|
||||||
|
dot_data_add_string(dd, "\\linput_node_id: ");
|
||||||
|
dot_data_add_uint32(dd, info->input_port_id);
|
||||||
|
dot_data_add_string(dd, "\\lstate: ");
|
||||||
|
dot_data_add_string(dd, pw_link_state_as_string(info->state));
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
if (g->data->show_detail)
|
||||||
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
|
/* draw the label footer */
|
||||||
|
dot_data_add_string(dd, "\"];\n");
|
||||||
|
|
||||||
/* draw the arrows */
|
/* draw the arrows */
|
||||||
dot_str_add(dot_str, "port_%u -> link_%u -> port_%u;\n", info->output_port_id, g->id, info->input_port_id);
|
dot_data_add_string(dd, "port_");
|
||||||
|
dot_data_add_uint32(dd, info->output_port_id);
|
||||||
|
dot_data_add_string(dd, " -> link_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " -> port_");
|
||||||
|
dot_data_add_uint32(dd, info->input_port_id);
|
||||||
|
dot_data_add_string(dd, ";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_client(struct global *g)
|
static void draw_client(struct global *g)
|
||||||
|
|
@ -292,19 +338,34 @@ static void draw_client(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Client);
|
spa_assert(g->type == INTERFACE_Client);
|
||||||
|
|
||||||
struct pw_client_info *info = g->info;
|
struct pw_client_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
|
const char *app_name = spa_dict_lookup(info->props, PW_KEY_APP_NAME);
|
||||||
|
const char *app_process_id = spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID);
|
||||||
|
|
||||||
/* draw the box */
|
/* draw the box */
|
||||||
dot_str_add(dot_str, "client_%u [shape=box style=filled fillcolor=tan1];\n", g->id);
|
dot_data_add_string(dd, "client_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=tan1];\n");
|
||||||
|
|
||||||
/* draw the label */
|
/* draw the label header */
|
||||||
draw_label(dot_str,
|
dot_data_add_string(dd, "client_");
|
||||||
"client", g->id, g->data->show_detail, info->props,
|
dot_data_add_uint32(dd, g->id);
|
||||||
"client_id: %u\\lname: %s\\lpid: %s\\l",
|
dot_data_add_string(dd, " [label=\"");
|
||||||
g->id,
|
|
||||||
spa_dict_lookup(info->props, PW_KEY_APP_NAME),
|
/* draw the label body */
|
||||||
spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID)
|
dot_data_add_string(dd, "client_id: ");
|
||||||
);
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, "\\lname: ");
|
||||||
|
dot_data_add_string(dd, app_name ? app_name : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\lpid: ");
|
||||||
|
dot_data_add_string(dd, app_process_id ? app_process_id : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
if (g->data->show_detail)
|
||||||
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
|
/* draw the label footer */
|
||||||
|
dot_data_add_string(dd, "\"];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_device(struct global *g)
|
static void draw_device(struct global *g)
|
||||||
|
|
@ -314,30 +375,56 @@ static void draw_device(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Device);
|
spa_assert(g->type == INTERFACE_Device);
|
||||||
|
|
||||||
struct pw_device_info *info = g->info;
|
struct pw_device_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
|
const char *app_name = spa_dict_lookup(info->props, PW_KEY_APP_NAME);
|
||||||
|
const char *media_class = spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS);
|
||||||
|
const char *device_api = spa_dict_lookup(info->props, PW_KEY_DEVICE_API);
|
||||||
|
const char *path = spa_dict_lookup(info->props, PW_KEY_OBJECT_PATH);
|
||||||
const char *client_id_str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID);
|
const char *client_id_str = spa_dict_lookup(info->props, PW_KEY_CLIENT_ID);
|
||||||
const char *factory_id_str = spa_dict_lookup(info->props, PW_KEY_FACTORY_ID);
|
const char *factory_id_str = spa_dict_lookup(info->props, PW_KEY_FACTORY_ID);
|
||||||
uint32_t client_id = client_id_str ? (uint32_t)atoi(client_id_str) : GLOBAL_ID_NONE;
|
uint32_t client_id = client_id_str ? (uint32_t)atoi(client_id_str) : GLOBAL_ID_NONE;
|
||||||
uint32_t factory_id = factory_id_str ? (uint32_t)atoi(factory_id_str) : GLOBAL_ID_NONE;
|
uint32_t factory_id = factory_id_str ? (uint32_t)atoi(factory_id_str) : GLOBAL_ID_NONE;
|
||||||
|
|
||||||
/* draw the box */
|
/* draw the box */
|
||||||
dot_str_add(dot_str, "device_%u [shape=box style=filled fillcolor=lightpink];\n", g->id);
|
dot_data_add_string(dd, "device_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=lightpink];\n");
|
||||||
|
|
||||||
/* draw the label */
|
/* draw the label header */
|
||||||
draw_label(dot_str,
|
dot_data_add_string(dd, "device_");
|
||||||
"device", g->id, g->data->show_detail, info->props,
|
dot_data_add_uint32(dd, g->id);
|
||||||
"device_id: %u\\lname: %s\\lmedia_class: %s\\lapi: %s\\lpath: %s\\l",
|
dot_data_add_string(dd, " [label=\"");
|
||||||
g->id,
|
|
||||||
spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME),
|
/* draw the label body */
|
||||||
spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS),
|
dot_data_add_string(dd, "device_id: ");
|
||||||
spa_dict_lookup(info->props, PW_KEY_DEVICE_API),
|
dot_data_add_uint32(dd, g->id);
|
||||||
spa_dict_lookup(info->props, PW_KEY_OBJECT_PATH)
|
dot_data_add_string(dd, "\\lname: ");
|
||||||
);
|
dot_data_add_string(dd, app_name ? app_name : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\lmedia_class: ");
|
||||||
|
dot_data_add_string(dd, media_class ? media_class : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\lapi: ");
|
||||||
|
dot_data_add_string(dd, device_api ? device_api : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\lpath: ");
|
||||||
|
dot_data_add_string(dd, path ? path : "(null)");
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
if (g->data->show_detail)
|
||||||
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
|
/* draw the label footer */
|
||||||
|
dot_data_add_string(dd, "\"];\n");
|
||||||
|
|
||||||
/* draw the arrows */
|
/* draw the arrows */
|
||||||
dot_str_add(dot_str, "device_%u -> client_%u [style=dashed];\n", g->id, client_id);
|
dot_data_add_string(dd, "device_");
|
||||||
dot_str_add(dot_str, "device_%u -> factory_%u [style=dashed];\n", g->id, factory_id);
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " -> client_");
|
||||||
|
dot_data_add_uint32(dd, client_id);
|
||||||
|
dot_data_add_string(dd, " [style=dashed];\n");
|
||||||
|
dot_data_add_string(dd, "device_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " -> factory_");
|
||||||
|
dot_data_add_uint32(dd, factory_id);
|
||||||
|
dot_data_add_string(dd, " [style=dashed];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_factory(struct global *g)
|
static void draw_factory(struct global *g)
|
||||||
|
|
@ -347,23 +434,41 @@ static void draw_factory(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Factory);
|
spa_assert(g->type == INTERFACE_Factory);
|
||||||
|
|
||||||
struct pw_factory_info *info = g->info;
|
struct pw_factory_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
const char *module_id_str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID);
|
const char *module_id_str = spa_dict_lookup(info->props, PW_KEY_MODULE_ID);
|
||||||
uint32_t module_id = module_id_str ? (uint32_t)atoi(module_id_str) : GLOBAL_ID_NONE;
|
uint32_t module_id = module_id_str ? (uint32_t)atoi(module_id_str) : GLOBAL_ID_NONE;
|
||||||
|
|
||||||
/* draw the box */
|
/* draw the box */
|
||||||
dot_str_add(dot_str, "factory_%u [shape=box style=filled fillcolor=lightyellow];\n", g->id);
|
dot_data_add_string(dd, "factory_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=lightyellow];\n");
|
||||||
|
|
||||||
/* draw the label */
|
/* draw the label header */
|
||||||
draw_label(dot_str,
|
dot_data_add_string(dd, "factory_");
|
||||||
"factory", g->id, g->data->show_detail, info->props,
|
dot_data_add_uint32(dd, g->id);
|
||||||
"factory_id: %u\\lname: %s\\lmodule_id: %u\\l",
|
dot_data_add_string(dd, " [label=\"");
|
||||||
g->id, info->name, module_id
|
|
||||||
);
|
/* draw the label body */
|
||||||
|
dot_data_add_string(dd, "factory_id: ");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, "\\lname: ");
|
||||||
|
dot_data_add_string(dd, info->name);
|
||||||
|
dot_data_add_string(dd, "\\lmodule_id: ");
|
||||||
|
dot_data_add_uint32(dd, module_id);
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
if (g->data->show_detail)
|
||||||
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
|
/* draw the label footer */
|
||||||
|
dot_data_add_string(dd, "\"];\n");
|
||||||
|
|
||||||
/* draw the arrow */
|
/* draw the arrow */
|
||||||
dot_str_add(dot_str, "factory_%u -> module_%u [style=dashed];\n", g->id, module_id);
|
dot_data_add_string(dd, "factory_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " -> module_id");
|
||||||
|
dot_data_add_uint32(dd, module_id);
|
||||||
|
dot_data_add_string(dd, " [style=dashed];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_module(struct global *g)
|
static void draw_module(struct global *g)
|
||||||
|
|
@ -373,17 +478,29 @@ static void draw_module(struct global *g)
|
||||||
spa_assert(g->type == INTERFACE_Module);
|
spa_assert(g->type == INTERFACE_Module);
|
||||||
|
|
||||||
struct pw_module_info *info = g->info;
|
struct pw_module_info *info = g->info;
|
||||||
char **dot_str = &g->data->dot_str;
|
struct dot_data *dd = &g->data->dot_data;
|
||||||
|
|
||||||
/* draw the box */
|
/* draw the box */
|
||||||
dot_str_add(dot_str, "module_%u [shape=box style=filled fillcolor=lightgrey];\n", g->id);
|
dot_data_add_string(dd, "module_");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, " [shape=box style=filled fillcolor=lightgrey];\n");
|
||||||
|
|
||||||
/* draw the label */
|
/* draw the label header */
|
||||||
draw_label(dot_str,
|
dot_data_add_string(dd, "module_id");
|
||||||
"module", g->id, g->data->show_detail, info->props,
|
dot_data_add_uint32(dd, g->id);
|
||||||
"module_id: %u\\lname: %s\\l",
|
dot_data_add_string(dd, " [label=\"");
|
||||||
g->id, info->name
|
|
||||||
);
|
/* draw the label body */
|
||||||
|
dot_data_add_string(dd, "module_id: ");
|
||||||
|
dot_data_add_uint32(dd, g->id);
|
||||||
|
dot_data_add_string(dd, "\\lname: ");
|
||||||
|
dot_data_add_string(dd, info->name);
|
||||||
|
dot_data_add_string(dd, "\\l");
|
||||||
|
if (g->data->show_detail)
|
||||||
|
draw_dict(dd, "properties", info->props);
|
||||||
|
|
||||||
|
/* draw the label footer */
|
||||||
|
dot_data_add_string(dd, "\"];\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_node_id_link_referenced(uint32_t id, struct spa_list *globals)
|
static bool is_node_id_link_referenced(uint32_t id, struct spa_list *globals)
|
||||||
|
|
@ -440,16 +557,18 @@ static int draw_graph(struct data *d, const char *path)
|
||||||
struct global *g;
|
struct global *g;
|
||||||
|
|
||||||
/* draw the header */
|
/* draw the header */
|
||||||
dot_str_add(&d->dot_str, "digraph pipewire {\n");
|
dot_data_add_string(&d->dot_data, "digraph pipewire {\n");
|
||||||
|
|
||||||
if (d->dot_rankdir) {
|
if (d->dot_rankdir) {
|
||||||
/* set rank direction, if provided */
|
/* set rank direction, if provided */
|
||||||
dot_str_add(&d->dot_str, "rankdir = \"%s\";\n", d->dot_rankdir);
|
dot_data_add_string(&d->dot_data, "rankdir = \"");
|
||||||
|
dot_data_add_string(&d->dot_data, d->dot_rankdir);
|
||||||
|
dot_data_add_string(&d->dot_data, "\";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->dot_orthoedges) {
|
if (d->dot_orthoedges) {
|
||||||
/* enable orthogonal edges */
|
/* enable orthogonal edges */
|
||||||
dot_str_add(&d->dot_str, "splines = ortho;\n");
|
dot_data_add_string(&d->dot_data, "splines = ortho;\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* iterate the globals */
|
/* iterate the globals */
|
||||||
|
|
@ -485,11 +604,11 @@ static int draw_graph(struct data *d, const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw the footer */
|
/* draw the footer */
|
||||||
dot_str_add(&d->dot_str, "}\n");
|
dot_data_add_string(&d->dot_data, "}\n");
|
||||||
|
|
||||||
if (spa_streq(path, "-")) {
|
if (spa_streq(path, "-")) {
|
||||||
/* wire the dot graph into to stdout */
|
/* wire the dot graph into to stdout */
|
||||||
fputs(d->dot_str, stdout);
|
fputs(d->dot_data.data, stdout);
|
||||||
} else {
|
} else {
|
||||||
/* open the file */
|
/* open the file */
|
||||||
fp = fopen(path, "we");
|
fp = fopen(path, "we");
|
||||||
|
|
@ -499,7 +618,7 @@ static int draw_graph(struct data *d, const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wire the dot graph into the file */
|
/* wire the dot graph into the file */
|
||||||
fputs(d->dot_str, fp);
|
fputs(d->dot_data.data, fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1124,7 +1243,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(data.dot_str = dot_str_new()))
|
if (!dot_data_init(&data.dot_data, DEFAULT_DOT_DATA_SIZE))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
spa_list_init(&data.globals);
|
spa_list_init(&data.globals);
|
||||||
|
|
@ -1136,7 +1255,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
draw_graph(&data, dot_path);
|
draw_graph(&data, dot_path);
|
||||||
|
|
||||||
dot_str_clear(&data.dot_str);
|
dot_data_clear(&data.dot_data);
|
||||||
spa_list_consume(g, &data.globals, link) {
|
spa_list_consume(g, &data.globals, link) {
|
||||||
if (g->info && g->info_destroy)
|
if (g->info && g->info_destroy)
|
||||||
g->info_destroy(g->info);
|
g->info_destroy(g->info);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue