How CGraph's Graph Visualization (Dump) Feature Generates GraphViz Outputs

CGraph's graph visualization feature generates GraphViz DOT files by traversing the pipeline's element manager, emitting node definitions with optional performance data, and rendering dependency edges between elements and groups.

CGraph is a high-performance C++ DAG (Directed Acyclic Graph) execution engine that includes a built-in dump API for visualizing pipeline topology. The graph visualization functionality converts the internal element structure into standard GraphViz DOT format, enabling developers to inspect node dependencies, group clusters, and execution performance through rendered diagrams. This output integrates seamlessly with GraphViz tools like dot, gvpr, or web-based renderers.

How CGraph's Graph Visualization Works

Pipeline Entry Point: GPipeline::dump

The visualization process begins at GPipeline::dump in src/GraphCtrl/GraphPipeline/GPipeline.cpp (lines 200-214). This method initializes the DOT output stream with a digraph CGraph {} header, sets numeric precision for performance data, and iterates over the internal element_manager_ to trigger element-specific dump routines.

After processing all elements, the method closes the graph definition with a closing brace and resets the stream's formatting flags, producing a complete, self-contained DOT file.

Element Processing and Node Definition

Each pipeline element implements the dump virtual method defined in src/GraphCtrl/GraphElement/GElement.cpp (lines 75-81). The base implementation calls dumpElement to emit the node definition, followed by edge generation for all dependencies.

The node definition consists of two parts:

  1. dumpElementHeader: Writes the node identifier and label in DOT format (p<ptr>[label="..."])
  2. dumpPerfInfo: Appends performance metadata including execution duration and start/finish timestamps when perf_info_ is populated by the performance subsystem

Dependency Edge Rendering

Edges are derived from the run_before_ adjacency list maintained by each element. The dumpEdge method in src/GraphCtrl/GraphElement/GElement.cpp (lines 84-100) handles four connection types:

  • Node-to-node
  • Node-to-group
  • Group-to-node
  • Group-to-group

For connections involving groups, the method adds ltail and lhead attributes to ensure GraphViz draws edges entering or exiting the correct cluster boundaries. When performance tracing is enabled, edges belonging to the longest execution path are rendered in red for critical path visualization.

Group and Cluster Handling

Group elements such as GSome, GRegion, and GCluster override the base dump method to create visual clusters. Located in files like src/GraphCtrl/GraphElement/GGroup/GSome/GSome.inl (lines 87-103), these implementations:

  1. Call dumpGroupLabelBegin from GGroup.cpp to emit subgraph cluster_<ptr> { with custom styling
  2. Recursively invoke dump on all child elements within the cluster
  3. Call dumpGroupLabelEnd to close the subgraph
  4. Emit group-level edges from run_before_ outside the cluster block

This hierarchical approach preserves the logical structure of complex pipelines containing nested regions or parallel sections.

Practical Usage Examples

C++ Implementation

To generate a visualization of your CGraph pipeline:

#include "CGraph.h"
#include <fstream>

int main() {
    auto pipeline = CGRAPH_NAMESPACE::GPipeline::create();
    
    // ... register elements and configure dependencies ...
    
    pipeline->run();                     // execute the pipeline
    
    std::ofstream dot("pipeline.dot");
    pipeline->dump(dot);                 // write GraphViz DOT file
    
    return 0;
}

Render the output using GraphViz command-line tools:

dot -Tpng pipeline.dot -o pipeline.png

Python Implementation

For Python users via PyCGraph bindings:

import cgraph

pipeline = cgraph.GPipeline()

# ... build pipeline and add elements ...

pipeline.run()
dot_text = pipeline.dump()          # returns DOT format string

with open("pipeline.dot", "w") as f:
    f.write(dot_text)

The Python dump() method invokes GPipeline::__dump_4py in python/PyCGraph.cpp (lines 221-225), which creates an ostringstream, calls the C++ dump implementation, and returns the generated string to Python.

Key Source Files for Graph Visualization

File Role
src/GraphCtrl/GraphPipeline/GPipeline.cpp Implements the pipeline-level dump entry point and the Python helper __dump_4py.
src/GraphCtrl/GraphElement/GElement.h / GElement.cpp Defines the base element's dump, dumpEdge, dumpElement* helpers, and performance-info output.
src/GraphCtrl/GraphElement/GGroup/GGroup.cpp Provides dumpGroupLabelBegin/End for cluster handling.
src/GraphCtrl/GraphElement/GGroup/GSome/GSome.inl (and similar files for GRegion, GCluster) Override dump for group elements, embedding child elements inside sub-graph clusters.
python/PyCGraph.cpp Bridges the C++ dump functionality to Python via __dump_4py.

Summary

  • CGraph's graph visualization generates standard GraphViz DOT format through the GPipeline::dump API, enabling visual inspection of pipeline topology.
  • The implementation traverses the element_manager_, invoking virtual dump methods on each element to emit node definitions and dependency edges.
  • Group elements create visual clusters using GraphViz subgraph cluster_* syntax, with specialized handling in GSome, GRegion, and GCluster classes.
  • Performance integration allows the dump output to include execution timestamps and highlight critical path edges in red when profiling data is available.
  • Both C++ and Python APIs support dumping to files or strings, with the Python binding located in python/PyCGraph.cpp.

Frequently Asked Questions

How do I render the DOT file generated by CGraph's dump feature?

Use any GraphViz-compatible renderer. For command-line conversion to PNG: dot -Tpng pipeline.dot -o pipeline.png. Web-based tools like WebGraphviz or integrated IDE plugins can also render the DOT syntax directly without external dependencies.

Can I visualize performance data in the generated graph?

Yes. When you enable CGraph's performance profiling subsystem, the dump method automatically appends duration and timestamp data to node labels. Additionally, edges belonging to the longest execution path are rendered in red, making critical path analysis visible in the GraphViz output.

What is the difference between dumping a pipeline in C++ versus Python?

Functionally, both produce identical DOT output. In C++, you pass an std::ostream (such as std::ofstream) to GPipeline::dump. In Python, calling pipeline.dump() invokes the __dump_4py helper in python/PyCGraph.cpp, which returns the DOT content as a string that you can write to a file or process programmatically.

How does CGraph handle nested groups in the visualization?

Nested groups render as GraphViz clusters using the subgraph cluster_<ptr> syntax. The GGroup base class provides dumpGroupLabelBegin and dumpGroupLabelEnd helpers, while concrete implementations like GSome, GRegion, and GCluster override the dump method to recursively process child elements within their respective cluster boundaries, preserving the hierarchical structure in the visual output.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →