An HPVM program is a combination of host code plus a set of one or more distinct dataflow graphs. Each dataflow graph (DFG) is a hierarchical graph with side effects. Nodes represent units of execution, and edges between nodes describe the explicit data transfer requirements. A node can begin execution once a data item becomes available on every one of its input edges. Repeated transfer of data items between nodes (if more inputs are provided) yields a pipelined execution of different nodes in the graph. The execution of a DFG is initiated and terminated by host code that launches the graph. Nodes may access globally shared memory through load and store instructions (side-effects).
An HPVM program is a combination of host code plus a set of one or more distinct dataflow graphs. Each dataflow graph (DFG) is a hierarchical graph with side effects. The DFG must be acyclic. Nodes represent units of execution, and edges between nodes describe the explicit data transfer requirements. A node can begin execution once a data item becomes available on every one of its input edges. Repeated transfer of data items between nodes (if more inputs are provided) yields a pipelined execution of different nodes in the graph. The execution of a DFG is initiated and terminated by host code that launches the graph. Nodes may access globally shared memory through load and store instructions (side-effects).
## Dataflow Node
## Dataflow Node
A *dataflow node* represents unit of computation in the DFG. A node can begin execution once a data item becomes available on every one of its input edges.
A *dataflow node* represents unit of computation in the DFG. A node can begin execution once a data item becomes available on every one of its input edges.
...
@@ -90,13 +90,13 @@ Create a static dataflow node replicated in two dimensions, namely ```x``` and `
...
@@ -90,13 +90,13 @@ Create a static dataflow node replicated in two dimensions, namely ```x``` and `
Create a static dataflow node replicated in three dimensions, namely ```x```, ```y``` and ```z```, with ```n1```, ```n2``` and ```n3``` dynamic instances in each dimension respectively, executing node function ```F```. Return a handle to the created node.
Create a static dataflow node replicated in three dimensions, namely ```x```, ```y``` and ```z```, with ```n1```, ```n2``` and ```n3``` dynamic instances in each dimension respectively, executing node function ```F```. Return a handle to the created node.
Create edge from output ```sp``` of node ```Src``` to input ```dp``` of node ```Dst```. ```ReplType``` chooses between a one-to-one (0) or all-to-all (1) edge. ```isStream``` chooses a streaming (1) or non streaming (0) edge. Return a handle to the created edge.
Create edge from output ```sp``` of node ```Src``` to input ```dp``` of node ```Dst```. Argument ```dp``` of ```Dst```'s node function and field ```sp``` of the return struct in ```Src```'s node function must have matching types. ```ReplType``` chooses between a one-to-one (0) or all-to-all (1) edge. ```isStream``` chooses a streaming (1) or non streaming (0) edge. Return a handle to the created edge.
```void llvm.hpvm.bind.input(i8* N, i32 ip, i32 ic, i1 isStream)```
```void llvm.hpvm.bind.input(i8* N, i32 ip, i32 ic, i1 isStream)```
Bind input ```ip``` of current node to input ```ic``` of child node ```N```. ```isStream``` chooses a streaming (1) or non streaming (0) bind.
Bind input ```ip``` of current node to input ```ic``` of child node ```N```. Argument ```ic``` of ```N```'s node function and argument ```ip``` of the current node function must have matching types. ```isStream``` chooses a streaming (1) or non streaming (0) bind.
```void llvm.hpvm.bind.output(i8* N, i32 oc, i32 op, i1 isStream)```
```void llvm.hpvm.bind.output(i8* N, i32 oc, i32 op, i1 isStream)```
Bind output ```oc``` of child node ```N``` to output ```op``` of current node. ```isStream``` chooses a streaming (1) or non streaming (0) bind.
Bind output ```oc``` of child node ```N``` to output ```op``` of current node. Field ```oc``` of the return struct in ```N```'s node function and field ```op``` of the return struct in the current node function must have matching types. ```isStream``` chooses a streaming (1) or non streaming (0) bind.
## Intrinsics for Querying Graphs
## Intrinsics for Querying Graphs
...
@@ -172,7 +172,7 @@ Stop tracking memory object with key ```ptr```, and remove it from memory tracke
...
@@ -172,7 +172,7 @@ Stop tracking memory object with key ```ptr```, and remove it from memory tracke
If memory object with key ```ptr``` is not located in host memory, copy it to host memory.
If memory object with key ```ptr``` is not located in host memory, copy it to host memory.
Launch the execution of DFG with node function ```RootGraph```. ```Args``` is a pointer to packed struct, containing one field per argument of the ```RootGraph``` function, consecutively. For non-streaming DFGs with a non empty result type, ```Args``` must contain an additional field of the type ```RootGraph.returnTy```, where the result of the graph will be returned. ```isStream``` chooses between a non streaming (0) or streaming (1) graph execution. Return a handle to the invoked DFG.
Launch the execution of a top-level DFG with root node function ```RootGraph```. ```Args``` is a pointer to a packed struct, containing one field per argument of the ```RootGraph``` function, consecutively. For non-streaming DFGs with a non empty result type, ```Args``` must contain an additional field of the type ```RootGraph.returnTy```, where the result of the graph will be returned. ```isStream``` chooses between a non streaming (0) or streaming (1) graph execution. Return a handle to the invoked DFG.
```void llvm.hpvm.wait(i8* GraphID)```
```void llvm.hpvm.wait(i8* GraphID)```
Wait for completion of execution of DFG with handle ```GraphID```.
Wait for completion of execution of DFG with handle ```GraphID```.
...
@@ -181,9 +181,10 @@ Wait for completion of execution of DFG with handle ```GraphID```.
...
@@ -181,9 +181,10 @@ Wait for completion of execution of DFG with handle ```GraphID```.
Push set of input data ```args``` (same as type included in launch) to streaming DFG with handle ```GraphID```.
Push set of input data ```args``` (same as type included in launch) to streaming DFG with handle ```GraphID```.
```i8* llvm.hpvm.pop(i8* GraphID)```
```i8* llvm.hpvm.pop(i8* GraphID)```
Pop and return data from streaming DFG with handle ```GraphID```.
Pop and return data from streaming DFG with handle ```GraphID```. The return type is a struct containing a field for every output of DFG.
## Implementation Limitations
## Implementation Limitations
Due to limitations of our current prototype implementation, the following restrictions are imposed:
Due to limitations of our current prototype implementation, the following restrictions are imposed:
- In HPVM, a memory object is represented as a (pointer, size) pair that includes the address of memory object, and the size (in bytes) of the pointed-to object. Therefore, when an edge/bind carries a pointer, it must be followed by an i64 size value.
- In HPVM, a memory object is represented as a (pointer, size) pair that includes the address of memory object, and the size (in bytes) of the pointed-to object. Therefore, when an edge/bind carries a pointer, it must be followed by an i64 size value.
- Pointers cannot be transferred between nodes using dataflow edges. Instead, they should be passed using the bind operation from the (common) parent of the source and sink nodes.
- Pointers cannot be transferred between nodes using dataflow edges. Instead, they should be passed using the bind operation from the (common) parent of the source and sink nodes.
- Instantiation of dataflow nodes is supported in up to three dimensions.