add ggml_backend_sched_dump_dot

This commit is contained in:
Judd 2024-12-14 18:09:39 +08:00
parent 56eea0781c
commit 12d8cd683d
4 changed files with 209 additions and 4 deletions

View file

@ -347,6 +347,9 @@ extern "C" {
GGML_API ggml_backend_buffer_t ggml_backend_cpu_buffer_from_ptr(void * ptr, size_t size);
GGML_API ggml_backend_buffer_type_t ggml_backend_cpu_buffer_type(void);
GGML_API void ggml_backend_sched_splits_fdump_dot(FILE * fp, ggml_backend_sched_t sched, const struct ggml_cgraph * graph);
GGML_API void ggml_backend_sched_dump_dot(ggml_backend_sched_t sched, const struct ggml_cgraph * graph, const char * filename);
#ifdef __cplusplus
}
#endif

View file

@ -14,6 +14,7 @@
#include "ggml-impl.h"
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
@ -21,6 +22,7 @@
#include <string.h>
#include <string>
#include <vector>
#include <set>
#ifdef __APPLE__
#include <sys/types.h>
@ -1997,3 +1999,199 @@ ggml_backend_buffer_t ggml_backend_cpu_buffer_from_ptr(void * ptr, size_t size)
GGML_ASSERT((uintptr_t)ptr % TENSOR_ALIGNMENT == 0 && "buffer pointer must be aligned");
return ggml_backend_buffer_init(ggml_backend_cpu_buffer_from_ptr_type(), ggml_backend_cpu_buffer_from_ptr_i, ptr, size);
}
void ggml_backend_sched_splits_fdump_dot(FILE * fp, ggml_backend_sched_t sched, const struct ggml_cgraph * graph) {
std::set<void *> visited;
for (int i = 0; i < sched->n_splits; i++) {
struct ggml_backend_sched_split * split = &sched->splits[i];
ggml_backend_t split_backend = sched->backends[split->backend_id];
fprintf(fp, " subgraph cluster_%d {"
" node [style=filled];"
" label = \"SPLIT %d : %s # %d inputs\";\n",
i, i, ggml_backend_name(split_backend), split->n_inputs);
for (int j = split->i_start; j < split->i_end; j++) {
struct ggml_tensor *node = graph->nodes[j];
fprintf(fp, " \"%p\";\n", node);
for (int k = 0; k < GGML_MAX_SRC; k++) {
struct ggml_tensor *src = node->src[k];
if ( (nullptr == src)
|| (tensor_backend_id(src) != split->backend_id)
|| (visited.find(src) != visited.end())) {
continue;
}
visited.insert(src);
fprintf(fp, " \"%p\";\n", src);
}
}
fprintf(fp, " }\n");
}
}
static uint32_t simple_hash(const unsigned char *str)
{
uint32_t hash = 5381;
while (unsigned char c = *str++) hash = hash * 33 + c;
return hash;
}
static const char *ggml_color_of_backend(ggml_backend_sched_t sched, struct ggml_tensor * node) {
#ifndef GGML_DOT_FULL_COLOR
#define COLOR_NUM 12
#define DEF_COLOR 0
#else
#define COLOR_NUM 0x1000000
#define DEF_COLOR 0x0ffffff
#endif
static char color[32];
uint32_t color1 = DEF_COLOR;
uint32_t color2 = DEF_COLOR;
ggml_backend_t backend = ggml_backend_sched_get_tensor_backend(sched, node);
if (backend) {
const char *name = ggml_backend_name(backend);
color1 = simple_hash((const unsigned char *)name) % COLOR_NUM;
color2 = color1;
}
if (node->buffer) {
ggml_backend_buffer_type_t buft = node->buffer->buft;
if (backend && !ggml_backend_supports_buft(backend, buft)) {
color2 = simple_hash((const unsigned char *)ggml_backend_buft_name(buft)) % COLOR_NUM;
if (color2 == color1) color2 = (~color1) % COLOR_NUM;
}
}
#ifndef GGML_DOT_FULL_COLOR
snprintf(color, sizeof(color), "%d;0.5:%d", color1 + 1, color2 + 1);
#else
snprintf(color, sizeof(color), "#%06x;0.5:#%06x", color1, color2);
#endif
return color;
}
static void ggml_graph_dump_dot_leaf(ggml_backend_sched_t sched, FILE * fp, std::set<void *> &visited_nodes, struct ggml_tensor * node, struct ggml_tensor *parent, const char *label, const int i) {
if (visited_nodes.find(node) != visited_nodes.end()) {
goto draw_edge;
}
visited_nodes.insert(node);
fprintf(fp, " \"%p\" [ style = filled; fillcolor = \"%s\"; shape = record; label=\"<x>",
(void *)node, ggml_color_of_backend(sched, node));
if (strlen(node->name) > 0) {
fprintf(fp, "%s (%s)|", node->name, ggml_type_name(node->type));
} else {
fprintf(fp, "(%s)|", ggml_type_name(node->type));
}
fprintf(fp, "CONST %d [%" PRId64 ", %" PRId64 "]", i, node->ne[0], node->ne[1]);
fprintf(fp, "\"; ]\n");
draw_edge:
if (parent) {
ggml_graph_dump_dot_leaf_edge(fp, parent, node, label);
}
if (node->view_src) {
ggml_graph_dump_dot_leaf_edge(fp, node, node->view_src, label);
}
}
static void ggml_graph_dump_dot_node(ggml_backend_sched_t sched, FILE * fp, std::set<void *> &visited_nodes, const struct ggml_cgraph * graph, struct ggml_tensor * node, struct ggml_tensor *child, const char *label, const int i);
static void ggml_graph_dump_dot_real_node(ggml_backend_sched_t sched, FILE * fp, std::set<void *> &visited_nodes, const struct ggml_cgraph * graph, struct ggml_tensor * node, struct ggml_tensor *child, const char *label, const int i) {
char color[16];
struct ggml_tensor * grad = nullptr;
if (visited_nodes.find(node) != visited_nodes.end()) {
goto draw_edge;
}
visited_nodes.insert(node);
grad = ggml_graph_get_grad(graph, node);
if (node->flags & GGML_TENSOR_FLAG_PARAM) {
snprintf(color, sizeof(color), "yellow");
} else if (grad) {
snprintf(color, sizeof(color), "lightblue");
} else {
snprintf(color, sizeof(color), "white");
}
fprintf(fp, " \"%p\" [ style = filled; fillcolor = \"%s\"; shape = record; label=\"",
(void *) node, ggml_color_of_backend(sched, node));
if (strlen(node->name) > 0) {
fprintf(fp, "%s (%s)|", node->name, ggml_type_name(node->type));
} else {
fprintf(fp, "(%s)|", ggml_type_name(node->type));
}
if (ggml_is_matrix(node)) {
fprintf(fp, "%d [%" PRId64 ", %" PRId64 "] | <x>%s", i, node->ne[0], node->ne[1], ggml_op_symbol(node->op));
} else {
fprintf(fp, "%d [%" PRId64 ", %" PRId64 ", %" PRId64 "] | <x>%s", i, node->ne[0], node->ne[1], node->ne[2], ggml_op_symbol(node->op));
}
if (grad) {
fprintf(fp, " | <g>%s\"; ]\n", ggml_op_symbol(grad->op));
} else {
fprintf(fp, "\"; ]\n");
}
for (int j = 0; j < GGML_MAX_SRC; j++) {
if (node->src[j]) {
char label[16];
snprintf(label, sizeof(label), "src %d", j);
ggml_graph_dump_dot_node(sched, fp, visited_nodes, graph, node->src[j], node, label, -1);
}
}
draw_edge:
if (child) {
ggml_graph_dump_dot_node_edge(fp, graph, child, node, label);
}
}
static void ggml_graph_dump_dot_node(ggml_backend_sched_t sched, FILE * fp, std::set<void *> &visited_nodes, const struct ggml_cgraph * graph, struct ggml_tensor * node, struct ggml_tensor *child, const char *label, const int i) {
if ((node->op == GGML_OP_NONE) && !(node->flags & GGML_TENSOR_FLAG_PARAM)) {
ggml_graph_dump_dot_leaf(sched, fp, visited_nodes, node, child, label, i);
} else {
ggml_graph_dump_dot_real_node(sched, fp, visited_nodes, graph, node, child, label, i);
}
}
void ggml_backend_sched_dump_dot(ggml_backend_sched_t sched, const struct ggml_cgraph * graph, const char * filename) {
FILE * fp = ggml_fopen(filename, "w");
GGML_ASSERT(fp);
std::set<void *> visited_nodes;
fprintf(fp, "digraph G {\n");
#ifndef GGML_DOT_FULL_COLOR
fprintf(fp, "node [colorscheme=set312]\n");
#endif
fprintf(fp, " newrank = true;\n");
fprintf(fp, " rankdir = TB;\n");
for (int i = 0; i < graph->n_nodes; i++) {
struct ggml_tensor * node = graph->nodes[i];
if (ggml_graph_get_parent(graph, node)) {
continue;
}
ggml_graph_dump_dot_node(sched, fp, visited_nodes, graph, node, NULL, NULL, i);
}
ggml_backend_sched_splits_fdump_dot(fp, sched, graph);
fprintf(fp, "}\n");
fclose(fp);
GGML_LOG_INFO("%s: dot -Tpng %s -o %s.png && open %s.png\n", __func__, filename, filename, filename);
}

