Skip to content

Commit a5410f0

Browse files
author
luker
committed
Add graph logging feature to GGML
This commit introduces a new feature to log the computation graph of the model to a CSV file. The logging can be enabled by setting the environment variable `GGML_LOG_GRAPH` to `1` or `true`. The output file can be customized using `GGML_LOG_GRAPH_FILENAME`. The CSV includes details such as node IDs, names, operations, dimensions, sizes, and flags for each tensor in the graph. The program will terminate after logging the graph. Additionally, the necessary header and source files for graph logging have been added, and the logging function is called after building the model graph.
1 parent 271369d commit a5410f0

File tree

6 files changed

+207
-1
lines changed

6 files changed

+207
-1
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
1+
# GGML GRAPH LOGGING FORK OF LLAMA.CPP
2+
3+
This fork includes a feature to log the computation graph of the model to a CSV file.
4+
5+
## Graph Logging
6+
7+
To enable graph logging, set the environment variable `GGML_LOG_GRAPH` to `1` or `true`:
8+
9+
```bash
10+
export GGML_LOG_GRAPH=1
11+
```
12+
13+
By default, the graph will be written to `ggml_graph.csv` in the current working directory. You can specify a different filename using the `GGML_LOG_GRAPH_FILENAME` environment variable:
14+
15+
```bash
16+
export GGML_LOG_GRAPH_FILENAME=/path/to/your/graph_log.csv
17+
```
18+
19+
**Important:** When graph logging is enabled, the program will terminate immediately after writing the log file.
20+
21+
### Output Format
22+
23+
The output CSV file contains the following columns for each node (tensor) in the graph:
24+
25+
- `node_id`: The memory address of the tensor, serving as a unique ID.
26+
- `name`: The name assigned to the tensor (if any).
27+
- `op`: The GGML operation that produces this tensor.
28+
- `dim0`, `dim1`, `dim2`, `dim3`: The dimensions of the tensor.
29+
- `bytes`: The size of the tensor data in bytes.
30+
- `flags`: Tensor flags (e.g., `PARAM`, `INPUT`, `OUTPUT`, `LEAF`).
31+
- `src0`...`srcN`: The `node_id` (memory address) of the source tensors for this node, up to `GGML_MAX_SRC`.
32+
133
# llama.cpp
234

335
![llama](https://user-images.githubusercontent.com/1991296/230134379-7181e485-c521-4d23-a0d6-f7b3b61ba524.png)

ggml/include/ggml-cpp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "ggml-alloc.h"
99
#include "ggml-backend.h"
1010
#include "gguf.h"
11+
#include "ggml-graph-logging.h"
1112
#include <memory>
1213

1314
// Smart pointers for ggml types

ggml/include/ggml-graph-logging.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// tensor-footprint-estimation.h
2+
#pragma once
3+
4+
#include <stdio.h>
5+
#include <stdint.h>
6+
7+
// Forward declaration for ggml_cgraph
8+
struct ggml_cgraph;
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
// Log the entire computation graph to CSV
15+
void ggml_log_graph(struct ggml_cgraph* cgraph);
16+
17+
#ifdef __cplusplus
18+
}
19+
#endif

ggml/src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ add_library(ggml-base
201201
ggml-threading.h
202202
ggml-quants.c
203203
ggml-quants.h
204-
gguf.cpp)
204+
gguf.cpp
205+
ggml-graph-logging.c)
205206

206207
target_include_directories(ggml-base PRIVATE .)
207208
if (GGML_BACKEND_DL)

