Redo dask.order.order. Fix #5584. Use structural info, not key names#5646
Redo dask.order.order. Fix #5584. Use structural info, not key names#5646jcrist merged 15 commits intodask:masterfrom
dask.order.order. Fix #5584. Use structural info, not key names#5646Conversation
…names. This is a substantial rewrite of `dask.order.order`, but the goals remain the same and many previous lessons were taken into consideration. The new version relies less on the key name by using more metrics and using a different strategy for walking up and down the DAG. Performance appears to be about the same (sometimes a litle faster, sometimes a little slower, and never a lot slower). I still need to wrap up some cosmetics (doc strings, code comments, etc). @TomAugspurger also suggested I add some benchmarks to dask-benchmarks.
|
Thanks @eriknw . When you get back from the holidays, I would be curious about the following:
The ordering code is fairly core to Dask's functioning today, so changes here should be scrutinized. It would be good if someone else close to this code (@jcrist @jrbourbeau ?) could review as well. |
|
Certainly. I expect this to be thoroughly scrutinized and will provide much more supporting material.
Here's a simple example from the tests where the old def test_avoid_broker_nodes(abcde):
r"""
b0 b1 b2
| \ /
a0 a1
a0 should be run before a1
"""
a, b, c, d, e = abcde
....
# Switch name of 0, 1 for "b"s too
dsk = {
(a, 0): (f,),
(a, 1): (f,),
(b, 1): (f, (a, 0)),
(b, 0): (f, (a, 1)),
(b, 2): (f, (a, 1)),
}
o = order(dsk)
assert o[(a, 0)] < o[(a, 1)]I found the old approach--although clever and short--to be irredeemable when trying to address these. I don't mean to sound too critical (the previous way and all the discussions around it were incredibly helpful), so not improving the old way is probably a lack of imagination on my part along with my preference for trying something new. |
| o = order(dsk) | ||
| expected = {"y": 0} | ||
| expected.update({k: i + 1 for i, k in enumerate(x_keys)}) | ||
| expected = {"y": 10} |
There was a problem hiding this comment.
Can you share why this changed?
There was a problem hiding this comment.
It looked to me that the old code here was wrong. "y" cannot be 0. It has 10 dependencies.
|
Here is a notebook showing a few examples: https://gist.github.com/eriknw/0ab7cf29a4f4f6037a22ede14b7f58b8 |
|
This is awaiting further review and scrutiny. As it turns out, I don't think this PR is all that different in spirit and practice than the original. This makes a few changes how we traverse the graph:
This PR adds a lot more structure. Although more complicated, I think this is also more maintainable and modifiable, and I expect to be around a while to address issues that may arise. In my benchmarks on my machine, this PR is about the same speed or a little faster than the original. About two thirds of the time is spent in |
|
Here is the notebook above run using master. There is at least one serious regression! https://gist.github.com/eriknw/b8478260d6c883cc3c80a1816a993442 Here's the serious regression: We should not be calculation all the dependents on the top at the beginning. I'd like to add this as a test. |
Avoid sorting or taking the min when there are many, many edges. This respects the use case here: dask#3298 Minor performance improvements.
|
I think the people able to review this are pretty busy this week, so here are relevant previous issues and PRs: Also, here are some benchmarks. https://gist.github.com/eriknw/82c204b7923f079e267ab245f7228f0a For these on my machine, the current PR is always faster than master, and sometimes significantly (x3-x10) faster (perhaps when there are many more edges than nodes?). To be fair, some of the performance improvements of this PR could also be applied to master. To reiterate, master has had regressions based on previously established and expected behavior. I believe this PR fixes these. Okay, I'll try to not revisit this issue until it's been reviewed! |
|
Are you able to reproduce the failing test locally? I don't really see how it would be related. Also, if you're able to, adding benchmarks to https://github.com/dask/dask-benchmarks/ can be done before this is merged. Those should be relatively easy to review. |
Re-add `total_dependencies` in `dependencies_key`.
|
Okay, so I just tried (and decided against) two things that are in master that aren't part of this PR:
I just added a new behavior to this PR. When we encounter a node that has dangling dependents--that is, nodes that are able to be computed and have no dependents--we always compute all of these nodes. We may then proceed to a different dependent. This appears to improve the ordering of graphs I've been looking at, and it seems to largely overcome the lack of having the above two behaviors. I don't think FIFO instead of LIFO behavior will be a significant shortcoming in practice. In fact, I think FIFO is useful given the lack of (1) above--FIFO gives us a chance to go back and visit branches that we maybe should have gone down instead. I also think FIFO will work well with the distributed and multithreaded scheduler. @jcrist I know this is a lot to digest. Let me know if you want to meet to go over this (and no rush). |
jcrist
left a comment
There was a problem hiding this comment.
Erik and I talked this through IRL, and I'm quite happy with these changes. The new ordering is both better for these example problems, and faster in most cases (sometimes significantly). I have one comment on clarifying a docstring, but otherwise this LGTM.
| 3. The maximum value of the maximum number of dependencies of | ||
| all final dependencies (see module-level comment for more) | ||
| 4. The minimum height from a root node | ||
| 5. The maximum height from a root node |
There was a problem hiding this comment.
I find the description of 2 and 3 difficult to understand, perhaps an ascii diagram here would be useful to clarify these metrics?
There was a problem hiding this comment.
docstring updated. Hopefully better.
|
Thanks @eriknw, this looks good to me. Merging! |



Closes #5584
This is a rewrite of
dask.order.order, but the goals remain the same and many previous lessons were taken into consideration. The new version relies less on the key name by using more metrics and using a different strategy for walking up and down the DAG.Performance appears to be about the same (often a little faster).
@TomAugspurger also suggested I add some benchmarks to
dask-benchmarks.black dask/flake8 dask