Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Added region aware testing #50

Merged
merged 18 commits into from
Jul 31, 2023
Merged

[WIP] Added region aware testing #50

merged 18 commits into from
Jul 31, 2023

Conversation

kc611
Copy link
Contributor

@kc611 kc611 commented Apr 24, 2023

As titled, this PR adds region-aware testing by modifying the from_yaml and to_yaml methods of SCFG.

Following is the task list for this PR:

  • Refactor from_yaml and to_yaml to new format.
  • Make the methods block-type aware
  • Make the methods region aware
  • Adapt the test suite to the new methods
  • Add the capability to build graphs using the YAML format
  • Add a comparator for testing the graph accurately.
  • Test the logic by adding automated tests for fig3 and fig4

@kc611 kc611 marked this pull request as ready for review April 25, 2023 09:04
@esc
Copy link
Member

esc commented Jun 30, 2023

  • Add capability to build graphs using the YAML format

@kc611 I see there is code to go from YAML to SCFG -- is this what this bullet refers to?

Copy link
Member

@esc esc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks mostly fine. I left some comments about code that needs to be cleaned up.

numba_rvsdg/tests/test_fig3.py Outdated Show resolved Hide resolved
numba_rvsdg/core/datastructures/scfg.py Outdated Show resolved Hide resolved
@esc
Copy link
Member

esc commented Jun 30, 2023

@kc611 also, The synthetic assignments need to save, which variable is being assigned. Also the synthetic branches and such need to store their table of variable -> destination. This is part of the graph and semantics so needs to be stores inside the YAML.

@kc611
Copy link
Contributor Author

kc611 commented Jun 30, 2023

  • Add capability to build graphs using the YAML format

@kc611 I see there is code to go from YAML to SCFG -- is this what this bullet refers to?

Yes, it refers to updating the from_yaml and from_dict methods for constructing SCFGs using a given YAML.

@esc
Copy link
Member

esc commented Jun 30, 2023

  • Add capability to build graphs using the YAML format

@kc611 I see there is code to go from YAML to SCFG -- is this what this bullet refers to?

Yes, it refers to updating the from_yaml and from_dict methods for constructing SCFGs using a given YAML.

OK, can you tick that checkbox, or is there still stuff missing?

@kc611
Copy link
Contributor Author

kc611 commented Jun 30, 2023

It is still missing support for building region blocks.

I have updated the description to include the final goal of this PR i.e. to get an automated test for transformed SCFGs which in our case is fig3 and fig4.

@esc
Copy link
Member

esc commented Jun 30, 2023

It is still missing support for building region blocks.

Ah, so you can't get a graph back from YAML that contains region blocks?

I have updated the description to include the final goal of this PR i.e. to get an automated test for transformed SCFGs which in our case is fig3 and fig4.

Yes, and test_scc.py too.

@esc esc added this to the 0.0.3 milestone Jun 30, 2023
Copy link
Member

@esc esc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One additional question, is the backedges is empty anyway, can we add code to omit that in input YAML?

edges = {}
backedges = {}

def reverse_lookup(value):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs a type signature

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values are class constructors, not sure what type that is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the correct signature for this would be type[BasicBlock]

