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

RFC: support lazy all_to_all connection setups #22814

Merged
merged 1 commit into from
Jul 25, 2017
Merged

Conversation

amitmurthy
Copy link
Contributor

@amitmurthy amitmurthy commented Jul 14, 2017

This PR does the following:

  • adds a lazy=true keyword option to addprocs. Default is true. Addresses part of Setup worker-worker connections lazily Distributed.jl#42 via this new keyword arg.
  • Only applicable to all_to_all connection setups.
  • All workers are still connected to the master. Only worker-worker connections are setup lazily at the time of the first request between 2 workers.
  • The lazy option is valid only for all_to_all topologies. For custom topologies, all connections are setup at the time of addprocs.
  • This more-or-less does away with the need to specify any complex topologies. Connections are setup on demand. For example a stencil operations will only lead to worker-worker connection setups between neighbors.
  • Will reduce startup time on large clusters.
  • Will limit resource usage (number of open fds per process) to the minimum required.

Todo:

  • - Doc update
  • - Tests

@amitmurthy
Copy link
Contributor Author

cc: @andreasnoack, @JeffBezanson

t = @async connect_to_peer(cluster_manager, rpid, wconfig)
push!(wait_tasks, t)
if lazy
# The constructor register the object with a global registery.
Copy link
Contributor

Choose a reason for hiding this comment

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

registers the object with a global registry

i==length(wlist) && continue
@async remotecall_fetch(wl -> asyncmap(q->remotecall_fetch(myid, q), wl),
p, wlist[i+1:end])

Copy link
Contributor

Choose a reason for hiding this comment

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

unnecessary blank line

@ararslan ararslan added the parallelism Parallel or distributed computation label Jul 14, 2017
@@ -317,7 +317,7 @@ function handle_msg(msg::JoinPGRPMsg, header, r_stream, w_stream, version)

let rpid=rpid, wconfig=wconfig
if lazy
# The constructor register the object with a global registery.
# The constructor registers the object with a global registery.
Copy link
Contributor

Choose a reason for hiding this comment

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

registry is still misspelled

test/topology.jl Outdated

# Test for 10 random combinations
wl = workers()
combinations =[]
Copy link
Contributor

Choose a reason for hiding this comment

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

combinations = []

test/topology.jl Outdated
@test num_conns == expected_num_conns
end

# With lazy=false, all connections ought to be setup initially itself
Copy link
Contributor

Choose a reason for hiding this comment

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

what are you referring to by "itself" ?

@amitmurthy amitmurthy changed the title RFC/WIP: support lazy all_to_all connection setups RFC: support lazy all_to_all connection setups Jul 18, 2017
@andreasnoack
Copy link
Member

I can try this out on a cluster later and see try the effect adding 500-1000 workers. API wise, I think it would be better to have orthogonal options. Is it the plan to make lazy applicable to other topologies later? If not, it might be better to have a :lazyalltoall topology instead.

@amitmurthy
Copy link
Contributor Author

Is it the plan to make lazy applicable to other topologies later? If not, it might be better to have a :lazyalltoall topology instead.

I was planning on doing that, but decided against it for now

  1. If one is going through the the trouble to specify a custom topology then we may as well setup connections upfront
  2. Since specifying custom topologies is currently non-trivial, such use cases are quite well served by lazily setting up connections on demand.

Having said that, a separate keyword arg allows us to enable it across all existing and any new topology types in the future if required.

@amitmurthy
Copy link
Contributor Author

Merging this tomorrow if there are no objections.

if isnull(PGRP.lazy) || nprocs() == 1
PGRP.lazy = Nullable{Bool}(params[:lazy])
elseif isclusterlazy() != params[:lazy]
throw(ErrorException(string("Active workers with lazy=", isclusterlazy(),
Copy link
Contributor

Choose a reason for hiding this comment

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

probably better as an ArgumentError if this comes from a bad keyword argument

@amitmurthy amitmurthy merged commit fd951c2 into master Jul 25, 2017
@amitmurthy amitmurthy deleted the amitm/lazy2 branch July 25, 2017 08:28
@amitmurthy
Copy link
Contributor Author

We should backport the lazy connection setup behavior onto 0.6 without introducing the lazy keyword, i.e. connections will always be setup lazily under a all_to_all topology. Will not affect any use code.

Opinions?

@tkelman
Copy link
Contributor

tkelman commented Jul 25, 2017

We don't generally backport behavior changes or new features of this size.

@amitmurthy
Copy link
Contributor Author

The behavior change in this case would be internal. Things would work as before, the only difference being that first time worker-worker requests will include a connection setup time. This is offset by the benefits on larger clusters in terms of initial setup time as well as resource usage if the workload does not require a complete mesh network.

@tkelman
Copy link
Contributor

tkelman commented Jul 25, 2017

Several types are being changed here in ways that would be visible and breaking for any external code that constructs them directly.

@StefanKarpinski
Copy link
Member

Is there a particularly strong case as to why we would need this change on 0.6 other than that it's a better default behavior?

@amitmurthy
Copy link
Contributor Author

The strong case is for larger clusters, say 200 workers and above. This will help in situations where a program run does not require all workers to actually communicate with all other workers, but still requires some inter-worker communications (say between neighbors). Defining a custom topology is not straightforward in the cluster manager and a lazy all_to_all setup does away with the need to do so ahead of time.

However, I also realized that this will break interop between 0.6 and 0.6.x and hence is not the right thing to do.

I can make a patch available if and when folks start asking for this in 0.6. People really needing this behavior will need to use a manually patched version of Julia.

@tkelman
Copy link
Contributor

tkelman commented Jul 26, 2017

Could the backport be implemented by ClusterManagers or some other package? We need to decouple this functionality from the release and compatibility constraints of the Base language and rest of the standard library, the sooner the better.

@amitmurthy
Copy link
Contributor Author

No.

@tkelman
Copy link
Contributor

tkelman commented Jul 26, 2017

Not an existing package, but this didn't touch anything outside of Distributed, so if that were a package it would be fine.

@amitmurthy
Copy link
Contributor Author

It did change core types and the messaging protocol. Will be difficult to do it externally.

@tkelman
Copy link
Contributor

tkelman commented Jul 26, 2017

The core types and messaging protocol should be in a package.

@sbromberger
Copy link
Contributor

sbromberger commented Aug 30, 2017

I am strongly in favor of backporting this to 0.6:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
parallelism Parallel or distributed computation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants