-
Notifications
You must be signed in to change notification settings - Fork 89
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
Enhance user experience with MPI #997
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea, thanks for the PR.
Two comments:
- Calling exit from within PlaneWaveBasis is super unexpected and can easily lead to spurious bugs. I'm thinking of a case where one uses MPI for DFTK and to run other things and all of a sudden part of the processes in the global communicator are just gone and the program hangs or does undefined stuff.
- Instead I propose to actually provide a mechanism to do the appropriate splitting of the communicator outside of a
PlaneWaveBasis
call. What I'm thinking is to essentially internally callbuild_kpoints
to determine thelength(kcoords_global)
plus a helper function to do the "shrinking" of the communicator plus potentially calling exit from there. The user would then explicitly call 3 functions. The one to determine the actual numer of k-points, then the split and exit function and then PlaneWaveBasis( ) with the communicator of the appropriate length.
Regarding the tests: I had in mind for a long time to actually switch the logic. Instead of "disabling" MPI tests where needed I think it's better to annotate those, which do support MPI instead. (I.e. instead of a :dont_test_mpi
have a simple :mpi
on the counter-set). If it's too much work, leave it as is and we do a follow-up ...
BTW the test failures in the "normal" tests seem fake (because of a too tightly chosen test tolerance, I think), but the cancelled MPI test points to an issue in your implementation (could be related to the |
Yes, I agree actually. In fact, I was facing this exact problem when trying to run the tests with more than 2 MPI ranks. Ideally, for a robust behavior, the extra MPI ranks should not exit the program, but wait at a synchronization barrier at the end of execution. I am not quite sure how to implement that in a light way, without an arbitrarily large There are 2 important questions to be addressed on the form I think:
I would tend to say no to both of the above. I'll try to come up with something along these lines. |
The latest commit brings major simplifications to this MPI issue. Instead of building sub-communicators and killing processes in a dangerous fashion, I propose to duplicate some k-points over the empty MPI ranks. The weights are adjusted in order to keep exactness of the results. A warning is issued as well. This is the lightest fix I could think of. It is also safe and robust, and the user does not have to think about parallelism in their script. The only potential issue I see is: if the user queries for the k-point mesh after the calculation, they could get a non irreducible k-mesh with duplicates. One possible solution would be to add an extra field to the basis with the original mesh, or write a function that always returns the irreducible mesh.
I don't mind changing from
In my experience, it seems that the |
I'm in favour of this. @abussy Please update and then we can merge this ! @antoine-levitt Objections ? |
@abussy The only thing that we have to be careful with is unfolding the k-point mesh when not using symmetries and during IO operations. |
I haven't looked in details but it looks reasonable, go ahead! |
b9f580e
to
7a46cef
Compare
Notes:
|
src/PlaneWaveBasis.jl
Outdated
@warn("Attempting to parallelize $n_kpt k-points over $n_procs MPI ranks. DFTK does " * | ||
"not support processes empty of k-point. Some k-points were duplicated over the " * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That line is a bit long.
src/PlaneWaveBasis.jl
Outdated
for i_dupl in basis.n_irreducible_kpoints+1:length(basis.kweights_global) | ||
for i_irr in 1:basis.n_irreducible_kpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use =
when loops are over integers.
src/common/mpi.jl
Outdated
@@ -5,6 +5,7 @@ import MPI | |||
Number of processors used in MPI. Can be called without ensuring initialization. | |||
""" | |||
mpi_nprocs(comm=MPI.COMM_WORLD) = (MPI.Init(); MPI.Comm_size(comm)) | |||
mpi_rankid(comm=MPI.COMM_WORLD) = (MPI.Init(); MPI.Comm_rank(comm)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused function ... remove or test
src/symmetry.jl
Outdated
@@ -414,6 +414,10 @@ function unfold_array(basis_irred, basis_unfolded, data, is_ψ) | |||
if !(basis_irred.comm_kpts == basis_irred.comm_kpts == MPI.COMM_WORLD) | |||
error("Brillouin zone symmetry unfolding not supported with MPI yet") | |||
end | |||
if basis_irred.n_irreducible_kpoints < mpi_nprocs(basis_irred.comm_kpts) | |||
#Note: if this routine is ever generalised for MPI, need special care for duplicated KP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after #
. May also be a bit too long.
src/PlaneWaveBasis.jl
Outdated
# Assume that duplicated k-points are appended at the end of the kcoords/kweights array | ||
for i_dupl in basis.n_irreducible_kpoints+1:length(basis.kweights_global) | ||
for i_irr in 1:basis.n_irreducible_kpoints | ||
if maximum(abs.(basis.kcoords_global[i_dupl]-basis.kcoords_global[i_irr])) < eps(T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments:
maximum(abs, ... )
is better (no allocation).- Hmm. This mechanics may be a little brittle. I'd be much more defensive here, e.g. make sure each
i_irr
only matches a single kpoint, e.g. by usingonly
in combination withfindall
or so. Similarly I'd put an assertion that the weights add up to the total electron count or so (see how it's done in other places, the correct number depends on the computational setup).
Also too long a line 😄.
7a46cef
to
3d84e95
Compare
Implemented most concerns raised by @mfherbst during his review. I'd like to raise two points for discussion:
|
Hmm. Yes, but I think that's ok, because it's fine if only the core is tested with MPI and not the rest. But let's think about this some more and leave as is for now.
True, good point.
Update: Ah no, this is before the entire spin business. |
This PR aims at enhancing the user experience when using MPI parallelization by not stopping when
n_ranks > n_kpt
.The current solution of stopping execution with an error message is not optimal. Indeed, for an arbitrary system, it is not trivial to know the number of irreducible K-points in advance. This is particularly annoying when calculations are launched in an automated fashion, where the only safe bet is to not use MPI at all.
The solution proposed here is simple. When a calculation is started with more MPI ranks than K-points, a new MPI communicator is created. This communicator has as many ranks as there are K-points, while the remaining processes exit the program.
While this may lead to idling CPU time, I believe that not crashing improves the experience. Moreover, a warning is printed describing the situation to the user, so that they can optimize their next run. I would also argue that this is not worse than under-parallelizing in some instances where the number of K-point is not a multiple of the number of MPI ranks (maybe we should also issue a warning in such a case?).
I also took the opportunity to fix testing with the
:mpi
tag. The current test onparse(Bool, get(ENV, "CI", "false"))
in thePlaneWaveBasis
creation, which essentially disables MPI testing on the CI, has been removed. Instead, all tests involving kgrids with a single k-point have received the:dont_test_mpi
tag. The number of MPI ranks for MPI testing is also hardcoded to 2: because all tests are run as a single calculation, killing processes whenn_ranks > n_kpt
would make the tests hang. This also fixes local testing viaPkg.test("DFTK"; test_args = ["mpi"])
.