Loading Documentation/driver-api/interconnect.rst +22 −0 Original line number Diff line number Diff line Loading @@ -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 for these interconnect paths. These interfaces are not currently 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 drivers/interconnect/core.c +66 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,70 @@ static int icc_summary_show(struct seq_file *s, void *data) } 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) { return idr_find(&icc_idr, id); Loading Loading @@ -776,6 +840,8 @@ static int __init icc_init(void) icc_debugfs_dir = debugfs_create_dir("interconnect", NULL); debugfs_create_file("interconnect_summary", 0444, icc_debugfs_dir, NULL, &icc_summary_fops); debugfs_create_file("interconnect_graph", 0444, icc_debugfs_dir, NULL, &icc_graph_fops); return 0; } Loading Loading
Documentation/driver-api/interconnect.rst +22 −0 Original line number Diff line number Diff line Loading @@ -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 for these interconnect paths. These interfaces are not currently 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
drivers/interconnect/core.c +66 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,70 @@ static int icc_summary_show(struct seq_file *s, void *data) } 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) { return idr_find(&icc_idr, id); Loading Loading @@ -776,6 +840,8 @@ static int __init icc_init(void) icc_debugfs_dir = debugfs_create_dir("interconnect", NULL); debugfs_create_file("interconnect_summary", 0444, icc_debugfs_dir, NULL, &icc_summary_fops); debugfs_create_file("interconnect_graph", 0444, icc_debugfs_dir, NULL, &icc_graph_fops); return 0; } Loading