Commit 1a0013c6 authored by Leonard Crestez's avatar Leonard Crestez Committed by Georgi Djakov

interconnect: Add interconnect_graph file to debugfs

The interconnect graphs can be difficult to understand and the current
"interconnect_summary" file doesn't even display links in any way.

Add a new "interconnect_graph" file to debugfs in the graphviz "dot"
format which describes interconnect providers, nodes and links.

The file is human-readable and can be visualized by piping through
graphviz. Example:

ssh $TARGET cat /sys/kernel/debug/interconnect/interconnect_graph \
	| dot -Tsvg > interconnect_graph.svg
Signed-off-by: default avatarLeonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: default avatarGeorgi Djakov <georgi.djakov@linaro.org>
parent b92c35e1
...@@ -91,3 +91,25 @@ Interconnect consumers are the clients which use the interconnect APIs to ...@@ -91,3 +91,25 @@ Interconnect consumers are the clients which use the interconnect APIs to
get paths between endpoints and set their bandwidth/latency/QoS requirements get paths between endpoints and set their bandwidth/latency/QoS requirements
for these interconnect paths. These interfaces are not currently for these interconnect paths. These interfaces are not currently
documented. documented.
Interconnect debugfs interfaces
-------------------------------
Like several other subsystems interconnect will create some files for debugging
and introspection. Files in debugfs are not considered ABI so application
software shouldn't rely on format details change between kernel versions.
``/sys/kernel/debug/interconnect/interconnect_summary``:
Show all interconnect nodes in the system with their aggregated bandwidth
request. Indented under each node show bandwidth requests from each device.
``/sys/kernel/debug/interconnect/interconnect_graph``:
Show the interconnect graph in the graphviz dot format. It shows all
interconnect nodes and links in the system and groups together nodes from the
same provider as subgraphs. The format is human-readable and can also be piped
through dot to generate diagrams in many graphical formats::
$ cat /sys/kernel/debug/interconnect/interconnect_graph | \
dot -Tsvg > interconnect_graph.svg
...@@ -71,6 +71,70 @@ static int icc_summary_show(struct seq_file *s, void *data) ...@@ -71,6 +71,70 @@ static int icc_summary_show(struct seq_file *s, void *data)
} }
DEFINE_SHOW_ATTRIBUTE(icc_summary); DEFINE_SHOW_ATTRIBUTE(icc_summary);
static void icc_graph_show_link(struct seq_file *s, int level,
struct icc_node *n, struct icc_node *m)
{
seq_printf(s, "%s\"%d:%s\" -> \"%d:%s\"\n",
level == 2 ? "\t\t" : "\t",
n->id, n->name, m->id, m->name);
}
static void icc_graph_show_node(struct seq_file *s, struct icc_node *n)
{
seq_printf(s, "\t\t\"%d:%s\" [label=\"%d:%s",
n->id, n->name, n->id, n->name);
seq_printf(s, "\n\t\t\t|avg_bw=%ukBps", n->avg_bw);
seq_printf(s, "\n\t\t\t|peak_bw=%ukBps", n->peak_bw);
seq_puts(s, "\"]\n");
}
static int icc_graph_show(struct seq_file *s, void *data)
{
struct icc_provider *provider;
struct icc_node *n;
int cluster_index = 0;
int i;
seq_puts(s, "digraph {\n\trankdir = LR\n\tnode [shape = record]\n");
mutex_lock(&icc_lock);
/* draw providers as cluster subgraphs */
cluster_index = 0;
list_for_each_entry(provider, &icc_providers, provider_list) {
seq_printf(s, "\tsubgraph cluster_%d {\n", ++cluster_index);
if (provider->dev)
seq_printf(s, "\t\tlabel = \"%s\"\n",
dev_name(provider->dev));
/* draw nodes */
list_for_each_entry(n, &provider->nodes, node_list)
icc_graph_show_node(s, n);
/* draw internal links */
list_for_each_entry(n, &provider->nodes, node_list)
for (i = 0; i < n->num_links; ++i)
if (n->provider == n->links[i]->provider)
icc_graph_show_link(s, 2, n,
n->links[i]);
seq_puts(s, "\t}\n");
}
/* draw external links */
list_for_each_entry(provider, &icc_providers, provider_list)
list_for_each_entry(n, &provider->nodes, node_list)
for (i = 0; i < n->num_links; ++i)
if (n->provider != n->links[i]->provider)
icc_graph_show_link(s, 1, n,
n->links[i]);
mutex_unlock(&icc_lock);
seq_puts(s, "}");
return 0;
}
DEFINE_SHOW_ATTRIBUTE(icc_graph);
static struct icc_node *node_find(const int id) static struct icc_node *node_find(const int id)
{ {
return idr_find(&icc_idr, id); return idr_find(&icc_idr, id);
...@@ -827,6 +891,8 @@ static int __init icc_init(void) ...@@ -827,6 +891,8 @@ static int __init icc_init(void)
icc_debugfs_dir = debugfs_create_dir("interconnect", NULL); icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
debugfs_create_file("interconnect_summary", 0444, debugfs_create_file("interconnect_summary", 0444,
icc_debugfs_dir, NULL, &icc_summary_fops); icc_debugfs_dir, NULL, &icc_summary_fops);
debugfs_create_file("interconnect_graph", 0444,
icc_debugfs_dir, NULL, &icc_graph_fops);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment