Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d269b40
compiler build
wmdi Oct 16, 2023
f46fd11
Merge branch 'test-substitution' into test-compiler
wmdi Oct 18, 2023
af67e9e
Merge branch 'test-substitution' into test-compiler
wmdi Nov 8, 2023
c015efb
unity dp works
wmdi Nov 15, 2023
6211b84
format
wmdi Nov 15, 2023
d9f1302
Merge remote-tracking branch 'upstream/repo-refactor' into test-compiler
wmdi Jan 24, 2024
fb58a99
fmt
wmdi Jan 24, 2024
02937e1
fix
wmdi Jan 24, 2024
6402ed0
add substitutions, compiler, and their unit tests to CI
wmdi Jan 25, 2024
0c45f61
disable runtime unit test
wmdi Jan 25, 2024
95fa427
minor fix
wmdi Feb 15, 2024
1f7e2b6
(not compilable) visitable issue for OptimalCostState
wmdi Feb 18, 2024
a9a6402
fix machine mapping hash & refactor dp algorithm
wmdi Feb 27, 2024
d8bbcb8
minor fix
wmdi Feb 27, 2024
09d3152
fix variant issue
wmdi Feb 28, 2024
a150d3a
fmt
wmdi Feb 28, 2024
2eb3fdf
fix
wmdi Mar 11, 2024
7598a92
fmt
wmdi Mar 11, 2024
05c8336
fix
wmdi Mar 14, 2024
71aeddb
Merge remote-tracking branch 'upstream/repo-refactor' into test-compiler
wmdi Mar 14, 2024
9345400
add more unit tests
wmdi Mar 18, 2024
c0015df
fmt
wmdi Mar 18, 2024
6d28697
Merge remote-tracking branch 'origin/repo-refactor' into compiler
lockshaw Mar 22, 2024
102f5fb
Fix post-merge
lockshaw Mar 22, 2024
d6e10bb
Add shell hook for sapling development
lockshaw Mar 23, 2024
95fb4cc
changed from nullopt to std::nullopt
Mar 23, 2024
c091479
fix cast issue
wmdi Mar 23, 2024
57bd35f
Merge branch 'test-compiler' of github.com:wmdi/FlexFlow into test-co…
wmdi Mar 23, 2024
54c604a
Fix spdlog cmake issue
lockshaw Mar 24, 2024
a09e528
Merge remote-tracking branch 'refs/remotes/wmdi/test-compiler' into c…
lockshaw Mar 24, 2024
8b914cf
Re-remove submodules
lockshaw Mar 24, 2024
189f323
minor fix & fmt
wmdi Mar 24, 2024
d2eb505
upd tests name to match ci
wmdi Mar 24, 2024
371324a
Add TEST_SUITE declaration to make tests findable by ctest
lockshaw Mar 26, 2024
da74817
Remove unnecessary nix files, add utils test to ci
lockshaw Mar 26, 2024
0db60db
Fix utils tests name, format
lockshaw Mar 26, 2024
6e520bb
Merge pull request #1229 from wmdi/test-compiler
wmdi Mar 26, 2024
dac253d
Documentation for graph library
Apr 15, 2024
7a1213b
Minor changes
Apr 15, 2024
fcf2d02
Updated diagram generator script for graph docs
Apr 19, 2024
be171cd
Added svg files for graph documentation
Apr 19, 2024
3644854
Docs changes
Apr 19, 2024
45eeb90
README change
Apr 19, 2024
27d9ad6
Updated README
Apr 19, 2024
5a96eae
Updated Docs
Apr 20, 2024
fe51ade
saving
Apr 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@
devShells = rec {
ci = mkShell {
shellHook = ''
<<<<<<< HEAD
export PATH="$HOME/ff/.scripts/:$HOME/ff/.modules/proj/bin/:$PATH"
=======
export PATH="$HOME/ff/.scripts/:$PATH"
>>>>>>> 8e0625fe72b731e199c3a6b9bec7c31464c0e637
'';

CMAKE_FLAGS = lib.strings.concatStringsSep " " [
Expand All @@ -71,7 +75,10 @@
"-DFF_USE_EXTERNAL_SPDLOG=ON"
"-DFF_USE_EXTERNAL_DOCTEST=ON"
"-DFF_USE_EXTERNAL_RAPIDCHECK=ON"
<<<<<<< HEAD
=======
"-DFF_USE_EXTERNAL_EXPECTED=ON"
>>>>>>> 8e0625fe72b731e199c3a6b9bec7c31464c0e637
"-DFF_USE_EXTERNAL_RANGEV3=ON"
"-DFF_USE_EXTERNAL_BOOST_PREPROCESSOR=ON"
"-DFF_USE_EXTERNAL_TYPE_INDEX=ON"
Expand All @@ -95,7 +102,10 @@
cudaPackages.nccl
cudaPackages.libcublas
cudaPackages.cuda_cudart
<<<<<<< HEAD
=======
tl-expected
>>>>>>> 8e0625fe72b731e199c3a6b9bec7c31464c0e637
])
(with self.packages.${system}; [
legion
Expand Down
64 changes: 60 additions & 4 deletions lib/utils/include/utils/graph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

FlexFlow's graph library very intentionally attempts to balance performance and ease of use.
The graph library aims to have a very simple external interface that is highly decoupled from the underlying representations, so performance and internal implementations can be tuned and modified over time without breaking the code that uses the library.
Because FlexFlow's graphs are not on the scale of machine memory or not so large that single traversals takes nontrivial time, the graph library intentially avoids performance opportunites that would expose many of these performance aspects to user code.
Of course, there are also some optimizations that simply have not been done due to time constraints: for example, algorithms currently are able to be specialized for the underlyign representation being used, but this could be added without modifying the user-side interface.
Because FlexFlow's graphs are not on the scale of machine memory or not so large that single traversals takes nontrivial time, the graph library intentionally avoids performance opportunities that would expose many of these performance aspects to user code.
Of course, there are also some optimizations that simply have not been done due to time constraints: for example, algorithms currently are able to be specialized for the underlying representation being used, but this could be added without modifying the user-side interface.

## Usage

Expand All @@ -17,7 +17,7 @@ At their core, they are as follows:

- `UndirectedGraph`: at most one edge allowed between every pair of nodes, edges are undirected
- `DirectedGraph`: at most one edge allowed between every ordered pair of nodes, edges are directed (i.e., have a source node and a destination node)
- `MultiDiGraph`: arbitrary numbers of edges allowed between every pair of nodes, but each must have not only source/destination nodes but also _source/destination` indices_, which serve to disambiguate different edges between the same nodes. There can exist at most one edge for every ordered tuple of source node, destination node, source index, and destination index.
- `MultiDiGraph`: arbitrary numbers of edges allowed between every pair of nodes, but each must have not only source/destination nodes but also _source/destination indices_, which serve to disambiguate different edges between the same nodes. There can exist at most one edge for every ordered tuple of source node, destination node, source index, and destination index.

Examples of the different graph variants are shown below.

Expand Down Expand Up @@ -149,6 +149,7 @@ To add an edge between two nodes `Node n1` and `Node n2` to an `UndirectedGraph
In `UndirectedGraph` the order of the arguments of `add_edge` doesn't matter as edges are undirected, but the order does matter for `DiGraph` and `MultiDiGraph`.
`MultiDiGraph::add_edge` takes in two additional arguments of type `NodePort`, specifying the source and destination indices.
Similar to `Node`s, `NodePort`s can be generated via `g.add_node_port()`.
`NodePort:` an opaque object used within `MultiDiGraph` to disambiguate between multiple edges. `MultiDiGraph` will be able to distinguish between 2 edges that share the same source and destination as long as at at least one `NodePort` differs. Within the context of a PCG, `NodePorts` must be thought of as the various inputs and outputs of a single node.

The last paragraph covered the base API used to write to graphs, but we also want to be able to read from graphs.
Reading from graphs is implemented with the `query_nodes` and `query_edges` methods, which can be thought of as executing a database query over the nodes and edges of the target graph, respectively (where queries are restricted to an incredibly simple set of operations).
Expand Down Expand Up @@ -179,6 +180,16 @@ Generally users will use underlying representations provided by the graph librar
[^1]: At some point we will likely add actual runtime checks on this, but for now we rely on the user not to mess up. Currently the implementation will keep going silently until the incorrectness grows so large that something breaks/crashes.
[^2]: See <https://en.wikipedia.org/wiki/Type_conversion> if you're not familiar with the term _type coercion_

### Open, Upward, Downward

`Open` is to be intended similarly to the topological sense: that is, a graph that contains some edges where one of the 2 nodes is not present in the graph itself.
We can further specify the "openeness" of a **directed** graph by specifying whether they are `UpwardOpen` (so some of the incoming edges are open) or `DownwardOpen` (so some of the outgoing edges are open).

![Open graphs inheritance diagram](docs/open.svg)

Arrows with pointed tips indicate inheritance, while arrows with square tips indicate that the pointing class has a 'cow_ptr' of the type of the pointed class. (for more info on `cow_ptr`, see below).


### Labelled Graphs

As nice as all of the above is, graphs without labels are mostly useless--in practice, nodes and edges represent some other system and the properties of that system (or at least a way to map the result of graph algorithms back to the underlying system) are necessary.
Expand All @@ -191,6 +202,51 @@ As such, the labelled graph types provide the typical `at` method (as on `std::u

[^3]: `operator[]` currently is not present because all nodes must have labels and we don't require label types to be default constructible, though some simple template programming could probably add `operator[]` support in the cases where the label types _are_ default constructible.

![Labelled Graphs Inheritance Diagram](docs/labelled.svg)



## Internals

TODO @lockshaw
Most of the major graph classes in the library come in sets of 4. For a given class `GlassName` we have:
1. `ClassName`
2. `ClassNameView`
3. `IClassName`
4. `IClassNameView`

General rules which apply to most classes:
- `ClassName` (virtually) inherits from `ClassNameView`. Similarly, `IClassName` (virtually) inherits from `IClassNameView`.
- `ClassName` has, as a member variable, a `cow_ptr` of type `IClassName`. Same holds for `ClassNameView`.
Thus, the bulk of the inheritance that actually extends functionality is present among `IClassNameView` classes.


### cow_ptr and Interfaces

The reason for the existence of the `View` variants has been explained in previous sections.
The existence of the `I(nterface)` variants stems from C++'s approach to modeling polymorphism.

C++ polymorphism is achieved through the use of [virtual functions](https://www.learncpp.com/cpp-tutorial/virtual-functions/).
To create objects with polymorphic behaviour, we use the following syntax:
`BaseClass* obj = new DerivedClass(); //or alternatives such as std::shared_ptr<BaseClass> obj = std::make_shared<DerivedClass>();`
Any call to `obj`'s member functions are resolved at runtime (dynamic binding), with C++ calling the most derived implementation of the function.

While this pattern works nicely, the way instantiation is done leaves the burden of memory management on the user.
To address this, graph classes store a cow_ptr as a member variable, which point to instances of type equal to their corresponding interface class.

All member functions present in `ClassName` and `ClassNameView` delegate their calls to their corresponding interface classes (which implement the actual logic), meaning that these classes essentially act as wrappers to their interface counterparts.

To create graphs within the library, we thus use the following syntax:
`BaseGraph obj = BaseGraph::create<DerivedGraph>();`

Resulting in an object that, while of type `BaseGraph`, can access at runtime the member functions defined in `DerivedGraph`


### Virtual Inheritance (Possibly superflous)
Due to the complexity of the graph library, diamond-style inheritance patterns emerge.
In the case of a diamond inheritance pattern C++ will instantiate multiple copies of the base class whenever we instantiate a derived class.
To address this issue, we employ [Virtual Inheritance](https://en.wikipedia.org/wiki/Virtual_inheritance), which removes the ambiguity associated with the multiple copies.
Furthermore, the use of virtual functions allows for runtime polymorphism, allowing for a single function defined on some superclass to also work correctly on it's subclasses.

### strong_typedef
`Node` inherits from `strong_typedef`: this is in order to ensure that distinct types that alias the same type are still considered distinct (and thus using one in place of the other will result in a compiler error).
For more info, see https://www.foonathan.net/2016/10/strong-typedefs/.
Loading