View file

@ -551,6 +551,10 @@ static inline ggml_bf16_t ggml_compute_fp32_to_bf16(float s) {
#define GGML_FP32_TO_BF16(x) ggml_compute_fp32_to_bf16(x)
#define GGML_BF16_TO_FP32(x) ggml_compute_bf16_to_fp32(x)
struct ggml_tensor * ggml_graph_get_parent(const struct ggml_cgraph * cgraph, const struct ggml_tensor * node);
void ggml_graph_dump_dot_leaf_edge(FILE * fp, struct ggml_tensor * node, struct ggml_tensor * parent, const char * label);
void ggml_graph_dump_dot_node_edge(FILE * fp, const struct ggml_cgraph * gb, struct ggml_tensor * node, struct ggml_tensor * parent, const char * label);
#ifdef __cplusplus
}
#endif

View file

@ -5987,7 +5987,7 @@ struct ggml_tensor * ggml_graph_get_tensor(const struct ggml_cgraph * cgraph, co
struct ggml_tensor * ggml_graph_get_grad(const struct ggml_cgraph * cgraph, const struct ggml_tensor * node) {
const size_t igrad = ggml_hash_find(&cgraph->visited_hash_set, node);
return igrad != GGML_HASHSET_FULL && ggml_bitset_get(cgraph->visited_hash_set.used, igrad) ? cgraph->grads[igrad] : NULL;
return igrad != GGML_HASHSET_FULL && ggml_bitset_get(cgraph->visited_hash_set.used, igrad) && cgraph->grads ? cgraph->grads[igrad] : NULL;
}
struct ggml_tensor * ggml_graph_get_grad_acc(const struct ggml_cgraph * cgraph, const struct ggml_tensor * node) {
@ -6038,7 +6038,7 @@ static bool ggml_graph_find(const struct ggml_cgraph * cgraph, const struct ggml
return false;
}
static struct ggml_tensor * ggml_graph_get_parent(const struct ggml_cgraph * cgraph, const struct ggml_tensor * node) {
struct ggml_tensor * ggml_graph_get_parent(const struct ggml_cgraph * cgraph, const struct ggml_tensor * node) {
for (int i = 0; i < cgraph->n_nodes; i++) {
struct ggml_tensor * parent = cgraph->nodes[i];
struct ggml_tensor * grad = ggml_graph_get_grad(cgraph, parent);
@ -6051,7 +6051,7 @@ static struct ggml_tensor * ggml_graph_get_parent(const struct ggml_cgraph * cgr
return NULL;
}
static void ggml_graph_dump_dot_node_edge(FILE * fp, const struct ggml_cgraph * gb, struct ggml_tensor * node, struct ggml_tensor * parent, const char * label) {
void ggml_graph_dump_dot_node_edge(FILE * fp, const struct ggml_cgraph * gb, struct ggml_tensor * node, struct ggml_tensor * parent, const char * label) {
struct ggml_tensor * gparent = ggml_graph_get_parent(gb, node);
struct ggml_tensor * gparent0 = ggml_graph_get_parent(gb, parent);
fprintf(fp, " \"%p\":%s -> \"%p\":%s [ arrowhead = %s; style = %s; label = \"%s\"; ]\n",
@ -6064,7 +6064,7 @@ static void ggml_graph_dump_dot_node_edge(FILE * fp, const struct ggml_cgraph *
label);
}
static void ggml_graph_dump_dot_leaf_edge(FILE * fp, struct ggml_tensor * node, struct ggml_tensor * parent, const char * label) {
void ggml_graph_dump_dot_leaf_edge(FILE * fp, struct ggml_tensor * node, struct ggml_tensor * parent, const char * label) {
fprintf(fp, " \"%p\":%s -> \"%p\":%s [ label = \"%s\"; ]\n",
(void *) parent, "x",
(void *) node, "x",