numba_rvsdg/core/datastructures/scfg.py Outdated Show resolved Hide resolved
numba_rvsdg/core/datastructures/scfg.py Outdated Show resolved Hide resolved
numba_rvsdg/tests/test_figures.py Show resolved Hide resolved
"0": ["1", "2"],
"1": ["5"],
"2": ["1", "5"],
"3": ["1"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this case, it goes from 0 to 1 in the diff?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as #50 (comment) except in this case since graphs are random it doesn't matter where they point.

'2': ['1', '4']
'3': ['0']
'4': []
backedges:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is wrong. The original should never have any backedges. They are just edges to begin with. Part of the SCFG loop restructure is to go through and make the distinction between edges and backedges.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is, if there's an edge (that is not a back edge) pointing towards the head of the graph, then we have no way of automatically detecting which node is the head of the graph from YAML.

Since our code logic behaves as follows:
The head of the graph is the node towards which no edge is pointing towards.

To resolve this issue for this example we can simply have a placeholder head with no edges pointing towards it that in turn points towards the actual graph we need, that'll remove the need for back edges.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also an offshoot variant of the issue faced by @sklam downstream in Numba, wherein he circumvented it by having a separate placeholder head and tail for every RegionBlock. Seems like that could be upstreamed here to fix it in the long run.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not convinced that this is a good implementation. I think it should be possible to specify a cyclic graph in YAML and read it in. I think I can see a way to eliminate the need to detect a head. In general, I think cyclic, but reducible graphs should be supported.

Copy link
Member

@esc esc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two mores suggestions.

numba_rvsdg/tests/test_utils.py Outdated Show resolved Hide resolved
numba_rvsdg/tests/test_utils.py Outdated Show resolved Hide resolved
@esc
Copy link
Member

esc commented Jul 5, 2023

@kc611 thank you for submitting this. I made two reviews with some sugggestions. Also, please don't forget #50 (comment)

@esc
Copy link
Member

esc commented Jul 5, 2023

Also, I am not sure that the values of the control variables are being tested. Using the following diff, I was expecting the tests to fail:

diff --git i/numba_rvsdg/tests/test_figures.py w/numba_rvsdg/tests/test_figures.py
index 82419f1d69..4e86d088d8 100644
--- i/numba_rvsdg/tests/test_figures.py
+++ w/numba_rvsdg/tests/test_figures.py
@@ -144,7 +144,7 @@ blocks:
         end: 22
     synth_asign_block_0:
         type: synth_asign
-        variable_assignment: {'control_var_0': 0}
+        variable_assignment: {'control_var_0': 1}
     synth_asign_block_1:
         type: synth_asign
         variable_assignment: {'control_var_0': 1}

But they do seem to pass?

@kc611
Copy link
Contributor Author

kc611 commented Jul 6, 2023

Seems like testing for equality assertions for synthetic assignments and synthetic branches has exposed a flaky failure in SCFG loop restructuring. (This can be tested by running the figure 3 test multiple times until you get a failure.)

@esc
Copy link
Member

esc commented Jul 11, 2023

Seems like testing for equality assertions for synthetic assignments and synthetic branches has exposed a flaky failure in SCFG loop restructuring. (This can be tested by running the figure 3 test multiple times until you get a failure.)

I think there are some fixes for this exact issue in: #57 -- I will investigate porting those fixes to this PR.

@esc
Copy link
Member

esc commented Jul 12, 2023

Seems like testing for equality assertions for synthetic assignments and synthetic branches has exposed a flaky failure in SCFG loop restructuring. (This can be tested by running the figure 3 test multiple times until you get a failure.)

I think there are some fixes for this exact issue in: #57 -- I will investigate porting those fixes to this PR.

This patch "seems" to fix things. I've run it several times now and I was unable to reproduce the error:

diff --git i/numba_rvsdg/core/datastructures/scfg.py w/numba_rvsdg/core/datastructures/scfg.py
index 2d29025b45..d80b99ae07 100644
--- i/numba_rvsdg/core/datastructures/scfg.py
+++ w/numba_rvsdg/core/datastructures/scfg.py
@@ -617,7 +617,7 @@ class SCFG:
             # Need to create synthetic assignments for each arc from a
             # predecessors to a successor and insert it between the predecessor
             # and the newly created block
-            for s in set(jt).intersection(successors):
+            for s in sorted(set(jt).intersection(successors)):
                 synth_assign = self.name_gen.new_block_name(SYNTH_ASSIGN)
                 variable_assignment = {}
                 variable_assignment[branch_variable] = branch_variable_value

Looking again at the patch in #57 -- there are only three changes that are not related to rendering. The above is one of them. Perhaps this is sufficient to fix the instability of the current loop restructure implementation.

This removes non-determinism from the insertion order of the
SYNTH_ASSIGN blocks such that the resulting SCFG output is stable and
can be tested appropriately.
@esc
Copy link
Member

esc commented Jul 13, 2023

Seems like testing for equality assertions for synthetic assignments and synthetic branches has exposed a flaky failure in SCFG loop restructuring. (This can be tested by running the figure 3 test multiple times until you get a failure.)

I think there are some fixes for this exact issue in: #57 -- I will investigate porting those fixes to this PR.

This patch "seems" to fix things. I've run it several times now and I was unable to reproduce the error:

diff --git i/numba_rvsdg/core/datastructures/scfg.py w/numba_rvsdg/core/datastructures/scfg.py
index 2d29025b45..d80b99ae07 100644
--- i/numba_rvsdg/core/datastructures/scfg.py
+++ w/numba_rvsdg/core/datastructures/scfg.py
@@ -617,7 +617,7 @@ class SCFG:
             # Need to create synthetic assignments for each arc from a
             # predecessors to a successor and insert it between the predecessor
             # and the newly created block
-            for s in set(jt).intersection(successors):
+            for s in sorted(set(jt).intersection(successors)):
                 synth_assign = self.name_gen.new_block_name(SYNTH_ASSIGN)
                 variable_assignment = {}
                 variable_assignment[branch_variable] = branch_variable_value

Looking again at the patch in #57 -- there are only three changes that are not related to rendering. The above is one of them. Perhaps this is sufficient to fix the instability of the current loop restructure implementation.

I pushed this change with 42434fd


seen = set()

def make_scfg(curr_heads: set, exiting: str = None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should not be a closure, unless it really needs to be.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I managed to write this such that it isn't a closure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I investigated this a bit more and I think this function will need some significant changes so as to make it more readable and that it becomes clearer what goes on. I think the make_scfg shouldn't be a closure and I also think that some stuff can be decomposed into smaller functions too.

Copy link
Member

@esc esc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a few comments, but I think there is some more work to do on this:

  • Refactor make_scfg so that it complies more closely with general software engineering best practices (low-coupling, high cohesion)
  • Refactor the need for having a graph with a pre-determined "head-node" to support cyclic graphs as YAML input.

Copy link
Member

@esc esc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to add some docstrings to the auxilliary methods and also place those into a class SCFGIO alongside make_scfg. Then, forward the methods from_yaml/to_yaml and from_dict/to_dictto the static methods of SCFGIO class. Make sure you also update the documentation to reflect this. The methods remaining in the original SCFG class can simply have a see also: in the NumPy style.

@@ -872,6 +966,33 @@ def view(self, name: str = None):
SCFGRenderer(self).view(name)


def find_outer_graph(graph_dict: dict):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring please.

return outer_blocks


def extract_block_info(blocks, current_name, block_ref_dict, edges, backedges):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstring too please.

@esc
Copy link
Member

esc commented Jul 31, 2023

@kc611 looks good, thank you, I fixed two minor typos in cadd031 and it's now ready to merge.

@esc esc merged commit b10fb94 into numba:main Jul 31, 2023
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants