Dvc: repro: downstream: reproducing in wrong order

Created on 7 Apr 2020  路  3Comments  路  Source: iterative/dvc

DVC version : 0.92.0 (PyPI) + MacOS

It seems dvc repro --downstream (could also be the -f option) sometimes executes DAGs in the wrong order.

Steps to reproduction:

dvc run -o 1 -o 2 -f step1.dvc 'touch 1 | touch 2'
dvc run -d 1 -o 3 -f step2.dvc 'touch 3'
dvc run -d 3 -d 2 -o 4 -f step3.dvc 'touch 4'
dvc repro --downstream -f step1.dvc

Last bit does :

Running command:                                                        
    touch 1 | touch 2

Running command:
    touch 4

Running command:
    touch 3

Even though the DAG looks like this :

             +-----------+        
             | step1.dvc |        
             +-----------+        
            ***          ***      
           *                *     
         **                  ***  
+-----------+                   * 
| step2.dvc |                ***  
+-----------+               *     
            ***          ***      
               *        *         
                **    **          
             +-----------+        
             | step3.dvc |        
             +-----------+   

In this case step2 (touch 3) should be executed before step3 (touch 4)

bug p1-important

All 3 comments

Can be reproduced with

def test_repro_downstream(dvc):

    assert (
        main(
            [
                "run",
                "-o",
                "A",
                "-o",
                "B",
                "-f",
                "step1.dvc",
                "echo 'A'>A; echo 'B'>B",
            ]
        )
        == 0
    )
    assert (
        main(["run", "-d", "A", "-o", "C", "-f", "step2.dvc", "echo 'C'>C"])
        == 0
    )
    assert (
        main(
            [
                "run",
                "-d",
                "C",
                "-d",
                "B",
                "-o",
                "D",
                "-f",
                "step3.dvc",
                "echo 'D'>D",
            ]
        )
        == 0
    )
    evaluation = dvc.reproduce("step1.dvc", downstream=True, force=True)
    assert len(evaluation) == 3
    assert evaluation[0].relpath == "step1.dvc"
    assert evaluation[1].relpath == "step2.dvc"
    assert evaluation[2].relpath == "step3.dvc"

Looks like the issue is that for --downstream, we are reversing the DAG, and then traversing the reversed graph w/DFS pre-ordered search. In the example case, using pre-ordered search provides no guarantee that step3 is only visited after step2.

networkx dfs_preorder_nodes() returns them in some arbitrary order, that is probably just dependent on default python set behavior - in the example test case, if I change the name of the final stage to 3.dvc, the test actually passes in OSX python 3.7.

I think what we should be doing is traversing the reversed graph w/reverse post-ordered search, to ensure that dependencies are run in the correct order.

Also reproducible using our existing repro --downstream test (https://github.com/iterative/dvc/blob/fefbcc0b4ccd5a93ab96665c714a93b9fbdd1fa0/tests/func/test_repro.py#L1584)

For the graph

    #       E
    #      / \
    #     D   F
    #    / \   \
    #   B   C   G
    #    \ /
    #     A

downstream A is run as [A, B, D, E, C] even though C should be run before D

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ynop picture ynop  路  41Comments

drorata picture drorata  路  46Comments

luchoPipe87 picture luchoPipe87  路  69Comments

JoeyCarson picture JoeyCarson  路  53Comments

ChrisHowlin picture ChrisHowlin  路  35Comments