-
Notifications
You must be signed in to change notification settings - Fork 60
JSONNode and WrapperNode
Author: Vinay Ramakrishnaiah (AMD)
This document details two classes that complement the ETFeeder module:
- JSONNode: A lightweight representation of a trace node parsed directly from a JSON-formatted Chakra trace.
- WrapperNode: A format-agnostic wrapper that abstracts over both protobuf-based ETFeederNode/ETFeeder and JSONNode-based feeding, providing a unified API to issue nodes, resolve dependencies, and manage queues.
The JSONNode class represents an operation/node within a JSON-formatted Chakra execution trace. It encapsulates node identifiers, attributes, and dependency tracking, and provides methods to manage child relationships and unresolved parent dependencies. It is designed to be stored in ordered containers and priority queues to support dependency resolution and node issuing.
-
Identification and metadata
-
uint64_t node_id: Unique identifier. -
std::string node_name: The name of the operation. -
int node_type: Node type; communication nodes use specific values. -
bool is_cpu_op: Indicates whether the operation executes on CPU. -
uint64_t runtime: Duration (if present in trace). -
uint64_t num_ops: Operation count (may be absent in JSON input depending on schema).
-
-
Communication metadata (only set for communication nodes)
- Node types considered communication:
- Enums:
COMM_SEND_NODE = 5COMM_RECV_NODE = 6COMM_COLL_NODE = 7
- Enums:
-
uint64_t tensor_size: Tensor size -
int64_t comm_type: communication operator type -
uint32_t comm_priority(defaults to 0 if not present) -
uint64_t comm_size: communication size -
uint32_t comm_src: source -
uint32_t comm_dst: destination -
uint32_t comm_tag: communication tag
- Node types considered communication:
-
Dependency management
-
std::vector<uint64_t> data_deps: IDs of parent nodes this node depends on (parsed from JSONdata_deps). -
std::vector<uint64_t> dep_unresolved_parent_ids_json: Parents not yet loaded or found. -
std::vector<JSONNode> children_vec_json: Child nodes that depend on this node. -
std::set<JSONNode, CompareJSONNodesLT> children_set_json: Ordered set to prevent duplicate children.CompareJSONNodesLTorders bynode_id.
-
-
Ordering/comparison helpers
-
struct CompareJSONNodesLT:a.node_id < b.node_id. -
struct CompareJSONNodesGT: Used for priority queue to order by greaterid(); enables min-issue behavior by flipping priority.
-
-
Hashing
-
namespace std::hash<JSONNode>: Custom hasher combinesid,name,type,is_cpu_op, andruntimefor use in unordered containers.
-
-
Constructors
-
JSONNode(): Default. -
JSONNode(const JSONNode& t): Copy constructor; copies metadata, deps, children; communication fields only ifnode_typeis 5/6/7. -
JSONNode(json data, uint64_t id): Constructs from parsed JSON document and node index (continuous index inworkload_graph). Extracts fields with error tolerance.
-
-
Accessors
uint64_t id() conststd::string name() constint type() constbool isCPUOp() constuint64_t getRuntime() constuint64_t getNumOps() constuint64_t getTensorSize() constint64_t getCommType() constuint32_t getCommPriority() constuint64_t getCommSize() constuint32_t getCommSrc() constuint32_t getCommDst() constuint32_t getCommTag() const
-
Dependency helpers
-
void addDepUnresolvedParentID(uint64_t node_id): Track missing parent. -
std::vector<uint64_t> getDepUnresolvedParentIDs(): Get the list of unresolved parent IDs -
void setDepUnresolvedParentIDs(const std::vector<uint64_t>& dep_unresolved_parent_ids): Update the list of unresolved parent IDs
-
-
Child management
-
void addChild(JSONNode node): Adds child if not already present (checked viachildren_set_json). -
std::vector<JSONNode> getChildren(): Get children nodes
-
-
Operators
-
bool operator==(const JSONNode& other) const: Deep equality across all relevant fields and containers. -
JSONNode& operator=(const JSONNode& other): Assignment copies all fields and containers.
-
- Conditional communication fields: Communication metadata is only valid/populated if
node_typeis send/recv/coll (types 5/6/7). - Input tolerance: JSON parsing is guarded by try/catch; missing fields either default (e.g.,
comm_priority= 0) or emit diagnostic messages. - Deduplication:
addChildprevents duplicates viachildren_set_json;children_vec_jsonmirrors the set order for iteration. - Ordering for issuance:
CompareJSONNodesGTis used to prioritize nodes by ID; coupled with dependency-resolution logic, it ensures deterministic issuance order.
WrapperNode unifies trace feeding across two formats:
- Protobuf (
.etfiles) viaChakra::ETFeederandChakra::ETFeederNode. - JSON (
.jsonfiles) viaJSONNode.
It abstracts the lifecycle (initialization, reading windows, dependency resolution, node issuance), so downstream simulators can consume nodes without format-specific code. It mirrors much of ETFeeder’s API while adding JSON-specific data structures and logic.
-
Format selection and core handles
-
enum format format_type_:ProtobuforJSON(based on filename extension *.et or *.json). -
Chakra::ETFeeder* et_feeder_: Feeder for protobuf traces. -
std::shared_ptr<Chakra::ETFeederNode> node_: Current protobuf node. -
std::ifstream jsonfile_: Input stream for JSON traces. -
json data_: Parsed JSON document (nlohmann::json). -
JSONNode json_node_: Current JSON node. -
int64_t node_idx_ = -1: Index inworkload_grapharray for the current JSON node.
-
-
Queues and dependency tracking (protobuf vs JSON)
- Protobuf queues
std::queue<std::shared_ptr<Chakra::ETFeederNode>> push_back_queue_proto
- JSON queues/graphs
std::queue<JSONNode> push_back_queue_json-
std::unordered_map<uint64_t, JSONNode> dep_graph_json: Loaded nodes by ID. -
std::unordered_set<uint64_t> dep_free_node_id_set_json: IDs currently dependency-free. -
std::priority_queue<JSONNode, std::vector<JSONNode>, CompareJSONNodesGT> dep_free_node_queue_json: JSON nodes ready to issue (ordered byid()). -
std::unordered_set<JSONNode, std::hash<JSONNode>> dep_unresolved_node_set_json: Nodes with unresolved parents (hashed by customstd::hash<JSONNode>).
- Window and completion flags
-
int window_size_json: Number of nodes in JSONworkload_graph. -
bool json_et_complete_: Whether all JSON nodes have been read.
-
- Protobuf queues
-
Construction and initialization
-
WrapperNode(): Default. -
WrapperNode(const WrapperNode& t): Copies format selection, queues, graphs, and current node state. -
WrapperNode(std::string filename): CallscreateWrapper(filename). -
void createWrapper(std::string filename): Detects format from extension:-
.et→ Protobuf: initializesETFeeder. -
.json→ JSON: parses the entire document, setswindow_size_json, and invokesreadNextWindow()(legacy behavior: full-file read).
-
-
~WrapperNode(): Destructor -
void releaseMemory(): Releases underlying resources (delete et_feeder_for protobuf, closes JSON file stream for JSON).
-
-
Node accessors (current node)
std::shared_ptr<Chakra::ETFeederNode> getProtobufNode()JSONNode getJSONNode()
-
Graph management
- Protobuf:
-
void addNode(std::shared_ptr<Chakra::ETFeederNode> node): Delegates toETFeeder::addNode. -
void removeNode(uint64_t node_id): Delegates; may trigger window reads.
-
- JSON:
-
void addNode(JSONNode node): Inserts intodep_graph_json. -
void removeNode(uint64_t node_id): Erases fromdep_graph_json; if not complete and queues underflow, triggersreadNextWindow().
-
- Protobuf:
-
Reading/parsing (JSON)
-
int64_t findNodeIndexJSON(uint64_t node_id): Linear scan ofworkload_graphto find continuous index. -
JSONNode readNode(uint64_t node_idx): BuildsJSONNodefromdata_at index:- For each
data_depsparent ID:- If found in
dep_graph_json, add current node as child to parent. - Else, mark as unresolved via
addDepUnresolvedParentID.
- If found in
- Unresolved nodes are tracked in
dep_unresolved_node_set_json.
- For each
-
void readNextWindow(): Reads nodes and resolves deps in a loop:- Reads all nodes up to
window_size_json. - After each addition, calls
resolveDep(). - Uses an arbitrarily large loop bound (
256 * window_size_json) to ensure repeated resolution attempts. - After reading, any node with zero
data_depsis added todep_free_node_id_set_jsonanddep_free_node_queue_json.
- Reads all nodes up to
-
-
Dependency resolution
-
void resolveDep(): For JSON:- Iterates unresolved nodes; for each unresolved parent ID, checks if now present in
dep_graph_json. - If present, adds current node as child to the parent and removes that unresolved parent ID.
- If a node’s unresolved list becomes empty, it is removed from
dep_unresolved_node_set_json; otherwise, its unresolved list is updated.
- Iterates unresolved nodes; for each unresolved parent ID, checks if now present in
- Protobuf path delegates to
ETFeeder::resolveDep().
-
-
Issuable nodes handling
-
void pushBackIssuableNode(uint64_t node_id): Marks a node as dependency-free and enqueues todep_free_node_queue_json(JSON) or delegates (protobuf). -
void freeChildrenNodes(uint64_t node_id): Upon completing a node:- For each child: remove the completed node ID from
child.data_deps. - If a child becomes dependency-free, add to
dep_free_node_id_set_jsonanddep_free_node_queue_json. - Protobuf path delegates to
ETFeeder::freeChildrenNodes.
- For each child: remove the completed node ID from
-
void getNextIssuableNode(): Retrieves the next dependency-free node:- Protobuf:
node_ = et_feeder_->getNextIssuableNode(). - JSON: Pops top of
dep_free_node_queue_json, setsjson_node_, updatesnode_idx_viafindNodeIndexJSON, and erases from ID set. If queue empty, setsnode_idx_ = -1.
- Protobuf:
-
bool hasNodesToIssue(): Checks whether there are nodes ready to issue:- Protobuf: delegates to
ETFeeder::hasNodesToIssue(). - JSON: Returns
!(dep_graph_json.empty() && dep_free_node_queue_json.empty()).
- Protobuf: delegates to
-
-
Queue utilities (format-generic wrappers)
-
void push_to_queue(): Pushes current node topush_back_queue_*. -
bool is_queue_empty(): Checks the appropriate push-back queue. -
void queue_front(): Sets current node from the front of the queue. -
void pop_from_queue(): Pops the front element.
-
-
Common metadata accessors (format-agnostic)
uint64_t getNodeID()std::string getNodeName()int getNodeType()bool isCPUOp()uint64_t getRuntime()uint64_t getNumOps()uint64_t getTensorSize()int64_t getCommType()uint32_t getCommPriority()uint64_t getCommSize()uint32_t getCommSrc()uint32_t getCommDst()uint32_t getCommTag()- Protobuf-only:
uint32_t getCommSrcOff()uint32_t getCommDstOff()
-
Children access
- Protobuf:
void getChildren(std::vector<std::shared_ptr<Chakra::ETFeederNode>>& childrenNodes) - JSON:
void getChildren(std::vector<JSONNode>& childrenNodes)
- Protobuf:
-
Lookup (retrieve by ID)
-
void lookupNode(uint64_t node_id): Protobuf delegates toETFeeder::lookupNode. - JSON uses
dep_graph_json.at(node_id); throws and logs if not loaded yet.
-
-
Initialization
- Create a
WrapperNodewith the trace filename:-
WrapperNode wrapper("path/to/trace.et")orWrapperNode wrapper("path/to/trace.json").
-
-
createWrapperdetects format (.et→ Protobuf,.json→ JSON). - For JSON, the full document is parsed and
readNextWindow()builds the dependency graph.
- Create a
-
Simulation loop
- Check readiness:
hasNodesToIssue(). - Retrieve next issuable node:
getNextIssuableNode().- Protobuf: returns
ETFeederNodevia internal state. - JSON: returns
JSONNodeviagetJSONNode().
- Protobuf: returns
- Process the node in your simulator.
- After completion:
- Free children dependencies:
freeChildrenNodes(node_id). - Optionally remove from graph:
removeNode(node_id)(JSON will read more if needed).
- Free children dependencies:
- Continue until
hasNodesToIssue()returns false.
- Check readiness:
-
Node inspection
- Access common metadata (
getNodeID,getNodeName, etc.) regardless of format. - Retrieve children via the appropriate
getChildrenoverload.
- Access common metadata (
- Format detection: WrapperNode determines trace format from the filename extension. Ensure correct extensions (
.etfor protobuf,.jsonfor JSON). - JSON reading strategy: Legacy design reads the entire JSON file at once and performs iterative dependency resolution across the whole graph.
- Issuance order: JSON dependency-free nodes are managed in a priority queue ordered by
id()(CompareJSONNodesGT), ensuring deterministic issuance. - Duplicate prevention: The JSON path uses sets (
dep_free_node_id_set_json, children sets) to avoid re-enqueuing or adding duplicate references. - Error handling: Many operations log to
std::cerrandexit(-1)on fatal path errors (e.g., unsupported format), so ensure inputs are valid. - Memory management: Call
releaseMemory()when done to close streams (JSON) or delete feeder (protobuf). - Protobuf-only fields:
getCommSrcOff()andgetCommDstOff()are only valid in protobuf mode; calling them in JSON mode triggers an error.
WrapperNode mirrors ETFeeder concepts (windows, dependency graph, dependency-free priority queue, unresolved set) while providing a uniform API across formats. For protobuf, most operations delegate to ETFeeder/ETFeederNode. For JSON, analogous data structures in WrapperNode and JSONNode implement equivalent functionality.
For broader context on ETFeeder's design, see the Chakra ETFeeder documentation:
- Chakra ETFeeder wiki (overview, methods, and workflow).
JSONNode and WrapperNode extend the Chakra Feeder's capabilities to handle JSON traces and provide a format-agnostic interface for simulators. Understanding their attributes and methods will help integrate Chakra traces into downstream tools while preserving correctness regarding dependency resolution and node issuance.
-
Home
-
Community
-
Chakra Schema Release Notes
-
Getting Started
-
Chakra Framework Explanation
- [Overview] Chakra Framework Components
- [TraceLinker] Merging Host and Device Execution Traces
- [Converter] Representing Nodes in Chakra Execution Traces
- [Converter] Converting Chakra Traces to Protobuf Format
- [ETFeeder] Feeding Chakra Traces to Simulators
- [JSONNode] Representing Chakra Traces in JSON
-
Downstream Tools & Applications
-
Resources
- Publications
- Videos
- Google Drive
- FAQ
- Design Documents
-
Contributing