-
Notifications
You must be signed in to change notification settings - Fork 429
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
RF: configure num_threads==-1 as the value to use all cores #2352
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2352 +/- ##
==========================================
- Coverage 91.38% 85.23% -6.16%
==========================================
Files 254 126 -128
Lines 33851 16562 -17289
Branches 3569 2681 -888
==========================================
- Hits 30936 14117 -16819
+ Misses 2111 1759 -352
+ Partials 804 686 -118
|
As an alternative, I would also consider using Unfortunately there is not good consensus on either this behavior or the name for the |
Thanks for taking care of this @drombas !
IMO using two (or more) different values to mean the same thing is misleading.
At first sight, this looks inconsistent/undesirable to me, but have not investigated the reasons, if any. Maybe others can elaborate on this.
Although not desirable, I'd definitely be for it if the new values are the ones that make sense/are sensible defaults. Interesting what @grlee77 says #2352 (comment) . That also broadens the scope of our issue. As for the terms used, I wouldn't know to tell which term is more accurate/honors its purpose, but have seen mixed use in the past elsewhere with the terms |
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.
Hi @drombas,
Thank you for doing this again!
After all comments and more thinking, see below some suggestions:
Modify the name of the argument num_proceses --> num_threads in reslice.py and test_reslice.py
you should keep num_processes
here. This is different than num_threads
. To simplify it means we spawn processes (run new python interpreter to parallelize).
Delete the num_threads argument where it is not used
you will have to keep it and start a deprecation cycle to warn the users
The number of used cores by default differs between functions. Does it make sense to use all cores by default in some functions and only 1 in others?
To me it makes sense. It depends a lot on the algorithms. Some of them are greedy and we do not want to kill/freeze the laptop of the user (they will blame the algo which is wrong)
This PR modifies the default value of num_threads in several functions, which was one of the main concerns discussed in #2300. What do you think @jhlegarreta,@skoudoro?
After @jhlegarreta and @grlee77 comments, I recommend that you keep the default value at None
or the value indicated, and inside each function just initialize the num_threads
by doing:
num_threads = num_threads or -1
Does it make sense to you @drombas?
Thank you all for your comments! TBH I don't have a strong opinion on this kind of conventions. On your points @skoudoro:
Sorry for that, thought it was just a different naming for the same.
Ok, I'll keep those.
Just to clarify, you mean we keep def anyFunction(...,num_threads=None): and then inside the function we initialize it to if num_threads is None:
num_threads = -1 It sounds reasonable as it doesn't change the default but incorporates As for selecting between |
Exactly and this if num_threads is None:
num_threads = -1 |
Before reviewing the code, please notice that I added some extra tests to account for invalid Could we restart those failing tests? (All related tests passed locally ) |
Thanks for the effort @drombas. Restarted the tests. |
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 had a quick look at the changes: the docstrings and the default values in the method signatures are contradicting, e.g.:
def _bundle_minimum_distance_matrix(double [:, ::1] static,
double [:, ::1] moving,
cnp.npy_intp static_size,
cnp.npy_intp moving_size,
cnp.npy_intp rows,
double [:, ::1] D,
num_threads=None):
(...)
num_threads : int, optional
Number of threads. If -1 (default) then all available threads will be
used.
Default is None
. Have not looked at all signatures, but I had a look at a few of them, and all them fall into this contradiction. I'd dare to say that for people that will be looking at the documentation this is quite confusing, and IMHO it is as confusing from a developer's point of view.
Thanks @jhlegarreta !
The intention was to keep We could also return to the original plan and get rid of |
I still believe that using two values with the same meaning is confusing, and this means that I'd be revisiting the use of Also, it looks like every method involved is forced to do its Sorry, but I feel that I cannot comment further being still not convinced by the solution. Thanks for the effort @drombas. |
This PR does not try to fix this anymore @jhlegarreta. it tries to standardize how we set up
that's why, the first step here is
I agree with this point. could you create a function @drombas in |
@jhlegarreta @drombas @grlee77 : More details about their rules below or in this link. I am ok to follow the same rules
|
We might want to check how the above (#2352 (comment), #2352 (comment)) would work when calling the CLIs, but looks like a step forward. |
okey, let's try that. I think we already have something similar in omp.pyx that we can adapt to the scikit-learn logic. I will give it a try during next days. |
Hi @drombas, Do you think you will have time to finish this PR before Friday and the new DIPY release? or should I move this PR for the next release cycle in June? Thank you for your feedback |
Hi @skoudoro, By tomorrow I should have finished the changes so, if it is ok we can decide tomorrow. |
sounds like a plan 👍🏾 . no problem |
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 very nice work @drombas. Thanks a lot for that.
Overall, it looks good. I still need to look at it more carefully. See below some comments.
Also, Can you add your docstring as a note on the [api_change.rst](https://github.com/dipy/dipy/blob/master/doc/api_changes.rst)
. You can create a section for DIPY 1.4.1.
Thanks!
Thanks for the comments @skoudoro. In summary, the selection of the number of cores is now centralized in two files:
Finally I split it in two as the logic is slightly different: for OpenMP the environment variable OMP_NUM_THREADS is considered while for multiprocessing it is not. I also thought it could be confusing to use omp.pyx to define the logic of parallelization using multiprocessing package. To help with the review a bit here is an organized list of the main changed files. |
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 is good to go!
I will wait until Friday evening to see if there is any additional comment and then go ahead and merge it.
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 for the hard work and for having persevered @drombas.
Looks very clean.
Thanks for the spreadsheet. Very helpful. On a related note, automatically knowing which methods are multi-threaded can be helpful to developers and users at some point. But that is a separate endeavor.
Not sure if I followed the removal in here
https://github.com/dipy/dipy/pull/2352/files#diff-5fcc99cde72e6ea9a640d32a91756c178d916d26ae479e0da4c766a61c45dd4cL226
But if it's OK, then dismiss the observation.
I am missing dedicated test methods for the accepted values in the determine_num_processes
and determine_num_threads
methods.
A minor in-line comment.
The last two comments can be addressed at a latter time if it is preferred to have this merged as soon as possible.
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.
💯 to the hard work @drombas.
Thanks for the quick feedback!
After the changes that part is not reached. It is true, though, that there is a catch of NotImplementedError exception that I did not implement (not sure how critical it is as it is the only place I saw that check). I added it just in case. |
thank you @drombas! merging |
I'd say that the exception added in 1e439ce should get tested. Thanks. |
That exception is raised when the number of cores is undetermined and TBH I don't know how we could test it. |
Can the exception be forced to be raised and the expected message or result be checked? |
I imagine it should be possible if we knew exactly how the number of cores is determined. |
Related to #2300 and a continuation of #2341.
Proposed Changes
num_threads<=0
as the option to use all cores across the codebasenum_proceses --> num_threads
in reslice.py and test_reslice.pynum_threads
argument where it is not usedImportant point
Unlike in #2341, most of the functions edited here used all cores by default (using
None
) so, to keep this behavior, I set the new default to0
. This implies that:1
in others?num_threads
in several functions, which was one of the main concerns discussed in NF: Add "None" options in the CLIs #2300. What do you think @jhlegarreta,@skoudoro?