Skip to content

Commit

Permalink
add ggml_backend_sched_dump_dot
Browse files Browse the repository at this point in the history
  • Loading branch information
Judd committed Dec 14, 2024
1 parent 56eea07 commit 12d8cd6
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 4 deletions.
3 changes: 3 additions & 0 deletions ggml/include/ggml-backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
198 changes: 198 additions & 0 deletions ggml/src/ggml-backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
#include "ggml-impl.h"

#include <assert.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <set>

#ifdef __APPLE__
#include <sys/types.h>
Expand Down Expand Up @@ -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);
}
4 changes: 4 additions & 0 deletions ggml/src/ggml-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 4 additions & 4 deletions ggml/src/ggml.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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",
Expand All @@ -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",
Expand Down

0 comments on commit 12d8cd6

Please sign in to comment.