ggml/src/ggml-graph-logging.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// ggml-graph-logging.c
2+
#include "ggml-graph-logging.h"
3+
#include <stdlib.h> // for getenv
4+
#include <stdio.h> // for fprintf, stderr
5+
#include <stdbool.h>
6+
#include <string.h>
7+
#include <inttypes.h>
8+
9+
// Include the full definition of ggml structs
10+
#include "ggml.h"
11+
#include "ggml-impl.h" // This includes the full definition of ggml_cgraph
12+
13+
14+
//
15+
// Graph logging
16+
//
17+
// This is a simple logging system for the graph of a GGML model.
18+
//
19+
// The graph is logged to a CSV file.
20+
//
21+
// The CSV file contains the following columns:
22+
//
23+
// - node_id: The unique identifier for the node.
24+
// - name: The name of the node.
25+
// - op: The operation performed by the node.
26+
// - dim0, dim1, dim2, dim3: The dimensions of the node.
27+
// - bytes: The number of bytes in the node.
28+
// - flags: The flags of the node.
29+
// - src0..srcN: The source nodes of the node.
30+
//
31+
// The CSV file is written to the current working directory.
32+
// The CSV file is overwritten if it already exists.
33+
// The program will terminate after the graph is logged.
34+
//
35+
// The graph is logged when the environment variable GGML_LOG_GRAPH is set to 1.
36+
// The filename for the log file can be set using the environment variable GGML_LOG_GRAPH_FILENAME.
37+
//
38+
// The graph is logged using the ggml_log_graph function.
39+
//
40+
41+
42+
static FILE* ggml_graph_log_init(const char* filename) {
43+
FILE* file = fopen(filename, "w");
44+
if (file) {
45+
fprintf(stderr, "%s: Graph logging enabled, will write to '%s'\n", __func__, filename);
46+
47+
// Write CSV header - now with dynamic source columns
48+
fprintf(file, "node_id,name,op,dim0,dim1,dim2,dim3,bytes,flags");
49+
50+
// Add source columns based on GGML_MAX_SRC
51+
for (int i = 0; i < GGML_MAX_SRC; i++) {
52+
fprintf(file, ",src%d", i);
53+
}
54+
fprintf(file, "\n");
55+
} else {
56+
fprintf(stderr, "%s: Error: Failed to open graph file '%s' for writing.\n", __func__, filename);
57+
}
58+
return file;
59+
}
60+
61+
static void ggml_graph_log_free(FILE* file) {
62+
if (file) {
63+
fclose(file);
64+
}
65+
}
66+
67+
static void write_tensor_to_csv(struct ggml_tensor* tensor, const char* custom_flags, FILE* file) {
68+
if (!tensor || !file) return;
69+
70+
// Get flags
71+
const char* flags = custom_flags ? custom_flags : "-";
72+
if (!custom_flags) {
73+
if (tensor->flags & GGML_TENSOR_FLAG_PARAM) {
74+
flags = "PARAM";
75+
} else if (tensor->flags & GGML_TENSOR_FLAG_INPUT) {
76+
flags = "INPUT";
77+
} else if (tensor->flags & GGML_TENSOR_FLAG_OUTPUT) {
78+
flags = "OUTPUT";
79+
}
80+
}
81+
82+
// Calculate size in bytes
83+
size_t total_size = ggml_nbytes(tensor);
84+
85+
// Write base tensor info
86+
fprintf(file,
87+
"%p,%s,%s,%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%.2f,%s",
88+
(void*)tensor, // node_id (pointer for uniqueness)
89+
tensor->name[0] ? tensor->name : "unnamed", // name
90+
ggml_op_name(tensor->op), // op
91+
tensor->ne[0], tensor->ne[1], tensor->ne[2], tensor->ne[3], // dimensions
92+
(double)total_size, // bytes
93+
flags); // flags
94+
95+
// Write all source tensors dynamically
96+
for (int i = 0; i < GGML_MAX_SRC; i++) {
97+
fprintf(file, ",%p", (void*)tensor->src[i]);
98+
}
99+
100+
fprintf(file, "\n");
101+
}
102+
103+
void ggml_log_graph(struct ggml_cgraph* cgraph) {
104+
const char* log_graph_env = getenv("GGML_LOG_GRAPH");
105+
if (!log_graph_env || (strcmp(log_graph_env, "1") != 0 && strcmp(log_graph_env, "true") != 0)) {
106+
return;
107+
}
108+
109+
// Get the filename from the environment variable, or use the default
110+
const char* filename_env = getenv("GGML_LOG_GRAPH_FILENAME");
111+
const char* filename = filename_env ? filename_env : "ggml_graph.csv";
112+
113+
FILE* file = ggml_graph_log_init(filename);
114+
if (!file || !cgraph) {
115+
return;
116+
}
117+
118+
// Process all nodes in the graph
119+
for (int i = 0; i < cgraph->n_nodes; i++) {
120+
struct ggml_tensor* node = cgraph->nodes[i];
121+
write_tensor_to_csv(node, NULL, file);
122+
}
123+
124+
// Process all leaf nodes as well
125+
for (int i = 0; i < cgraph->n_leafs; i++) {
126+
struct ggml_tensor* leaf = cgraph->leafs[i];
127+
if (!leaf) continue;
128+
129+
// Skip if already included in nodes
130+
bool already_processed = false;
131+
for (int j = 0; j < cgraph->n_nodes; j++) {
132+
if (cgraph->nodes[j] == leaf) {
133+
already_processed = true;
134+
break;
135+
}
136+
}
137+
if (already_processed) continue;
138+
139+
write_tensor_to_csv(leaf, "LEAF", file);
140+
}
141+
142+
// Flush the file to ensure all data is written
143+
fflush(file);
144+
ggml_graph_log_free(file);
145+
146+
fprintf(stderr, "Graph logging complete: %d nodes and %d leafs written to CSV file. Terminating.\n",
147+
cgraph->n_nodes, cgraph->n_leafs);
148+
exit(0);
149+
}
150+

src/llama-model.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13064,6 +13064,9 @@ llm_graph_result_ptr llama_model::build_graph(
1306413064
// add on pooling layer
1306513065
llm->build_pooling(gf, cls, cls_b, cls_out, cls_out_b);
1306613066

13067+
// Log the entire computation graph after it's built
13068+
ggml_log_graph(gf);
13069+
1306713070
return std::move(llm->res);
1306813071
}
1306913072

0 commit comments

Comments
 (0)