summaryrefslogtreecommitdiff
path: root/var/spack/repos/builtin/packages/mvapich2/package.py
blob: d1944023d1773e3f358fa1bd64b70c73a3c046fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
import os


class Mvapich2(Package):
    """MVAPICH2 is an MPI implementation for Infiniband networks."""
    homepage = "http://mvapich.cse.ohio-state.edu/"
    url = "http://mvapich.cse.ohio-state.edu/download/mvapich/mv2/mvapich2-2.2b.tar.gz"

    version('2.2b', '5651e8b7a72d7c77ca68da48f3a5d108')
    version('2.2a', 'b8ceb4fc5f5a97add9b3ff1b9cbe39d2')
    version('2.0',  '9fbb68a4111a8b6338e476dc657388b4')
    version('1.9',  '5dc58ed08fd3142c260b70fe297e127c')

    patch('ad_lustre_rwcontig_open_source.patch', when='@1.9')

    provides('mpi@:2.2', when='@1.9')  # MVAPICH2-1.9 supports MPI 2.2
    provides('mpi@:3.0', when='@2.0:')  # MVAPICH2-2.0 supports MPI 3.0

    variant('debug', default=False, description='Enables debug information and error messages at run-time')

    ##########
    # TODO : Process managers should be grouped into the same variant,
    # as soon as variant capabilities will be extended See
    # https://groups.google.com/forum/#!topic/spack/F8-f8B4_0so
    SLURM = 'slurm'
    HYDRA = 'hydra'
    GFORKER = 'gforker'
    REMSHELL = 'remshell'
    SLURM_INCOMPATIBLE_PMS = (HYDRA, GFORKER, REMSHELL)
    variant(SLURM, default=False, description='Sets slurm as the only process manager')
    variant(HYDRA, default=False, description='Sets hydra as one of the process managers')
    variant(GFORKER, default=False, description='Sets gforker as one of the process managers')
    variant(REMSHELL, default=False, description='Sets remshell as one of the process managers')
    ##########

    ##########
    # TODO : Network types should be grouped into the same variant, as
    # soon as variant capabilities will be extended
    PSM = 'psm'
    SOCK = 'sock'
    NEMESISIBTCP = 'nemesisibtcp'
    NEMESISIB = 'nemesisib'
    NEMESIS = 'nemesis'
    MRAIL = 'mrail'
    SUPPORTED_NETWORKS = (PSM, SOCK, NEMESIS, NEMESISIB, NEMESISIBTCP)
    variant(PSM, default=False, description='Configures a build for QLogic PSM-CH3')
    variant(SOCK, default=False, description='Configures a build for TCP/IP-CH3')
    variant(NEMESISIBTCP, default=False, description='Configures a build for both OFA-IB-Nemesis and TCP/IP-Nemesis')
    variant(NEMESISIB, default=False, description='Configures a build for OFA-IB-Nemesis')
    variant(NEMESIS, default=False, description='Configures a build for TCP/IP-Nemesis')
    variant(MRAIL, default=False, description='Configures a build for OFA-IB-CH3')
    ##########

    # FIXME : CUDA support is missing

    def url_for_version(self, version):
        base_url = "http://mvapich.cse.ohio-state.edu/download"
        if version < Version('2.0'):
            return "%s/mvapich2/mv2/mvapich2-%s.tar.gz" % (base_url, version)
        else:
            return "%s/mvapich/mv2/mvapich2-%s.tar.gz"  % (base_url, version)

    @staticmethod
    def enabled(x):
        """Given a variant name returns the string that means the variant is
        enabled

        :param x: variant name
        :return:
        """
        return '+' + x

    def set_build_type(self, spec, configure_args):
        """Appends to configure_args the flags that depends only on the build
        type (i.e. release or debug)

        :param spec: spec
        :param configure_args: list of current configure arguments
        """
        if '+debug' in spec:
            build_type_options = [
                "--disable-fast",
                "--enable-error-checking=runtime",
                "--enable-error-messages=all",
                # Permits debugging with TotalView
                "--enable-g=dbg", "--enable-debuginfo"
            ]
        else:
            build_type_options = ["--enable-fast=all"]

        configure_args.extend(build_type_options)

    def set_process_manager(self, spec, configure_args):
        """Appends to configure_args the flags that will enable the
        appropriate process managers

        :param spec: spec
        :param configure_args: list of current configure arguments
        """
        # Check that slurm variant is not activated together with
        # other pm variants
        has_slurm_incompatible_variants = \
            any(self.enabled(x) in spec
                for x in Mvapich2.SLURM_INCOMPATIBLE_PMS)

        if self.enabled(Mvapich2.SLURM) in spec and \
           has_slurm_incompatible_variants:
            raise RuntimeError(" %s : 'slurm' cannot be activated \
            together with other process managers" % self.name)

        process_manager_options = []
        # See: http://slurm.schedmd.com/mpi_guide.html#mvapich2
        if self.enabled(Mvapich2.SLURM) in spec:
            if self.version > Version('2.0'):
                process_manager_options = [
                    "--with-pmi=pmi2",
                    "--with-pm=slurm"
                ]
            else:
                process_manager_options = [
                    "--with-pmi=slurm",
                    "--with-pm=no"
                ]

        elif has_slurm_incompatible_variants:
            pms = []
            # The variant name is equal to the process manager name in
            # the configuration options
            for x in Mvapich2.SLURM_INCOMPATIBLE_PMS:
                if self.enabled(x) in spec:
                    pms.append(x)
            process_manager_options = [
                "--with-pm=%s" % ':'.join(pms)
            ]
        configure_args.extend(process_manager_options)

    def set_network_type(self, spec, configure_args):
        # Check that at most one variant has been activated
        count = 0
        for x in Mvapich2.SUPPORTED_NETWORKS:
            if self.enabled(x) in spec:
                count += 1
        if count > 1:
            raise RuntimeError('network variants are mutually exclusive \
            (only one can be selected at a time)')

        network_options = []
        # From here on I can suppose that only one variant has been selected
        if self.enabled(Mvapich2.PSM) in spec:
            network_options = ["--with-device=ch3:psm"]
        elif self.enabled(Mvapich2.SOCK) in spec:
            network_options = ["--with-device=ch3:sock"]
        elif self.enabled(Mvapich2.NEMESISIBTCP) in spec:
            network_options = ["--with-device=ch3:nemesis:ib,tcp"]
        elif self.enabled(Mvapich2.NEMESISIB) in spec:
            network_options = ["--with-device=ch3:nemesis:ib"]
        elif self.enabled(Mvapich2.NEMESIS) in spec:
            network_options = ["--with-device=ch3:nemesis"]
        elif self.enabled(Mvapich2.MRAIL) in spec:
            network_options = ["--with-device=ch3:mrail", "--with-rdma=gen2"]

        configure_args.extend(network_options)

    def setup_environment(self, spack_env, run_env):
        if self.enabled(Mvapich2.SLURM) in self.spec and \
           self.version > Version('2.0'):
            run_env.set('SLURM_MPI_TYPE', 'pmi2')

    def setup_dependent_environment(self, spack_env, run_env, extension_spec):
        spack_env.set('MPICH_CC', spack_cc)
        spack_env.set('MPICH_CXX', spack_cxx)
        spack_env.set('MPICH_F77', spack_f77)
        spack_env.set('MPICH_F90', spack_fc)
        spack_env.set('MPICH_FC', spack_fc)

    def setup_dependent_package(self, module, dep_spec):
        self.spec.mpicc  = join_path(self.prefix.bin, 'mpicc')
        self.spec.mpicxx = join_path(self.prefix.bin, 'mpicxx')
        self.spec.mpifc  = join_path(self.prefix.bin, 'mpif90')
        self.spec.mpif77 = join_path(self.prefix.bin, 'mpif77')

    def install(self, spec, prefix):
        # we'll set different configure flags depending on our
        # environment
        configure_args = [
            "--prefix=%s" % prefix,
            "--enable-shared",
            "--enable-romio",
            "--disable-silent-rules",
        ]

        if self.compiler.f77 and self.compiler.fc:
            configure_args.append("--enable-fortran=all")
        elif self.compiler.f77:
            configure_args.append("--enable-fortran=f77")
        elif self.compiler.fc:
            configure_args.append("--enable-fortran=fc")
        else:
            configure_args.append("--enable-fortran=none")

        # Set the type of the build (debug, release)
        self.set_build_type(spec, configure_args)
        # Set the process manager
        self.set_process_manager(spec, configure_args)
        # Determine network type by variant
        self.set_network_type(spec, configure_args)

        configure(*configure_args)
        make()
        make("install")

        self.filter_compilers()

    def filter_compilers(self):
        """Run after install to make the MPI compilers use the
           compilers that Spack built the package with.

           If this isn't done, they'll have CC, CXX, F77, and FC set
           to Spack's generic cc, c++, f77, and f90.  We want them to
           be bound to whatever compiler they were built with.
        """
        bin = self.prefix.bin
        mpicc  = os.path.join(bin, 'mpicc')
        mpicxx = os.path.join(bin, 'mpicxx')
        mpif77 = os.path.join(bin, 'mpif77')
        mpif90 = os.path.join(bin, 'mpif90')

        spack_cc  = os.environ['CC']
        spack_cxx = os.environ['CXX']
        spack_f77 = os.environ['F77']
        spack_fc  = os.environ['FC']

        kwargs = {
            'ignore_absent': True,
            'backup': False,
            'string': True
        }

        filter_file('CC="%s"' % spack_cc,
                    'CC="%s"' % self.compiler.cc, mpicc, **kwargs)
        filter_file('CXX="%s"' % spack_cxx,
                    'CXX="%s"' % self.compiler.cxx, mpicxx, **kwargs)
        filter_file('F77="%s"' % spack_f77,
                    'F77="%s"' % self.compiler.f77, mpif77, **kwargs)
        filter_file('FC="%s"' % spack_fc,
                    'FC="%s"' % self.compiler.fc, mpif90, **kwargs)