Raptor graph explorer tool
Validate Operations / validate-operations (push) Has been cancelled

This commit is contained in:
ilgeco
2026-07-16 11:37:12 +02:00
parent d788178749
commit ae67d720c6
40 changed files with 2879 additions and 0 deletions
@@ -0,0 +1,35 @@
from __future__ import annotations
import shutil
import sys
from pathlib import Path
import pytest
TOOL_ROOT = Path(__file__).parents[1]
sys.path.insert(0, str(TOOL_ROOT))
from raptor_graph_explorer.cli import build_output
@pytest.fixture
def fixture_dir() -> Path:
return Path(__file__).with_name("fixtures")
@pytest.fixture
def built_output(tmp_path: Path, fixture_dir: Path) -> Path:
reports = tmp_path / "reports"
reports.mkdir()
for source in fixture_dir.glob("demo_*.csv"):
shutil.copy2(source, reports / source.name)
output = tmp_path / "built"
build_output([reports], output)
return output
@pytest.fixture
def regression_output(tmp_path: Path, fixture_dir: Path) -> Path:
output = tmp_path / "regressions"
build_output([fixture_dir / "regressions"], output)
return output
@@ -0,0 +1,10 @@
Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id,edge_extra
gc:0,gcb:1:0,16,tensor<4xf32>,spatial1,,0,,a
gc:0,gcb:1:1,16,tensor<4xf32>,spatial1,,1,,a
gcb:1:0,gcb:2:0,16,tensor<4xf32>,spatial1,0,0,,b
gcb:1:1,gcb:2:1,16,tensor<4xf32>,spatial1,1,1,,b
gcb:2:0,gcb:3:0,8,tensor<2xf32>,spatial1,,,7,c
gcb:2:1,gcb:3:1,8,tensor<2xf32>,spatial1,,,8,c
gcb:3:0,gc:4,8,tensor<2xf32>,spatial1,0,,,d
gcb:3:1,gc:4,8,tensor<2xf32>,spatial1,1,,,d
gc:4,mystery:5,,tensor<1xf32>,spatial1,,,,e
1 Source Target Weight Type stage source_lane target_lane channel_id edge_extra
2 gc:0 gcb:1:0 16 tensor<4xf32> spatial1 0 a
3 gc:0 gcb:1:1 16 tensor<4xf32> spatial1 1 a
4 gcb:1:0 gcb:2:0 16 tensor<4xf32> spatial1 0 0 b
5 gcb:1:1 gcb:2:1 16 tensor<4xf32> spatial1 1 1 b
6 gcb:2:0 gcb:3:0 8 tensor<2xf32> spatial1 7 c
7 gcb:2:1 gcb:3:1 8 tensor<2xf32> spatial1 8 c
8 gcb:3:0 gc:4 8 tensor<2xf32> spatial1 0 d
9 gcb:3:1 gc:4 8 tensor<2xf32> spatial1 1 d
10 gc:4 mystery:5 tensor<1xf32> spatial1 e
@@ -0,0 +1,10 @@
Id,op_id,lane,core,ssa_name,node_extra
gc:0,0,,,%0,root
gcb:1:0,1,0,,%1#0,lane
gcb:1:1,1,1,,%1#1,lane
gcb:2:0,2,0,,%2#0,lane
gcb:2:1,2,1,,%2#1,lane
gcb:3:0,3,0,,%3#0,lane
gcb:3:1,3,1,,%3#1,lane
gc:4,4,,,%4,sink
mystery:5,5,,,%5,unknown
1 Id op_id lane core ssa_name node_extra
2 gc:0 0 %0 root
3 gcb:1:0 1 0 %1#0 lane
4 gcb:1:1 1 1 %1#1 lane
5 gcb:2:0 2 0 %2#0 lane
6 gcb:2:1 2 1 %2#1 lane
7 gcb:3:0 3 0 %3#0 lane
8 gcb:3:1 3 1 %3#1 lane
9 gc:4 4 %4 sink
10 mystery:5 5 %5 unknown
@@ -0,0 +1,3 @@
Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id
scb:0:0,sc:1,4,tensor<1xf32>,spatial3,0,,21
scb:0:1,sc:1,4,tensor<1xf32>,spatial3,1,,22
1 Source Target Weight Type stage source_lane target_lane channel_id
2 scb:0:0 sc:1 4 tensor<1xf32> spatial3 0 21
3 scb:0:1 sc:1 4 tensor<1xf32> spatial3 1 22
@@ -0,0 +1,4 @@
Id,op_id,lane,core,ssa_name
scb:0:0,0,0,10,%0
scb:0:1,0,1,11,%0
sc:1,1,,12,%1
1 Id op_id lane core ssa_name
2 scb:0:0 0 0 10 %0
3 scb:0:1 0 1 11 %0
4 sc:1 1 12 %1
@@ -0,0 +1 @@
Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id
1 Source Target Weight Type stage source_lane target_lane channel_id
@@ -0,0 +1,4 @@
Id,op_id,lane,core,ssa_name
gc:0,0,,,%0
gcb:1:0,1,0,,%1
gcb:1:1,1,1,,%1
1 Id op_id lane core ssa_name
2 gc:0 0 %0
3 gcb:1:0 1 0 %1
4 gcb:1:1 1 1 %1
@@ -0,0 +1,65 @@
Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id
gcb:1:0,gcb:2:0,8192,tensor<16x1x8x1x16xf32>,spatial1,0,0,
gcb:1:1,gcb:2:1,8192,tensor<16x1x8x1x16xf32>,spatial1,1,1,
gcb:1:2,gcb:2:2,8192,tensor<16x1x8x1x16xf32>,spatial1,2,2,
gcb:1:3,gcb:2:3,8192,tensor<16x1x8x1x16xf32>,spatial1,3,3,
gcb:1:4,gcb:2:4,8192,tensor<16x1x8x1x16xf32>,spatial1,4,4,
gcb:1:5,gcb:2:5,8192,tensor<16x1x8x1x16xf32>,spatial1,5,5,
gcb:1:6,gcb:2:6,8192,tensor<16x1x8x1x16xf32>,spatial1,6,6,
gcb:1:7,gcb:2:7,8192,tensor<16x1x8x1x16xf32>,spatial1,7,7,
gcb:1:8,gcb:2:8,8192,tensor<16x1x8x1x16xf32>,spatial1,8,8,
gcb:1:9,gcb:2:9,8192,tensor<16x1x8x1x16xf32>,spatial1,9,9,
gcb:1:10,gcb:2:10,8192,tensor<16x1x8x1x16xf32>,spatial1,10,10,
gcb:1:11,gcb:2:11,8192,tensor<16x1x8x1x16xf32>,spatial1,11,11,
gcb:1:12,gcb:2:12,8192,tensor<16x1x8x1x16xf32>,spatial1,12,12,
gcb:1:13,gcb:2:13,8192,tensor<16x1x8x1x16xf32>,spatial1,13,13,
gcb:1:14,gcb:2:14,8192,tensor<16x1x8x1x16xf32>,spatial1,14,14,
gcb:1:15,gcb:2:15,8192,tensor<16x1x8x1x16xf32>,spatial1,15,15,
gcb:2:0,gcb:3:0,8192,tensor<16x1x8x1x16xf32>,spatial1,0,0,
gcb:2:1,gcb:3:1,8192,tensor<16x1x8x1x16xf32>,spatial1,1,1,
gcb:2:2,gcb:3:2,8192,tensor<16x1x8x1x16xf32>,spatial1,2,2,
gcb:2:3,gcb:3:3,8192,tensor<16x1x8x1x16xf32>,spatial1,3,3,
gcb:2:4,gcb:3:4,8192,tensor<16x1x8x1x16xf32>,spatial1,4,4,
gcb:2:5,gcb:3:5,8192,tensor<16x1x8x1x16xf32>,spatial1,5,5,
gcb:2:6,gcb:3:6,8192,tensor<16x1x8x1x16xf32>,spatial1,6,6,
gcb:2:7,gcb:3:7,8192,tensor<16x1x8x1x16xf32>,spatial1,7,7,
gcb:2:8,gcb:3:8,8192,tensor<16x1x8x1x16xf32>,spatial1,8,8,
gcb:2:9,gcb:3:9,8192,tensor<16x1x8x1x16xf32>,spatial1,9,9,
gcb:2:10,gcb:3:10,8192,tensor<16x1x8x1x16xf32>,spatial1,10,10,
gcb:2:11,gcb:3:11,8192,tensor<16x1x8x1x16xf32>,spatial1,11,11,
gcb:2:12,gcb:3:12,8192,tensor<16x1x8x1x16xf32>,spatial1,12,12,
gcb:2:13,gcb:3:13,8192,tensor<16x1x8x1x16xf32>,spatial1,13,13,
gcb:2:14,gcb:3:14,8192,tensor<16x1x8x1x16xf32>,spatial1,14,14,
gcb:2:15,gcb:3:15,8192,tensor<16x1x8x1x16xf32>,spatial1,15,15,
gcb:3:0,gcb:4:0,8192,tensor<16x1x8x1x16xf32>,spatial1,0,0,
gcb:3:1,gcb:4:1,8192,tensor<16x1x8x1x16xf32>,spatial1,1,1,
gcb:3:2,gcb:4:2,8192,tensor<16x1x8x1x16xf32>,spatial1,2,2,
gcb:3:3,gcb:4:3,8192,tensor<16x1x8x1x16xf32>,spatial1,3,3,
gcb:3:4,gcb:4:4,8192,tensor<16x1x8x1x16xf32>,spatial1,4,4,
gcb:3:5,gcb:4:5,8192,tensor<16x1x8x1x16xf32>,spatial1,5,5,
gcb:3:6,gcb:4:6,8192,tensor<16x1x8x1x16xf32>,spatial1,6,6,
gcb:3:7,gcb:4:7,8192,tensor<16x1x8x1x16xf32>,spatial1,7,7,
gcb:3:8,gcb:4:8,8192,tensor<16x1x8x1x16xf32>,spatial1,8,8,
gcb:3:9,gcb:4:9,8192,tensor<16x1x8x1x16xf32>,spatial1,9,9,
gcb:3:10,gcb:4:10,8192,tensor<16x1x8x1x16xf32>,spatial1,10,10,
gcb:3:11,gcb:4:11,8192,tensor<16x1x8x1x16xf32>,spatial1,11,11,
gcb:3:12,gcb:4:12,8192,tensor<16x1x8x1x16xf32>,spatial1,12,12,
gcb:3:13,gcb:4:13,8192,tensor<16x1x8x1x16xf32>,spatial1,13,13,
gcb:3:14,gcb:4:14,8192,tensor<16x1x8x1x16xf32>,spatial1,14,14,
gcb:3:15,gcb:4:15,8192,tensor<16x1x8x1x16xf32>,spatial1,15,15,
gc:0,gcb:1:0,3888,tensor<1x3x18x18xf32>,spatial1,,0,
gc:0,gcb:1:1,3888,tensor<1x3x18x18xf32>,spatial1,,1,
gc:0,gcb:1:2,3888,tensor<1x3x18x18xf32>,spatial1,,2,
gc:0,gcb:1:3,3888,tensor<1x3x18x18xf32>,spatial1,,3,
gc:0,gcb:1:4,3888,tensor<1x3x18x18xf32>,spatial1,,4,
gc:0,gcb:1:5,3888,tensor<1x3x18x18xf32>,spatial1,,5,
gc:0,gcb:1:6,3888,tensor<1x3x18x18xf32>,spatial1,,6,
gc:0,gcb:1:7,3888,tensor<1x3x18x18xf32>,spatial1,,7,
gc:0,gcb:1:8,3888,tensor<1x3x18x18xf32>,spatial1,,8,
gc:0,gcb:1:9,3888,tensor<1x3x18x18xf32>,spatial1,,9,
gc:0,gcb:1:10,3888,tensor<1x3x18x18xf32>,spatial1,,10,
gc:0,gcb:1:11,3888,tensor<1x3x18x18xf32>,spatial1,,11,
gc:0,gcb:1:12,3888,tensor<1x3x18x18xf32>,spatial1,,12,
gc:0,gcb:1:13,3888,tensor<1x3x18x18xf32>,spatial1,,13,
gc:0,gcb:1:14,3888,tensor<1x3x18x18xf32>,spatial1,,14,
gc:0,gcb:1:15,3888,tensor<1x3x18x18xf32>,spatial1,,15,
1 Source Target Weight Type stage source_lane target_lane channel_id
2 gcb:1:0 gcb:2:0 8192 tensor<16x1x8x1x16xf32> spatial1 0 0
3 gcb:1:1 gcb:2:1 8192 tensor<16x1x8x1x16xf32> spatial1 1 1
4 gcb:1:2 gcb:2:2 8192 tensor<16x1x8x1x16xf32> spatial1 2 2
5 gcb:1:3 gcb:2:3 8192 tensor<16x1x8x1x16xf32> spatial1 3 3
6 gcb:1:4 gcb:2:4 8192 tensor<16x1x8x1x16xf32> spatial1 4 4
7 gcb:1:5 gcb:2:5 8192 tensor<16x1x8x1x16xf32> spatial1 5 5
8 gcb:1:6 gcb:2:6 8192 tensor<16x1x8x1x16xf32> spatial1 6 6
9 gcb:1:7 gcb:2:7 8192 tensor<16x1x8x1x16xf32> spatial1 7 7
10 gcb:1:8 gcb:2:8 8192 tensor<16x1x8x1x16xf32> spatial1 8 8
11 gcb:1:9 gcb:2:9 8192 tensor<16x1x8x1x16xf32> spatial1 9 9
12 gcb:1:10 gcb:2:10 8192 tensor<16x1x8x1x16xf32> spatial1 10 10
13 gcb:1:11 gcb:2:11 8192 tensor<16x1x8x1x16xf32> spatial1 11 11
14 gcb:1:12 gcb:2:12 8192 tensor<16x1x8x1x16xf32> spatial1 12 12
15 gcb:1:13 gcb:2:13 8192 tensor<16x1x8x1x16xf32> spatial1 13 13
16 gcb:1:14 gcb:2:14 8192 tensor<16x1x8x1x16xf32> spatial1 14 14
17 gcb:1:15 gcb:2:15 8192 tensor<16x1x8x1x16xf32> spatial1 15 15
18 gcb:2:0 gcb:3:0 8192 tensor<16x1x8x1x16xf32> spatial1 0 0
19 gcb:2:1 gcb:3:1 8192 tensor<16x1x8x1x16xf32> spatial1 1 1
20 gcb:2:2 gcb:3:2 8192 tensor<16x1x8x1x16xf32> spatial1 2 2
21 gcb:2:3 gcb:3:3 8192 tensor<16x1x8x1x16xf32> spatial1 3 3
22 gcb:2:4 gcb:3:4 8192 tensor<16x1x8x1x16xf32> spatial1 4 4
23 gcb:2:5 gcb:3:5 8192 tensor<16x1x8x1x16xf32> spatial1 5 5
24 gcb:2:6 gcb:3:6 8192 tensor<16x1x8x1x16xf32> spatial1 6 6
25 gcb:2:7 gcb:3:7 8192 tensor<16x1x8x1x16xf32> spatial1 7 7
26 gcb:2:8 gcb:3:8 8192 tensor<16x1x8x1x16xf32> spatial1 8 8
27 gcb:2:9 gcb:3:9 8192 tensor<16x1x8x1x16xf32> spatial1 9 9
28 gcb:2:10 gcb:3:10 8192 tensor<16x1x8x1x16xf32> spatial1 10 10
29 gcb:2:11 gcb:3:11 8192 tensor<16x1x8x1x16xf32> spatial1 11 11
30 gcb:2:12 gcb:3:12 8192 tensor<16x1x8x1x16xf32> spatial1 12 12
31 gcb:2:13 gcb:3:13 8192 tensor<16x1x8x1x16xf32> spatial1 13 13
32 gcb:2:14 gcb:3:14 8192 tensor<16x1x8x1x16xf32> spatial1 14 14
33 gcb:2:15 gcb:3:15 8192 tensor<16x1x8x1x16xf32> spatial1 15 15
34 gcb:3:0 gcb:4:0 8192 tensor<16x1x8x1x16xf32> spatial1 0 0
35 gcb:3:1 gcb:4:1 8192 tensor<16x1x8x1x16xf32> spatial1 1 1
36 gcb:3:2 gcb:4:2 8192 tensor<16x1x8x1x16xf32> spatial1 2 2
37 gcb:3:3 gcb:4:3 8192 tensor<16x1x8x1x16xf32> spatial1 3 3
38 gcb:3:4 gcb:4:4 8192 tensor<16x1x8x1x16xf32> spatial1 4 4
39 gcb:3:5 gcb:4:5 8192 tensor<16x1x8x1x16xf32> spatial1 5 5
40 gcb:3:6 gcb:4:6 8192 tensor<16x1x8x1x16xf32> spatial1 6 6
41 gcb:3:7 gcb:4:7 8192 tensor<16x1x8x1x16xf32> spatial1 7 7
42 gcb:3:8 gcb:4:8 8192 tensor<16x1x8x1x16xf32> spatial1 8 8
43 gcb:3:9 gcb:4:9 8192 tensor<16x1x8x1x16xf32> spatial1 9 9
44 gcb:3:10 gcb:4:10 8192 tensor<16x1x8x1x16xf32> spatial1 10 10
45 gcb:3:11 gcb:4:11 8192 tensor<16x1x8x1x16xf32> spatial1 11 11
46 gcb:3:12 gcb:4:12 8192 tensor<16x1x8x1x16xf32> spatial1 12 12
47 gcb:3:13 gcb:4:13 8192 tensor<16x1x8x1x16xf32> spatial1 13 13
48 gcb:3:14 gcb:4:14 8192 tensor<16x1x8x1x16xf32> spatial1 14 14
49 gcb:3:15 gcb:4:15 8192 tensor<16x1x8x1x16xf32> spatial1 15 15
50 gc:0 gcb:1:0 3888 tensor<1x3x18x18xf32> spatial1 0
51 gc:0 gcb:1:1 3888 tensor<1x3x18x18xf32> spatial1 1
52 gc:0 gcb:1:2 3888 tensor<1x3x18x18xf32> spatial1 2
53 gc:0 gcb:1:3 3888 tensor<1x3x18x18xf32> spatial1 3
54 gc:0 gcb:1:4 3888 tensor<1x3x18x18xf32> spatial1 4
55 gc:0 gcb:1:5 3888 tensor<1x3x18x18xf32> spatial1 5
56 gc:0 gcb:1:6 3888 tensor<1x3x18x18xf32> spatial1 6
57 gc:0 gcb:1:7 3888 tensor<1x3x18x18xf32> spatial1 7
58 gc:0 gcb:1:8 3888 tensor<1x3x18x18xf32> spatial1 8
59 gc:0 gcb:1:9 3888 tensor<1x3x18x18xf32> spatial1 9
60 gc:0 gcb:1:10 3888 tensor<1x3x18x18xf32> spatial1 10
61 gc:0 gcb:1:11 3888 tensor<1x3x18x18xf32> spatial1 11
62 gc:0 gcb:1:12 3888 tensor<1x3x18x18xf32> spatial1 12
63 gc:0 gcb:1:13 3888 tensor<1x3x18x18xf32> spatial1 13
64 gc:0 gcb:1:14 3888 tensor<1x3x18x18xf32> spatial1 14
65 gc:0 gcb:1:15 3888 tensor<1x3x18x18xf32> spatial1 15
@@ -0,0 +1,66 @@
Id,op_id,lane,core,ssa_name
gc:0,0,,,%0
gcb:1:0,1,0,,%1
gcb:1:1,1,1,,%1
gcb:1:2,1,2,,%1
gcb:1:3,1,3,,%1
gcb:1:4,1,4,,%1
gcb:1:5,1,5,,%1
gcb:1:6,1,6,,%1
gcb:1:7,1,7,,%1
gcb:1:8,1,8,,%1
gcb:1:9,1,9,,%1
gcb:1:10,1,10,,%1
gcb:1:11,1,11,,%1
gcb:1:12,1,12,,%1
gcb:1:13,1,13,,%1
gcb:1:14,1,14,,%1
gcb:1:15,1,15,,%1
gcb:2:0,2,0,,%2
gcb:2:1,2,1,,%2
gcb:2:2,2,2,,%2
gcb:2:3,2,3,,%2
gcb:2:4,2,4,,%2
gcb:2:5,2,5,,%2
gcb:2:6,2,6,,%2
gcb:2:7,2,7,,%2
gcb:2:8,2,8,,%2
gcb:2:9,2,9,,%2
gcb:2:10,2,10,,%2
gcb:2:11,2,11,,%2
gcb:2:12,2,12,,%2
gcb:2:13,2,13,,%2
gcb:2:14,2,14,,%2
gcb:2:15,2,15,,%2
gcb:3:0,3,0,,%3
gcb:3:1,3,1,,%3
gcb:3:2,3,2,,%3
gcb:3:3,3,3,,%3
gcb:3:4,3,4,,%3
gcb:3:5,3,5,,%3
gcb:3:6,3,6,,%3
gcb:3:7,3,7,,%3
gcb:3:8,3,8,,%3
gcb:3:9,3,9,,%3
gcb:3:10,3,10,,%3
gcb:3:11,3,11,,%3
gcb:3:12,3,12,,%3
gcb:3:13,3,13,,%3
gcb:3:14,3,14,,%3
gcb:3:15,3,15,,%3
gcb:4:0,4,0,,%4
gcb:4:1,4,1,,%4
gcb:4:2,4,2,,%4
gcb:4:3,4,3,,%4
gcb:4:4,4,4,,%4
gcb:4:5,4,5,,%4
gcb:4:6,4,6,,%4
gcb:4:7,4,7,,%4
gcb:4:8,4,8,,%4
gcb:4:9,4,9,,%4
gcb:4:10,4,10,,%4
gcb:4:11,4,11,,%4
gcb:4:12,4,12,,%4
gcb:4:13,4,13,,%4
gcb:4:14,4,14,,%4
gcb:4:15,4,15,,%4
1 Id op_id lane core ssa_name
2 gc:0 0 %0
3 gcb:1:0 1 0 %1
4 gcb:1:1 1 1 %1
5 gcb:1:2 1 2 %1
6 gcb:1:3 1 3 %1
7 gcb:1:4 1 4 %1
8 gcb:1:5 1 5 %1
9 gcb:1:6 1 6 %1
10 gcb:1:7 1 7 %1
11 gcb:1:8 1 8 %1
12 gcb:1:9 1 9 %1
13 gcb:1:10 1 10 %1
14 gcb:1:11 1 11 %1
15 gcb:1:12 1 12 %1
16 gcb:1:13 1 13 %1
17 gcb:1:14 1 14 %1
18 gcb:1:15 1 15 %1
19 gcb:2:0 2 0 %2
20 gcb:2:1 2 1 %2
21 gcb:2:2 2 2 %2
22 gcb:2:3 2 3 %2
23 gcb:2:4 2 4 %2
24 gcb:2:5 2 5 %2
25 gcb:2:6 2 6 %2
26 gcb:2:7 2 7 %2
27 gcb:2:8 2 8 %2
28 gcb:2:9 2 9 %2
29 gcb:2:10 2 10 %2
30 gcb:2:11 2 11 %2
31 gcb:2:12 2 12 %2
32 gcb:2:13 2 13 %2
33 gcb:2:14 2 14 %2
34 gcb:2:15 2 15 %2
35 gcb:3:0 3 0 %3
36 gcb:3:1 3 1 %3
37 gcb:3:2 3 2 %3
38 gcb:3:3 3 3 %3
39 gcb:3:4 3 4 %3
40 gcb:3:5 3 5 %3
41 gcb:3:6 3 6 %3
42 gcb:3:7 3 7 %3
43 gcb:3:8 3 8 %3
44 gcb:3:9 3 9 %3
45 gcb:3:10 3 10 %3
46 gcb:3:11 3 11 %3
47 gcb:3:12 3 12 %3
48 gcb:3:13 3 13 %3
49 gcb:3:14 3 14 %3
50 gcb:3:15 3 15 %3
51 gcb:4:0 4 0 %4
52 gcb:4:1 4 1 %4
53 gcb:4:2 4 2 %4
54 gcb:4:3 4 3 %4
55 gcb:4:4 4 4 %4
56 gcb:4:5 4 5 %4
57 gcb:4:6 4 6 %4
58 gcb:4:7 4 7 %4
59 gcb:4:8 4 8 %4
60 gcb:4:9 4 9 %4
61 gcb:4:10 4 10 %4
62 gcb:4:11 4 11 %4
63 gcb:4:12 4 12 %4
64 gcb:4:13 4 13 %4
65 gcb:4:14 4 14 %4
66 gcb:4:15 4 15 %4
@@ -0,0 +1,2 @@
Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id
scb:1:5,sc:0,512,tensor<1x8x1x16xf32>,spatial3,5,,0
1 Source Target Weight Type stage source_lane target_lane channel_id
2 scb:1:5 sc:0 512 tensor<1x8x1x16xf32> spatial3 5 0
@@ -0,0 +1,17 @@
Id,op_id,lane,core,ssa_name
sc:0,0,,500,%0#0;%0#1;%0#2;%0#3;%0#4
scb:1:0,1,0,380,%1#0;%1#1;%1#2;%1#3
scb:1:1,1,1,419,%1#0;%1#1;%1#2;%1#3
scb:1:2,1,2,420,%1#0;%1#1;%1#2;%1#3
scb:1:3,1,3,421,%1#0;%1#1;%1#2;%1#3
scb:1:4,1,4,459,%1#0;%1#1;%1#2;%1#3
scb:1:5,1,5,460,%1#0;%1#1;%1#2;%1#3
scb:1:6,1,6,461,%1#0;%1#1;%1#2;%1#3
scb:1:7,1,7,498,%1#0;%1#1;%1#2;%1#3
scb:1:8,1,8,499,%1#0;%1#1;%1#2;%1#3
scb:1:9,1,9,501,%1#0;%1#1;%1#2;%1#3
scb:1:10,1,10,502,%1#0;%1#1;%1#2;%1#3
scb:1:11,1,11,539,%1#0;%1#1;%1#2;%1#3
scb:1:12,1,12,540,%1#0;%1#1;%1#2;%1#3
scb:1:13,1,13,541,%1#0;%1#1;%1#2;%1#3
scb:1:14,1,14,580,%1#0;%1#1;%1#2;%1#3
1 Id op_id lane core ssa_name
2 sc:0 0 500 %0#0;%0#1;%0#2;%0#3;%0#4
3 scb:1:0 1 0 380 %1#0;%1#1;%1#2;%1#3
4 scb:1:1 1 1 419 %1#0;%1#1;%1#2;%1#3
5 scb:1:2 1 2 420 %1#0;%1#1;%1#2;%1#3
6 scb:1:3 1 3 421 %1#0;%1#1;%1#2;%1#3
7 scb:1:4 1 4 459 %1#0;%1#1;%1#2;%1#3
8 scb:1:5 1 5 460 %1#0;%1#1;%1#2;%1#3
9 scb:1:6 1 6 461 %1#0;%1#1;%1#2;%1#3
10 scb:1:7 1 7 498 %1#0;%1#1;%1#2;%1#3
11 scb:1:8 1 8 499 %1#0;%1#1;%1#2;%1#3
12 scb:1:9 1 9 501 %1#0;%1#1;%1#2;%1#3
13 scb:1:10 1 10 502 %1#0;%1#1;%1#2;%1#3
14 scb:1:11 1 11 539 %1#0;%1#1;%1#2;%1#3
15 scb:1:12 1 12 540 %1#0;%1#1;%1#2;%1#3
16 scb:1:13 1 13 541 %1#0;%1#1;%1#2;%1#3
17 scb:1:14 1 14 580 %1#0;%1#1;%1#2;%1#3
@@ -0,0 +1,57 @@
from __future__ import annotations
import csv
import os
import sqlite3
from pathlib import Path
import pytest
from raptor_graph_explorer.cli import build_output
def test_operation_core_and_node_kind_aggregation(built_output: Path):
db = sqlite3.connect(built_output / "graph.sqlite")
report = db.execute("SELECT * FROM reports WHERE report_id='demo_graph'").fetchone()
assert report[2:8] == (9, 9, 6, 5, 1, 1)
op = db.execute("SELECT instance_count,lane_count,minimum_lane,maximum_lane FROM aggregate_nodes WHERE aggregate_id='operation:demo_graph:1'").fetchone()
assert op == (2, 2, 0, 1)
assert db.execute("SELECT COUNT(*) FROM aggregate_nodes WHERE report_id='demo_graph' AND level='node_kind'").fetchone()[0] == 3
core = db.execute("SELECT group_key FROM aggregate_nodes WHERE report_id='demo_scheduled' AND level='core' ORDER BY group_key").fetchall()
assert core == [("10",), ("11",), ("12",)]
db.close()
def test_manifest_generation(built_output: Path):
import json
manifest = json.loads((built_output / "manifest.json").read_text())
assert manifest["schema_version"] == 1
assert [report["report_id"] for report in manifest["reports"]] == ["demo_graph", "demo_scheduled"]
assert all("input" not in report for report in manifest["reports"])
def _generated_report(directory: Path, operations=10, lanes=50, edges=500):
directory.mkdir()
with (directory / "generated.nodes.csv").open("w", newline="") as stream:
writer=csv.writer(stream);writer.writerow(["Id","op_id","lane","core","ssa_name"])
for op in range(operations):
for lane in range(lanes):writer.writerow([f"gcb:{op}:{lane}",op,lane,"",f"%{op}"])
with (directory / "generated.edges.csv").open("w", newline="") as stream:
writer=csv.writer(stream);writer.writerow(["Source","Target","Weight","Type","stage","source_lane","target_lane","channel_id"])
for index in range(edges):
op=index%(operations-1);lane=index%lanes;writer.writerow([f"gcb:{op}:{lane}",f"gcb:{op+1}:{lane}",4,"tensor<1xf32>","generated",lane,lane,""])
def test_generated_performance_shape(tmp_path: Path):
_generated_report(tmp_path / "reports")
manifest=build_output([tmp_path / "reports"],tmp_path / "out")
assert manifest["reports"][0]["raw_node_count"] == 500
assert manifest["reports"][0]["raw_edge_count"] == 500
@pytest.mark.slow
@pytest.mark.skipif(not os.getenv("RAPTOR_GRAPH_SLOW"), reason="set RAPTOR_GRAPH_SLOW=1")
def test_100k_edge_smoke(tmp_path: Path):
_generated_report(tmp_path / "reports",operations=100,lanes=1000,edges=100_000)
manifest=build_output([tmp_path / "reports"],tmp_path / "out")
assert manifest["reports"][0]["raw_edge_count"] == 100_000
@@ -0,0 +1,45 @@
from pathlib import Path
from fastapi.testclient import TestClient
import pytest
from raptor_graph_explorer.api import create_app
def test_manifest_graph_motifs_and_pagination(built_output: Path):
client=TestClient(create_app(built_output,max_page_size=2))
assert "Raptor Graph Explorer" in client.get("/").text
assert "runLayout" in client.get("/app.js").text
assert client.get("/api/manifest").status_code==200
assert len(client.get("/api/reports").json())==2
graph=client.get("/api/reports/demo_graph/graph/operation").json()
assert len(graph["nodes"])==6 and len(graph["edges"])==5
assert client.get("/api/reports/demo_graph/motifs").status_code==200
page=client.get("/api/reports/demo_graph/raw-nodes?limit=2").json()
assert page["total"]==9 and len(page["items"])==2
assert client.get("/api/reports/demo_graph/raw-nodes?limit=3").status_code==400
def test_edge_mapping_matrix_and_binning(built_output: Path):
client=TestClient(create_app(built_output,exact_matrix_points=1))
edge="operation:demo_graph:1->2"
detail=client.get(f"/api/aggregate-edges/{edge}").json()
assert detail["mapping_kind"]=="identity"
assert client.get(f"/api/aggregate-edges/{edge}/mapping").json()["total"]==2
matrix=client.get(f"/api/aggregate-edges/{edge}/matrix").json()
assert matrix["mode"]=="binned" and matrix["dimensions"]==[64,64]
def test_expansion_safety_cap(built_output: Path):
client=TestClient(create_app(built_output,expansion_cap=2))
selected="operation:demo_graph:1"
response=client.get(f"/api/reports/demo_graph/subgraph?aggregate_id={selected}&expand_lanes=true")
assert response.status_code==400 and "safety cap" in response.json()["detail"]
def test_unsupported_database_schema_is_rejected(built_output: Path):
import sqlite3
db=sqlite3.connect(built_output/"graph.sqlite")
db.execute("UPDATE metadata SET value='999' WHERE key='schema_version'");db.commit();db.close()
with pytest.raises(ValueError,match="unsupported database schema"):
create_app(built_output)
@@ -0,0 +1,13 @@
from pathlib import Path
from raptor_graph_explorer.cli import main
def test_build_inspect_and_exit_codes(tmp_path: Path, fixture_dir: Path, capsys):
output=tmp_path/"output"
assert main(["build",str(fixture_dir),"--output",str(output)])==0
assert main(["inspect",str(output)])==0
captured=capsys.readouterr().out
assert "demo_graph" in captured and "mappings:" in captured
assert main(["build",str(fixture_dir),"--output",str(output)])==2
assert main(["build",str(tmp_path/"missing"),"--output",str(tmp_path/"bad")])==2
@@ -0,0 +1,36 @@
from __future__ import annotations
import zipfile
from pathlib import Path
from raptor_graph_explorer.discovery import discover_reports
def test_discovers_complete_pairs_and_reports_incomplete(tmp_path: Path, fixture_dir: Path):
nested = tmp_path / "nested"
nested.mkdir()
for path in fixture_dir.glob("demo_graph.*.csv"):
(nested / path.name).write_bytes(path.read_bytes())
(tmp_path / "lonely.nodes.csv").write_text("Id,op_id,lane,core,ssa_name\n")
pairs, diagnostics = discover_reports([tmp_path], tmp_path / "extract")
assert [pair.report_id for pair in pairs] == ["demo_graph"]
assert any(item.code == "incomplete_pair" for item in diagnostics.items)
def test_zip_and_explicit_repeated_inputs(tmp_path: Path, fixture_dir: Path):
archive = tmp_path / "reports.zip"
with zipfile.ZipFile(archive, "w") as zipped:
for path in fixture_dir.glob("demo_graph.*.csv"):
zipped.write(path, f"sub/{path.name}")
pairs, _ = discover_reports([archive], tmp_path / "extract")
assert len(pairs) == 1 and pairs[0].report_id == "demo_graph"
def test_zip_traversal_is_rejected(tmp_path: Path):
archive = tmp_path / "bad.zip"
with zipfile.ZipFile(archive, "w") as zipped:
zipped.writestr("../escape.nodes.csv", "bad")
pairs, diagnostics = discover_reports([archive], tmp_path / "extract")
assert not pairs
assert diagnostics.items[0].code == "invalid_zip"
assert not (tmp_path / "escape.nodes.csv").exists()
@@ -0,0 +1,58 @@
from __future__ import annotations
import json
import sqlite3
from pathlib import Path
from raptor_graph_explorer.cli import build_output
def test_normalization_unknown_columns_prefix_and_lane_fallback(built_output: Path):
db = sqlite3.connect(built_output / "graph.sqlite")
db.row_factory = sqlite3.Row
unknown = db.execute("SELECT * FROM raw_nodes WHERE node_id='mystery:5'").fetchone()
assert unknown["node_kind"] == "unknown:mystery"
assert json.loads(unknown["attributes_json"]) == {"node_extra": "unknown"}
edge = db.execute("SELECT * FROM raw_edges WHERE source_node_id='gcb:2:0'").fetchone()
assert (edge["source_lane"], edge["target_lane"]) == (0, 0)
assert json.loads(edge["attributes_json"])["edge_extra"] == "c"
db.close()
def test_malformed_rows_unknown_endpoint_and_strict_mode(tmp_path: Path):
reports = tmp_path / "reports"; reports.mkdir()
(reports / "bad.nodes.csv").write_text(
"Id,op_id,lane,core,ssa_name\ngc:0,0,,,%0\ngc:1,nope,,,%1\n")
(reports / "bad.edges.csv").write_text(
"Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id\n"
"gc:0,gc:missing,1,tensor<1xf32>,bad,,,\n")
manifest = build_output([reports], tmp_path / "out")
assert manifest["reports"][0]["raw_node_count"] == 1
assert manifest["reports"][0]["raw_edge_count"] == 0
assert manifest["diagnostic_count"] == 2
try:
build_output([reports], tmp_path / "strict", strict=True)
except RuntimeError as exc:
assert "strict build" in str(exc)
else:
raise AssertionError("strict mode accepted invalid rows")
def test_missing_schema_column_is_diagnosed(tmp_path: Path):
reports = tmp_path / "reports"; reports.mkdir()
(reports / "x.nodes.csv").write_text("Id,op_id,lane,core\ngc:0,0,,,\n")
(reports / "x.edges.csv").write_text("Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id\n")
manifest = build_output([reports], tmp_path / "out")
assert manifest["reports"][0]["raw_node_count"] == 0
assert manifest["diagnostic_count"] == 2
def test_explicit_edge_lane_precedes_endpoint_lane(tmp_path: Path):
reports=tmp_path/"reports";reports.mkdir()
(reports/"x.nodes.csv").write_text("Id,op_id,lane,core,ssa_name\ngcb:0:0,0,0,,%0\ngcb:1:0,1,0,,%1\n")
(reports/"x.edges.csv").write_text("Source,Target,Weight,Type,stage,source_lane,target_lane,channel_id\ngcb:0:0,gcb:1:0,1,tensor<1xf32>,x,9,8,\n")
output=tmp_path/"out";build_output([reports],output)
db=sqlite3.connect(output/"graph.sqlite")
assert db.execute("SELECT source_lane,target_lane FROM raw_edges").fetchone()==(9,8)
assert db.execute("SELECT occurrence_count FROM diagnostics WHERE code='contradictory_lane'").fetchone()==(1,)
db.close()
@@ -0,0 +1,22 @@
import pytest
from raptor_graph_explorer.mappings import classify_lane_pairs
@pytest.mark.parametrize(("pairs","kind"),[
([(None,None)],"scalar_to_scalar"), ([(None,0),(None,1)],"scalar_to_batch"),
([(0,None),(1,None)],"batch_to_scalar"), ([(0,0),(1,1)],"identity"),
([(0,2),(1,3)],"constant_offset"), ([(0,1),(1,0)],"permutation"),
([(3,0),(3,1)],"broadcast"), ([(0,3),(1,3)],"fan_in"),
([(0,0),(0,1),(1,1),(1,2)],"stencil"),
([(0,0),(0,2),(1,1)],"irregular"), ([(None,1),(2,3)],"unknown"),
])
def test_all_mapping_classes(pairs,kind):
assert classify_lane_pairs(pairs)[0] == kind
def test_mapping_metadata_is_exact():
assert classify_lane_pairs([(0,2),(1,3)])[1] == {"offset":2}
kind,metadata=classify_lane_pairs([(0,0),(0,1),(1,1),(1,2)])
assert kind == "stencil" and metadata == {"offsets":[0,1]}
assert classify_lane_pairs([(None,2),(None,3)])[1]["target"]["contiguous"] is True
@@ -0,0 +1,51 @@
from __future__ import annotations
import networkx as nx
from raptor_graph_explorer.motifs import detect_motifs
def graph(edges):
result=nx.DiGraph();result.add_edges_from(edges);return result
def test_exact_diamond():
motifs,scc=detect_motifs(graph([("s","a"),("s","b"),("a","t"),("b","t")]))
assert scc == 4 and len(motifs)==1 and motifs[0].kind=="exact_diamond"
def test_longer_rhomboid():
motifs,_=detect_motifs(graph([("s","a"),("a","c"),("c","t"),("s","b"),("b","d"),("d","t")]))
assert len(motifs)==1 and motifs[0].kind=="rhomboid"
def test_three_branch_split_rejoin():
motifs,_=detect_motifs(graph([("s","a"),("s","b"),("s","c"),("a","t"),("b","t"),("c","t")]))
assert len(motifs)==1 and len(motifs[0].branches)==3
def test_nested_motifs_are_preserved():
edges=[("s","a"),("s","b"),("a","c"),("a","d"),("c","e"),("d","e"),("e","t"),("b","t")]
motifs,_=detect_motifs(graph(edges))
assert {(motif.entry,motif.exit) for motif in motifs} == {("a","e"),("s","t")}
def test_disconnected_graph():
motifs,scc=detect_motifs(graph([("s","a"),("s","b"),("a","t"),("b","t"),("x","y")]))
assert len(motifs)==1 and scc==6
def test_cycle_is_condensed():
edges=[("s","a"),("s","b"),("a","c"),("c","a"),("c","t"),("b","t")]
motifs,_=detect_motifs(graph(edges))
assert len(motifs)==1 and motifs[0].contains_cycle
def test_external_entrance_rejected():
edges=[("s","a"),("s","b"),("a","t"),("b","t"),("x","a")]
assert detect_motifs(graph(edges))[0] == []
def test_external_exit_rejected():
edges=[("s","a"),("s","b"),("a","t"),("b","t"),("a","x")]
assert detect_motifs(graph(edges))[0] == []
@@ -0,0 +1,125 @@
from __future__ import annotations
from pathlib import Path
from fastapi.testclient import TestClient
import pytest
from raptor_graph_explorer.api import create_app
from raptor_graph_explorer.database import connect_readonly
from raptor_graph_explorer.projection import DisplayGraphTooLarge, display_graph
def project(output: Path, report_id: str, expanded=(), *, view="operation", cap=5_000):
db = connect_readonly(output / "graph.sqlite")
try:
return display_graph(db, report_id, view=view, expanded_operation_ids=expanded, cap=cap)
finally:
db.close()
def test_spatial1_baseline_and_one_operation_expansion(regression_output: Path):
db = connect_readonly(regression_output / "graph.sqlite")
source_counts = db.execute("""
SELECT operation_node_count,operation_edge_count,raw_node_count,raw_edge_count
FROM reports WHERE report_id='spatial1_graph'
""").fetchone()
db.close()
assert tuple(source_counts) == (5, 4, 65, 64)
baseline = project(regression_output, "spatial1_graph")
assert baseline["counts"] == {
"nodes": 5, "edges": 4, "isolated_nodes": 0,
"raw_nodes": 0, "aggregate_nodes": 5, "raw_edges": 0, "aggregate_edges": 4,
}
expanded = project(regression_output, "spatial1_graph", [1])
node_ids = {node["display_id"] for node in expanded["nodes"]}
assert "operation:spatial1_graph:1" not in node_ids
assert {f"gcb:1:{lane}" for lane in range(16)} <= node_ids
assert {f"operation:spatial1_graph:{op_id}" for op_id in (0, 2, 3, 4)} <= node_ids
aggregate_pairs = {(edge["source_op_id"], edge["target_op_id"])
for edge in expanded["edges"] if edge["representation"] == "aggregate"}
assert aggregate_pairs == {(2, 3), (3, 4)}
assert {(edge["source_op_id"], edge["target_op_id"])
for edge in expanded["edges"] if edge["representation"] == "raw"} == {(0, 1), (1, 2)}
assert len({edge["display_id"] for edge in expanded["edges"]}) == len(expanded["edges"])
def test_expansion_order_is_irrelevant(regression_output: Path):
first = project(regression_output, "spatial1_graph", [1, 2])
second = project(regression_output, "spatial1_graph", [2, 1])
assert first["nodes"] == second["nodes"]
assert first["edges"] == second["edges"]
def test_expand_all_spatial1_is_exact_raw_graph(regression_output: Path):
graph = project(regression_output, "spatial1_graph", range(5))
assert graph["counts"] == {
"nodes": 65, "edges": 64, "isolated_nodes": 0,
"raw_nodes": 65, "aggregate_nodes": 0, "raw_edges": 64, "aggregate_edges": 0,
}
node_ids = {node["node_id"] for node in graph["nodes"]}
assert all(edge["source"] in node_ids and edge["target"] in node_ids for edge in graph["edges"])
identity_edges = [edge for edge in graph["edges"] if edge["source_op_id"] >= 1]
assert identity_edges and all(edge["source_lane"] == edge["target_lane"] for edge in identity_edges)
def test_collapse_reconstructs_every_boundary(regression_output: Path):
graph = project(regression_output, "spatial1_graph", [0, 1, 3, 4])
node_ids = {node["display_id"] for node in graph["nodes"]}
assert "operation:spatial1_graph:2" in node_ids
assert not any(node.get("op_id") == 2 and node["representation"] == "raw" for node in graph["nodes"])
assert all(edge["source"] in node_ids and edge["target"] in node_ids for edge in graph["edges"])
boundaries = {(edge["source_op_id"], edge["target_op_id"]): (edge["source"], edge["target"])
for edge in graph["edges"]
if edge["source_lane"] == 0 or edge["source_lane"] is None and edge["target_lane"] == 0}
assert boundaries[(1, 2)] == ("gcb:1:0", "operation:spatial1_graph:2")
assert boundaries[(2, 3)] == ("operation:spatial1_graph:2", "gcb:3:0")
assert boundaries[(0, 1)] == ("gc:0", "gcb:1:0")
assert boundaries[(3, 4)] == ("gcb:3:0", "gcb:4:0")
assert all(edge["representation"] == "raw" for edge in graph["edges"])
def test_spatial3_includes_isolated_nodes_and_has_distinct_positions(regression_output: Path):
graph = project(regression_output, "spatial3_scheduled", view="raw")
assert graph["counts"] == {
"nodes": 16, "edges": 1, "isolated_nodes": 14,
"raw_nodes": 16, "aggregate_nodes": 0, "raw_edges": 1, "aggregate_edges": 0,
}
nodes = {node["node_id"]: node for node in graph["nodes"]}
assert {"scb:1:0", "scb:1:14", "sc:0"} <= nodes.keys()
assert len({(node["x"], node["y"]) for node in graph["nodes"]}) == 16
assert [(edge["source"], edge["target"]) for edge in graph["edges"]] == [("scb:1:5", "sc:0")]
def test_header_only_edges_preserve_all_nodes(regression_output: Path):
graph = project(regression_output, "empty_edges", view="raw")
assert graph["counts"]["nodes"] == 3
assert graph["counts"]["edges"] == 0
assert graph["counts"]["isolated_nodes"] == 3
def test_projection_cap_is_actionable_and_never_partial(regression_output: Path):
with pytest.raises(DisplayGraphTooLarge, match="Use an aggregate view or increase"):
project(regression_output, "spatial3_scheduled", view="raw", cap=16)
client = TestClient(create_app(regression_output, expansion_cap=16))
response = client.get("/api/reports/spatial3_scheduled/display-graph?view=raw")
assert response.status_code == 400
assert "safety cap" in response.json()["detail"] and "aggregate view" in response.json()["detail"]
def test_display_api_and_static_raw_interactions(regression_output: Path):
client = TestClient(create_app(regression_output))
assert client.get("/api/reports/spatial3_scheduled/display-graph?view=raw").json()["counts"]["nodes"] == 16
index = client.get("/").text
script = client.get("/app.js").text
assert '<option value="raw">Raw instances</option>' in index
assert 'report?.stage === "spatial3"' in script
assert 'local.representation === "raw"' in script
reducer = script[script.index("function reduceEdge"):script.index("function applyFilters")]
assert "state.graph.source(id)" not in reducer
assert "edge.source === edge.target" in reducer
raw_edge_branch = script.index('if (local.representation === "raw")', script.index("async function showEdge"))
aggregate_request = script.index("/api/aggregate-edges/", raw_edge_branch)
assert "return;" in script[raw_edge_branch:aggregate_request]
aggregate_edge = "operation:spatial1_graph:1->2"
assert client.get(f"/api/aggregate-edges/{aggregate_edge}/matrix").status_code == 200