-
Notifications
You must be signed in to change notification settings - Fork 203
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
consider potential of multiple subtoolchains in get_toolchain_hierarchy #2466
consider potential of multiple subtoolchains in get_toolchain_hierarchy #2466
Conversation
This PR replaces easybuilders#2234. subtoolchains are now searched using a breadth-first-search, which allows multiple subtoolchains per toolchain. Some subtoolchains such as golf and golfc are now marked OPTIONAL since they do not have to exist as modules, and can be skipped. Since those optional subtoolchains cannot usually be found via a dependency search (as toolchain easyconfigs do not typically have subtoolchains as dependencies) try to search for subtoolchain/version with the same version as the parent. E.g. goolfc/2.6.10 searches for golfc/2.6.10, and golfc/2.6.10 searches for golf/2.6.10 and gcccuda/2.6.10.
easybuild/toolchains/golfc.py
Outdated
from easybuild.toolchains.fft.fftw import Fftw | ||
from easybuild.toolchains.linalg.openblas import OpenBLAS | ||
|
||
class Golfc(GccCUDA, Golf, OpenBLAS, Fftw): |
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.
expected 2 blank lines, found 1
easybuild/toolchains/golfc.py
Outdated
from easybuild.toolchains.fft.fftw import Fftw | ||
from easybuild.toolchains.linalg.openblas import OpenBLAS | ||
|
||
class Golfc(GccCUDA, Golf, OpenBLAS, Fftw): |
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.
expected 2 blank lines, found 1
Now a bit of merging of conflicts is in order here. |
Just a merge, no conflicts. |
Reopening since travis still has not reported after 19 hours. |
This looks sane to me. How much testing have you done? |
I've had a simpler variant (from #2234) of this in Compute Canada for ages (since May 2017), but not this exact code yet. Will do a few tests here. |
I did a test with this code on CP2K-iomkl now which in our setup depends on libxsmm-iimkl using this subtoolchain mechanism. It works. I did promise in last week's conf call however to add a comment with the dependency tree for the most complex case (goolfc). So I will do that. |
One more thing, this approach should be applied to many other toolchains to be complete, at least the following: should I submit a seperate PR for this fairly boring but noisy diff? |
I think a separate PR for that would be easier to handle? @boegel ?? |
travis now fails with |
Related to Travis issue: |
@riccardomurri Can this somehow be caused by the GC3Pie release? The latest version of GC3Pie gets installed automagically, it seems like 2.5.0 includes a backwards incompatible change?! |
The The |
@riccardomurri Well, ok, I can see the motivation, but this is a backward-incompatible change, so anyone who will be trying to use an existing EasyBuild release with GC3Pie 2.5.0 will run into this... :) Very good reason to get #2474 ready & merged to be included in EasyBuild v3.7.0 ASAP... :) |
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.
@bartoldeman Do you mind adding a dedicated test for det_subtoolchain_version
? In test/framework/easyconfig.py
would make sense, but put it wherever it's most convenient (get_toolchain_hierarchy
is tested in test/framework/robot.py
)
# skip dummy if add_dummy_to_minimal_toolchains is not set | ||
return None | ||
|
||
return {'name': subtoolchain_name, 'version': subtoolchain_version} |
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.
@bartoldeman I would just return subtoolchain_version
here? I don't really see the point in returning a dict value here...
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 can't because of the change of name from "GCCcore" to "dummy" for legacy toolchains. I did not want to remove that code.
I suspect the idea is that older toolchains had GCC directly above dummy, but the gcc toolchain has GCCcore as the subtoolchain which does not exist in those situations.
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.
Ah, OK, I figured there must have been a good reason.
Then: i) mention that in a comment, explain why you need to return the subtoolchain name too, ii) just make this a tuple (subtoolchain_name, subtoolchain_version)
.
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.
There are some ways around this of course, but e.g. moving the GCCcore logic back to the main function needs another check for dummy there too then, which is awkward...
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.
No, it's fine like this, just needs a comment since it doesn't make sense unless you take the whole function into account.
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.
In the end I found a more elegant way by declaring the gcccore toolchain as optional. It still needs some special logic in the main loop, but det_subtoolchain_version does exactly that now and nothing more.
Next will be tests for that but probably on Monday :)
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.
Only read this after your earlier comment, looks good to me in its current state, it doesn't hurt that the fallback to dummy for GCCcore
stands out a bit.
subtoolchain_name, subtoolchain_version = subtoolchains[current_tc_name], None | ||
toolchain_hierarchy.insert(0, {'name': current_tc_name, 'version': current_tc_version}) | ||
for subtoolchain_name in subtoolchain_names: | ||
tc = det_subtoolchain_version(current_tc, subtoolchain_name, optional_toolchains, cands) |
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.
If you change the return type of det_subtoolchain_version
, I'd go with subtc_ver
(but I guess subtoolchain_version
is better for consistency with subtoolchain_name
)
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.
With the above in mind:
subtc_name, subtc_ver = det_subtoolchain_version(current_tc, subtoolchain_name, optional_toolchains, cands)
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 won't work since the function can also return None
.
I tried to implement your suggestion but I don't think it looks any better:
@@ -185,7 +185,7 @@ def det_subtoolchain_version(current_tc, subtoolchain_name, optional_toolchains,
# skip dummy if add_dummy_to_minimal_toolchains is not set
return None
- return {'name': subtoolchain_name, 'version': subtoolchain_version}
+ return subtoolchain_name, subtoolchain_version
@toolchain_hierarchy_cache
@@ -278,12 +278,15 @@ def get_toolchain_hierarchy(parent_toolchain):
cands = [c for c in cands if c['name'] in subtoolchain_names]
for subtoolchain_name in subtoolchain_names:
- tc = det_subtoolchain_version(current_tc, subtoolchain_name, optional_toolchains, cands)
+ subtc = det_subtoolchain_version(current_tc, subtoolchain_name, optional_toolchains, cands)
# add to hierarchy and move to next
- if tc is not None and tc['name'] not in visited:
- toolchain_hierarchy.insert(0, tc)
- bfs_queue.insert(0, tc)
- visited.add(tc['name'])
+ if subtc is not None:
+ subtc_name, subtc_ver = subtc
+ if subtc_name not in visited:
+ tc = {'name': subtc_name, 'version': subtc_ver}
+ toolchain_hierarchy.insert(0, tc)
+ bfs_queue.insert(0, tc)
+ visited.add(subtc_name)
_log.info("Found toolchain hierarchy for toolchain %s: %s", parent_toolchain, toolchain_hierarchy)
return toolchain_hierarchy
unless I am missing something?
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.
Ah, I overlooked the fact that you need tc
as a dict anyway... You're right, keep it as is. :)
for subtoolchain_name in subtoolchain_names: | ||
tc = det_subtoolchain_version(current_tc, subtoolchain_name, optional_toolchains, cands) | ||
# add to hierarchy and move to next | ||
if tc is not None and tc['name'] not in visited: |
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's the tc['name']
that makes this a bit awkward, just use subtoolchain_name
?
Legacy where gcc/iccifort/etc have dummy directly as subtoolchain, and GCCcore does not exist.
@bartoldeman Gave this another review, looks good, just missing the test for |
The OPTIONAL flag in the toolchain definitions, that's used in a toolchain that is optional, not in toolchains that have optional sub-toolchains? |
It is the toolchain itself that is optional. However I hit an issue by marking gcccore optional it marked almost all others optional too through subclassing...will correct tomorrow. Today we are all off in Canada (labour day) |
By allowing both GCCcore and dummy as allowed subtoolchains for compilers we no longer need the special logic in easyconfig.py. However I did need to unconditionally return '' as version for the dummy toolchain to avoid inconsistencies with 'dummy','dummy', which resolves to the same dependency anyway.
This is now done in the candidate search instead of det_toolchain_version, and applies to all subtoolchains that are composite, so they can have the same version as the parent.
test/framework/easyconfig.py
Outdated
@@ -2078,6 +2080,52 @@ def test_resolve_template(self): | |||
# '%(name)' is not a correct template spec (missing trailing 's') | |||
self.assertEqual(resolve_template('%(name)', tmpl_dict), '%(name)') | |||
|
|||
|
|||
def test_det_subtoolchain_version(self): |
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.
too many blank lines (2)
ok, I have been able to simplify the code quite a bit by giving the gcc, iccifort and pgi toolchains multiple subtoolchains (GCCcore and dummy). This way the data can do the talking which looks much more elegant than special case code. Test case added for det_subtoolchain_version too. |
|
||
class GccToolchain(GCCcore): | ||
"""Simple toolchain with just the GCC compilers.""" | ||
NAME = 'GCC' | ||
COMPILER_MODULE_NAME = [NAME] | ||
SUBTOOLCHAIN = GCCcore.NAME | ||
SUBTOOLCHAIN = [GCCcore.NAME, DUMMY_TOOLCHAIN_NAME] |
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.
@bartoldeman How does this relate to --add-dummy-to-minimal-toolchains
?
dummy
should only be considered a subtoolchain when --add-dummy-to-minimal-toolchains
is enabled?
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.
Actually, it's probably OK, since dummy
was already a subtoolchain for GCCcore
(see below)..
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.
exactly. the bfs tree has dummy twice here:
gcc
/ \
gcccore dummy
|
dummy
which actually corresponds to pre-existing behaviour since the legacy gcc toolchains do not have gcccore. det_toolchain_version
then explicitly filters out dummy if --add-dummy-to-minimal-toolchains
is not set.
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.
hmm, should adjust the ascii-art diagram comment then!
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.
Yes, indeed :)
It's basically this:
gcc
/ \
/ \
gcccore /
\ /
\ /
dummy
(I need more practice in this ASCII art thing, ugh...)
easybuild/toolchains/gcccore.py
Outdated
@@ -37,3 +37,4 @@ class GCCcore(Gcc): | |||
# Replace the default compiler module name with our own | |||
COMPILER_MODULE_NAME = [NAME] | |||
SUBTOOLCHAIN = DUMMY_TOOLCHAIN_NAME | |||
OPTIONAL = True |
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.
@bartoldeman Can you clarify why GCCcore
is optional?
It's the base of every toolchain, or am I overlooking something?
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's not the base of the older toolchains with GCC 4.8 / intel 2015.2 and older.
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.
Right, I overlooked that...
Please clarify with a comment above:
# GCCcore is only guaranteed to be present in recent toolchains
# for old versions of some toolchains (GCC, intel) it is not part of the hierarchy and hence optional
Apart from the missing toolchains (esp intelcuda and friends), this looks good. |
Missed those, thanks @akesandgren.
@akesandgren Isn't |
nvm, changes in 345c515 make sense... Anything else @akesandgren? |
No @boegel, @akesandgren is right. I missed intelcuda and intel-para as well. Some others could have multiple subtoolchains except they do not exist yet. I skipped them for now: |
I'm a bit tired so this is probably wrong^3, but why doesn't iccifort have both icc and ifort listed as subtoolchains |
@akesandgren Neither |
Going in, thanks @bartoldeman |
elif len(uniq_subtc_versions) == 0: | ||
if subtoolchain_name not in optional_toolchains: | ||
# raise error if the subtoolchain considered now is not optional | ||
raise EasyBuildError("No version found for subtoolchain %s in dependencies of %s", |
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.
@bartoldeman I'm hitting this error with our intel-para
toolchain but I don't understand why since Iimkl
is an optional toolchain
== 2018-09-21 14:42:03,912 build_log.py:158 ERROR EasyBuild crashed with an error (at ?:124 in __init__): No version found for subtoolchain <class 'easybuild.toolchains.iimkl.Iimkl'> in dependencies of intel-para (at easybuild/framework/easyconfig/easyconfig.py:162 in det_subtoolchain_version)
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.
Never mind PR on the way
elif len(uniq_subtc_versions) == 0: | ||
if subtoolchain_name not in optional_toolchains: | ||
# raise error if the subtoolchain considered now is not optional | ||
raise EasyBuildError("No version found for subtoolchain %s in dependencies of %s", |
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.
Never mind PR on the way
This PR replaces #2234, and depends on
#2464and#2465.subtoolchains are now searched using a breadth-first-search, which
allows multiple subtoolchains per toolchain.
Some subtoolchains such as golf and golfc are now marked OPTIONAL
since they do not have to exist as modules, and can be skipped.
Since those optional subtoolchains cannot usually be found via a
dependency search (as toolchain easyconfigs do not typically have
subtoolchains as dependencies)
try to search for subtoolchain/version with the same version as
the parent. E.g. goolfc/2.6.10 searches for golfc/2.6.10, and
golfc/2.6.10 searches for golf/2.6.10 and gcccuda/2.6.10.