-
Notifications
You must be signed in to change notification settings - Fork 12
Reduce warnings & Initialise MPI with MPI_Init_thread #47
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
base: main
Are you sure you want to change the base?
Conversation
aradi
left a comment
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.
Thanks a lot for the PR! This PR should be split into 2 separate ones:
- Compiler warning workarounds
- MPI-initialization
as the two features are completely unrelated.
As for the compiler warnings: I am not a big fan of writing workarounds to avoid false positive compiler warnings. I am fine with the explicit allocate() statements (to avoid automatic lhs-(re)allocation), but I would not prefer to incorporate the other changes (the string addition and the placeholder local instance variable.)
For the MPI initialization, see the detailed comment below, I think the solution proposed there would be more elegant and robust.
.gitignore
Outdated
| /_* | ||
| /build | ||
| *.mod | ||
| /cmake-* |
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.
How and why are files matching this pattern generated during code development or build? (The .gitignore of the repository should only contain patterns, which are generated during the common development workflow.)
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.
This is a Jetbrains convention for cmake build folder names. It's relatively common, but not defacto. I can drop the commit if you prefer.
| !> State of global random number | ||
| integer :: rn = 0 |
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.
Note, this example is there to demonstrate the usage of module variables to pass initialization information. We should, therefore, explicitly do not create a variable within the type, in order to make the example clearer. (What is the actual reason for adding this (unused) instance variable?)
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.
You've got a type-bound procedure that does not use this.
Happy to roll back the change
| allocate(match(size(value1, dim=1), size(value1, dim=2))) | ||
| match = value1 == value2 |
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.
| allocate(match(size(value1, dim=1), size(value1, dim=2))) | |
| match = value1 == value2 | |
| allocate(match(size(value1, dim=1), size(value1, dim=2))) | |
| match(:,:) = value1 == value2 |
Whenever lhs reallocation is not wanted (because lhs had been already allocated) or not possible (because lhs is not allocatable), the placeholder indices should be used for arrays on the lhs. This makes the intention of assigning into more pronounced.
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.
Doesn't this only occur when the LHS is an allocatable variable being assigned a value whose shape/length doesn’t match its current allocation (like, the LHS not being allocated)? In this case, a shape mismatch is impossible because you have if-statements guarding against it.
But happy to make the change
| allocate(match(size(value1, dim=1))) | ||
| match = value1 == value2 |
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.
| allocate(match(size(value1, dim=1))) | |
| match = value1 == value2 | |
| allocate(match(size(value1, dim=1))) | |
| match(:) = value1 == value2 |
|
|
||
| ! Note: factorial(n) with n > 13 overflows with 32 bit integers | ||
| nn = int(13 * rand) + 1 | ||
| this%rn = nn |
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.
This should be removed, as we do not want to use variables within the type instance in this example.
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.
ok
| allocate(match(size(value1, dim=1), size(value1, dim=2))) | ||
| match = is_close_elem(value1, value2, atol=atol, rtol=rtol) |
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.
| allocate(match(size(value1, dim=1), size(value1, dim=2))) | |
| match = is_close_elem(value1, value2, atol=atol, rtol=rtol) | |
| allocate(match(size(value1, dim=1), size(value1, dim=2))) | |
| match(:,:) = is_close_elem(value1, value2, atol=atol, rtol=rtol) |
| allocate(match(size(value2, dim=1), size(value2, dim=2))) | ||
| match = is_close_elem(value1, value2, atol=atol, rtol=rtol) |
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.
| allocate(match(size(value2, dim=1), size(value2, dim=2))) | |
| match = is_close_elem(value1, value2, atol=atol, rtol=rtol) | |
| allocate(match(size(value2, dim=1), size(value2, dim=2))) | |
| match(:,:) = is_close_elem(value1, value2, atol=atol, rtol=rtol) |
| ! & helpmsg="list of tests and suites to include or to exclude when prefixed with '~' (e.g. " //& | ||
| ! & "'somesuite ~somesuite/avoidedtest' would run all tests except 'avoidedtest' in the test " //& | ||
| ! & "suite 'somesuite')")& |
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.
Why should we use sting addition, if Fortran has a perfect feature of breaking strings into continuation lines? I don't see the point for this change...
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.
I agree it makes no sense, but GCC with warnings enabled will catch what you currently have. Unlike most of the warning fixes, which affect fortuno's test cases (we don't build by default), this one gets caught by Octopus's CI.
So the point is either client codes are forced into disabling specific warnings or one does a trivial patch upstream. Alternatively, we discussed scoping compiler flags on a per library basis some time ago, but since Cristian's left, this is a non-starter.
| & helpmsg="list of tests and suites to include or to exclude when prefixed with '~' (e.g. " // & | ||
| & "'somesuite ~somesuite/avoidedtest' would run all tests except 'avoidedtest' in the test " // & | ||
| & "suite 'somesuite')") |
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.
See comment just above. Let's keep the original form, unless there is a really convincing argument for the change.
src/fortuno_mpi/mpienv.f90
Outdated
|
|
||
| call MPI_Init(ierror) | ||
| if (ierror /= 0) error stop "MPI_Init failed in init_mpi_env" | ||
| call MPI_Init_thread(MPI_THREAD_MULTIPLE, provided) |
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.
The problem with this approach is, that if the client is using the high level runner routine execute_mpi_cmd_app(), it has no way to check before the tests start, whether the MPI framework provides the necessary level of thread support. So, it is safer here to use the lowest possible threading level (MPI_THREAD_SINGLE, which must work, if the MPI framework works at all). This is also the level of threading support Fortuno requires.
In order to allow codes to use a more advanced threading support, we should allow clients to initialize the MPI-framework before calling execute_mpi_cmd_app() and pass then the global communicator (as optional argument) to execute_mpi_cmd_app(). Fortuno should then just use the provided communicator without initializing or finalizing the MPI framework. The client would then also be responsible for the finalization of the MPI framework after the call.
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.
it has no way to check before the tests start, whether the MPI framework provides the necessary level of thread support.
How does this prevent the caller from calling execute_mpi_cmd_app , followed by a setup that calls MPI_Query_thread?
Fortuno should then just use the provided communicator without initializing or finalizing the MPI framework. The client would then also be responsible for the finalization of the MPI framework after the call.
As discussed over email, I'm fine with this idea. I'll open a separate PR for it
I'll drop the commit and open a separate PR |
51ec80c to
a8f74c1
Compare
This MR does two separate things:
MPI_INITwithMPI_Init_thread, where I request the maximum threading supportW.r.t. compiler warnings, most of the changes silence false positives resulting from implicit LHS allocation. In these cases, I've just added explicit
allocatestatements. A couple others are from unused arguments. In one instance, I've removed an argument (see the logger) and in the other I'm assigned a dummy attribute.W.r.t. replacing
MPI_INITwithMPI_Init_thread. There's no obvious reason (to me) not to do this, and if a consumer/client code initialises with anything other thanMPI_THREAD_SINGLE, this is required. As such, I initialise withMPI_THREAD_MULTIPLE, which should maximise support.It is still the client code's responsibility to check what's actually provided by the MPI library, and handle appropriately: