Skip to content

Commit c7060bd

Browse files
committed
roofline: emit per-operand names/types/shapes aligned with in_storage_ids
Each launch's topology now carries, 1:1 with in_storage_ids, the source operand's tensor name (in_names), dtype (in_types) and shape (in_ne). The name makes weight-vs-input unambiguous for the consumer -- a model weight is named e.g. "blk.0.ffn_gate.weight" / "*.bias", a dynamic input "inp_pos" / "cache_k_l0" -- and the per-operand type/shape are correct even for a fused span's non-head operands, which the shared (head-only) geometry record does not describe. The name is taken from the storage root so a view/reshape of a weight keeps the weight's name.
1 parent 0b77fbf commit c7060bd

1 file changed

Lines changed: 57 additions & 12 deletions

File tree

ggml/src/ggml-cuda/ggml-cuda-roofline.cpp

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <cxxabi.h>
2525

2626
#include <algorithm>
27+
#include <array>
2728
#include <atomic>
2829
#include <cstdint>
2930
#include <cstdio>
@@ -80,18 +81,25 @@ struct dispatch {
8081
uint64_t duration_ns = 0;
8182
};
8283

83-
// Per-invocation identity kept for graph reconstruction. The geometry record is shared by every
84-
// op of the same shape, so its ids cannot distinguish repeated layers; these are the ids of this
85-
// specific launch. Ids are storage ids (view_src root), so a consumer that reads a view/reshape of
86-
// a producer's output -- reshape/view/permute launch no kernel and have no row -- still resolves to
87-
// the producing op. out_storage_id is what the launch writes (the last node of a fused span, else
88-
// the node itself); in_storage_ids are the storages it reads from outside the span. The consumer
89-
// links each in_storage_id to the most recent prior launch whose out_storage_id matches (last
90-
// writer wins, which also resolves in-place ops whose output aliases an input).
84+
// Per-launch identity for graph reconstruction: the geometry record is shared across ops of the
85+
// same shape, so only these ids distinguish repeated layers. Ids are storage ids at the view_src
86+
// root, so a read of a view/reshape (which launches no kernel and has no row) still resolves to the
87+
// producing op. The consumer links each in_storage_id to the last prior launch whose out_storage_id
88+
// matches (last writer wins, which also resolves in-place ops).
89+
// One entry per external source (aligned 1:1 with in_storage_ids). Holds each operand's own
90+
// name/type/shape so the consumer can label and classify it (weight vs dynamic input, by name) --
91+
// which a fused row's head-only geometry record can't supply.
92+
struct src_operand {
93+
std::string name;
94+
std::string type; // ggml_type_name
95+
int64_t ne[4] = {0, 0, 0, 0};
96+
};
97+
9198
struct node_topology {
92-
uint64_t out_storage_id = 0;
93-
std::vector<uint64_t> in_storage_ids;
94-
std::string name;
99+
uint64_t out_storage_id = 0;
100+
std::vector<uint64_t> in_storage_ids;
101+
std::vector<src_operand> in_operands; // aligned with in_storage_ids
102+
std::string name;
95103
};
96104

97105
std::mutex g_mutex;
@@ -195,6 +203,18 @@ const ggml_tensor * roofline_storage(const ggml_tensor * t) {
195203
return t;
196204
}
197205

206+
// Capture one source operand's identity (name/type/shape) for the topology, so the consumer can
207+
// label and classify it directly. The name is taken from the storage root (a view of a model
208+
// weight keeps the weight's name), which is what makes weight-vs-input unambiguous.
209+
src_operand make_src_operand(const ggml_tensor * t) {
210+
src_operand op;
211+
const ggml_tensor * root = roofline_storage(t);
212+
op.name = root && root->name[0] ? root->name : (t->name[0] ? t->name : "");
213+
op.type = ggml_type_name(t->type);
214+
for (int d = 0; d < 4; d++) op.ne[d] = t->ne[d];
215+
return op;
216+
}
217+
198218
// Fill a record's geometry and single-node HBM byte fields from one ggml node.
199219
void fill_head_record(op_record & rec, const ggml_tensor * node) {
200220
const ggml_tensor * src0 = node->src[0];
@@ -412,6 +432,27 @@ void write_report() {
412432
out << topo_it->second.in_storage_ids[j];
413433
}
414434
out << "], ";
435+
// Per-operand identity aligned 1:1 with in_storage_ids: the tensor name (unambiguous
436+
// weight-vs-input), its dtype and its shape -- correct even for a fused span's non-head
437+
// operands, which the shared geometry record's head-only src arrays do not describe.
438+
const auto & ops = topo_it->second.in_operands;
439+
out << "\"in_names\": [";
440+
for (size_t j = 0; j < ops.size(); j++) {
441+
if (j) out << ", ";
442+
out << "\""; json_escape(out, ops[j].name); out << "\"";
443+
}
444+
out << "], \"in_types\": [";
445+
for (size_t j = 0; j < ops.size(); j++) {
446+
if (j) out << ", ";
447+
out << "\"" << ops[j].type << "\"";
448+
}
449+
out << "], \"in_ne\": [";
450+
for (size_t j = 0; j < ops.size(); j++) {
451+
if (j) out << ", ";
452+
out << "[" << ops[j].ne[0] << ", " << ops[j].ne[1] << ", "
453+
<< ops[j].ne[2] << ", " << ops[j].ne[3] << "]";
454+
}
455+
out << "], ";
415456
}
416457
if (!rec.fused_nodes.empty()) {
417458
out << "\"fused_ops\": [";
@@ -614,7 +655,10 @@ void ggml_cuda_roofline_begin_op(const struct ggml_tensor * node, void * stream)
614655
topo.out_storage_id = (uint64_t) (uintptr_t) roofline_storage(node);
615656
topo.name = node->name;
616657
for (int j = 0; j < GGML_MAX_SRC; j++) {
617-
if (node->src[j]) topo.in_storage_ids.push_back((uint64_t) (uintptr_t) roofline_storage(node->src[j]));
658+
if (node->src[j]) {
659+
topo.in_storage_ids.push_back((uint64_t) (uintptr_t) roofline_storage(node->src[j]));
660+
topo.in_operands.push_back(make_src_operand(node->src[j]));
661+
}
618662
}
619663

620664
{
@@ -689,6 +733,7 @@ void ggml_cuda_roofline_fuse_ops(const struct ggml_cgraph * cgraph, int node_idx
689733
const uint64_t sid = (uint64_t) (uintptr_t) roofline_storage(n->src[s]);
690734
if (!internal.count(sid) && seen.insert(sid).second) {
691735
topo.in_storage_ids.push_back(sid);
736+
topo.in_operands.push_back(make_src_operand(n->src[s]));
692737
}
693738
}
694739
}

0 commit comments

Comments
 (0)