Spack: a Package Manager for Scientific Software

Massimiliano Culpo - SCITAS, EPFL

Spack in a nutshell

A 10 minutes introduction to the tool

Spack is a package manager

  • Tracks metadata for installed software
  • Multiple configurations of the same software
  • Support for supercomputers, linux and MacOS
  • Builds from sources, supports binary packaging
  • Can be used for deployment, development or QA

https://spack.io

Who can profit from Spack?

  • End users of HPC software
  • HPC application teams
  • Package developers
  • User support teams at HPC centers

Spack is open source

  • Started by Todd Gamblin (LLNL, Lead Developer)
  • Very active and engaging community
  • Dual license Apache-2.0 or MIT
  • Switched from LGPL to be company friendly
  • Want to get buy-in and PRs by HPC vendors

https://github.com/spack/spack

Spack is used worldwide!

Sessions on spack.readthedocs.io for one month

Contributions to Spack

Spack is committed to be open source

Clone it and you're ready to go!


	      $ git clone https://github.com/spack/spack.git
	      $ . spack/share/spack/setup-env.sh

	      $ spack install hdf5
	            

Packages are Python classes


class Kripke(Package):
    """Kripke is a simple, scalable, 3D Sn
    deterministic particle transport mini app.
    """
    homepage = "https://codesign.llnl.gov/kripke.php"
    url      = "https://codesign.llnl.gov/kripke-1.1.tar.gz"

    version('1.1', '7fe6f2b26ed983a6ce5495ab701f85bf')
    version('1.0', 'f4247dde07952a5ff866b24e45b5cdd1')

    variant('mpi', default=True, description='Build with MPI.')

    depends_on('mpi', when="+mpi")
                

Easy to work with packages


                    $ # Create a new package in the built-in repository
                    $ spack create <url>

                    $ # Modify an existing package
                    $ export EDITOR='emacs -nw'
                    $ spack edit <package-name>

                    $ # Scrape for versions of an existing package
                    $ spack versions <package-name>
                

3 reasons Spack is different from Easybuild

Spack fights combinatorics with combinatorics!

Complexity of a typical HPC ecosystem

Software must be easy to use in any configuration

The spec syntax describes user's needs


   $ # Install a specific version by appending @
   $ spack install hdf5@1.10.1

   $ # Specify a compiler (and optional version), with %
   $ spack install hdf5@1.10.1 %gcc@4.7.3

   $ # Add special boolean compile-time options with +
   $ spack install hdf5@1.10.1 +szip

   $ # Add custom compiler flags
   $ spack install hdf5@1.10.1 cppflags="-O3 -floop-block"

   $ # Cross-compile on a Cray or Blue Gene/Q
   $ spack install hdf5@1.10.1 target=backend
                

Directives model allowed configurations


class Openblas(MakefilePackage):
    """OpenBLAS: An optimized BLAS library"""

    homepage = 'http://www.openblas.net'
    url      = 'http://github.com/OpenBLAS/v0.2.19.tar.gz'

    version('0.3.4', sha256='4b4b4453251')
    version('0.3.3', sha256='49d88f4494a')

    variant('shared', default=True,
            description='Build shared libraries')
    variant('ilp64', default=False,
            description='64 bit integers')

    conflicts('%intel@16', when='@0.2.15:0.2.19')

                

The concretizer fills in missing details

The abstract spec is turned into a concrete configuration that can be installed

Each configuration is installed in its own prefix

All the software is installed in the Spack's store

The results of concretization can be queried


$ spack spec -Il hdf5+mpi ^mpich
Input spec
--------------------------------
 -   hdf5+mpi
 -       ^mpich

Concretized
--------------------------------
 -   wqoi56r  hdf5@1.10.4%gcc@8.2.0~cxx~debug~fortran~hl+mpi+pic+shared~szip~threadsafe arch=linux-ubuntu18.04-x86_64
 -   k2mhs2k      ^mpich@3.3%gcc@8.2.0 device=ch3 +hydra netmod=tcp +pmi+romio~verbs arch=linux-ubuntu18.04-x86_64
 -   rwrp443          ^findutils@4.6.0%gcc@8.2.0 patches=84b916c0bf8c51b7e7b28417692f0ad3e7030d1f3c248ba77c42ede5c1c5d11e,bd9e4e5cc280f9753ae14956c4e4aa17fe7a210f55dd6c84aa60b12d106d47a2 arch=linux-ubuntu18.04-x86_64
 -   vsawnwb              ^autoconf@2.69%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   i3zd457                  ^m4@1.4.18%gcc@8.2.0 patches=3877ab548f88597ab2327a2230ee048d2d07ace1062efe81fc92e91b7f39cd00,c0a408fbffb7255fcc75e26bd8edab116fc81d216bfd18b473668b7739a4158e,fc9b61654a3ba1a8d6cd78ce087e7c96366c290bc8d2c299f09828d793b853c8 +sigsegv arch=linux-ubuntu18.04-x86_64
 -   bd227q2                      ^libsigsegv@2.11%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   5pyk3t3                  ^perl@5.26.2%gcc@8.2.0+cpanm patches=0eac10ed90aeb0459ad8851f88081d439a4e41978e586ec743069e8b059370ac +shared+threads arch=linux-ubuntu18.04-x86_64
 -   gota243                      ^gdbm@1.18.1%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   ltrvf62                          ^readline@7.0%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   6mbvq7i                              ^ncurses@6.1%gcc@8.2.0~symlinks~termlib arch=linux-ubuntu18.04-x86_64
 -   zaevtj5                                  ^pkgconf@1.5.4%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   tcf52hq              ^automake@1.16.1%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   rcuvdn3              ^libtool@2.4.6%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
 -   3iz4m52              ^texinfo@6.5%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
[+]  ivqu252      ^zlib@1.2.11%gcc@8.2.0+optimize+pic+shared arch=linux-ubuntu18.04-x86_64
                

Spack keeps the metadata of the software it installed!

Installed configurations are stored in a JSON file


{
 "database": {
  "installs": {
   "ivqu252fvh7r5iar6zwx4fmeoxiykln7": {
    "explicit": true,
    "installation_time": 1548272929.178339,
    "ref_count": 0,
    "installed": true,
    "path": "/home/mculpo/PycharmProjects/spack/opt/spack/linux-ubuntu18.04-x86_64/gcc-8.2.0/zlib-1.2.11-ivqu252fvh7r5iar6zwx4fmeoxiykln7",
    "spec": {
     "zlib": {
      "version": "1.2.11",
      "arch": {
       "platform": "linux",
       "platform_os": "ubuntu18.04",
       "target": "x86_64"
      },
      "compiler": {
       "name": "gcc",
       "version": "8.2.0"
      },
      "namespace": "builtin",
      "parameters": {
       "optimize": true,
       "pic": true,
       "shared": true,
       "cflags": [],
       "cppflags": [],
       "cxxflags": [],
       "fflags": [],
       "ldflags": [],
       "ldlibs": []
      }
     }
    }
   }
  },
  "version": "0.9.3"
 }
}
                
opt/spack/.spack-db/index.json

Provenance is preserved for each configuration


$ tree $(spack location -i hdf5)/.spack
<prefix>/.spack
├── archived-files
│   └── config.log
├── build.env
├── build.out
├── repos
│   └── builtin
│       ├── packages
│       │   ├── hdf5
│       │   │   └── package.py
│       │   └── zlib
│       │       └── package.py
│       └── repo.yaml
└── spec.yaml

6 directories, 7 files
                
The JSON database can be regenerated based on this information

Tools are then built over the data in the DB

  • Query commands
  • Uninstallation procedures
  • Module file generation
  • Python modules activation
  • ...

Query what's installed from the command line


$ spack find zlib
==> 1 installed package
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
zlib@1.2.11

$ spack find --start-date 'a month ago'
==> 3 installed packages
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
hdf5@1.10.4  openblas@0.3.5  zlib@1.2.11
                

Uninstall anything in an easy and safe way


$ spack find zlib
==> 2 installed packages
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
zlib@1.2.8  zlib@1.2.11

$ spack uninstall zlib@1.2.8
==> The following packages will be uninstalled:

-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
    yxoie27 zlib@1.2.8%gcc+optimize+pic+shared
==> Do you want to proceed? [y/N] y
==> Successfully uninstalled zlib@1.2.8%gcc@8.2.0 [...] /yxoie27
                

Generate module files for HPC sites

  • Output highly customizable using YAML files
  • By default generated via post-install hooks
  • Can be managed via command line afterwards
  • Everything is powered by Jinja2 templates
  • Support for both TCL and Lua modules

Tutorial: Spack 101 - module files

Generate module files for HPC sites


modules:
  lmod:
    core_compilers:
      - gcc@4.8.5
    hierarchy:
      - mpi
      - lapack
    hash_length: 0
    all:
      suffixes:
        +mpi: mpi
        +openmp: openmp
        ...
                

Tutorial: Spack 101 - module files

Activate python modules on a fine-grained base


$ spack install python py-scipy py-numpy
[...]

$ # Activate only py-numpy
$ $ spack activate py-numpy
==> Activating extension py-numpy@1.15.2%gcc@8.2.0+blas+lapack arch=linux-ubuntu18.04-x86_64 /o626ufb for python@2.7.15%gcc@8.2.0+dbm~optimizations patches=123082ab3483ded78e86d7c809e98a804b3465b4683c96bd79a2fd799f572244 +pic+pythoncmd+shared~tk~ucs4 arch=linux-ubuntu18.04-x86_64 /nft4nfs

$ $(spack location -i python)/bin/python
Python 2.7.15 (default, Jan 25 2019, 09:14:19)
[GCC 8.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import scipy
[...]
ImportError: No module named scipy
                
Activated modules look like they are site installed

Scrape build logs of installed configurations


$ spack log-parse $(spack location -i hdf5)/.spack/build.out
0 errors

$ spack log-parse --show=errors,warnings $(spack location -i hdf5)/.spack/build.out
0 errors
741 warnings
     534       CC       H5dbg.lo
     535       CC       H5system.lo
     536     H5system.c: In function 'HDfprintf':
  >> 537     H5system.c:276:45: warning: format not a string literal, argument types not checked [-Wformat-nonliteral]
     538                              n = fprintf(stream, format_templ, x);
     539                                                  ^~~~~~~~~~~~
[...]
                
Permits to investigate issues reported on software that has already been deployed

Spack can fine-tune compiler options to user's needs!

Wrapper scripts mediate compilation

Also ensure the software runs the way it was built

Spack Environments

The cool new feature!

Spack's store might be inconvenient at times


$ spack find
==> 70 installed packages
-- linux-ubuntu16.04-x86_64 / clang@3.8.0-2ubuntu4 ----
tcl@8.6.8  zlib@1.2.8  zlib@1.2.11

-- linux-ubuntu16.04-x86_64 / gcc@4.7 ----
zlib@1.2.11

-- linux-ubuntu16.04-x86_64 / gcc@5.4.0 ----
adept-utils@1.0.1  hdf5@1.10.4          mpc@1.1.0
autoconf@2.69      hdf5@1.10.4          mpfr@3.1.6
automake@1.16.1    hdf5@1.10.4          mpich@3.2.1
boost@1.68.0       hwloc@1.11.9         mpileaks@1.0
bzip2@1.0.6        hypre@2.15.1         mumps@5.1.1
...
                
It would be nice to have a terser view without throwing away what's already installed

Spack environments to the rescue!


$ spack env create my-project
==> Created environment 'my-project' in [...]/my-project

$ spack env activate my-project
$ spack env status
==> In environment my-project

$ spack find
==> In environment my-project
==> No root specs

==> 0 installed packages
                
An environment is a virtualized Spack instance that can be used for a specific purpose

Environments use what's available in the store


$ spack find
==> In environment my-project
==> No root specs

==> 0 installed packages

$ spack install zlib hdf5~mpi
==> zlib is already installed in [...]
==> Installing hdf5
[...]
==> Successfully installed hdf5
  Fetch: 0.06s.  Build: 1m 14.67s.  Total: 1m 14.73s.
[+] /home/.../hdf5-1.10.4-xucyflhbo2p47n46smfsqo7p2y3hijmd
                
zlib has been reused, hdf5 has been installed in the Spack's store and then added

Users can set-up groups of packages at once


$ spack add hdf5~mpi python
==> Adding hdf5~mpi to environment my-project
==> Adding python to environment my-project
==> Adding mpich to environment my-project

$ spack find -v
==> In environment my-project
==> Root specs
hdf5~mpi  mpich  python

==> 0 installed packages

$ spack install
[...]
                
"spack install" concretizes the root specs and builds what's missing

Each detail can be finely tuned


$ spack config get
# This is a Spack Environment file.
#
# It describes a set of packages to be installed, along with
# configuration settings.
spack:
  # add package specs to the `specs` list
  specs: [hdf5~mpi, python, mpich]
  mirrors: {}
  modules:
    enable: []
  repos: []
  packages: {}
  config: {}
                
Use "spack config edit" to edit the file and add custom configurations

Abstract user requests are stored in spack.yaml

  • It's the configuration file we have seen before
  • Does not have to live inside Spack tree
  • Can be bundled with anything
  • Can be manipulated directly if it is in the pwd
  • Use spack.yaml to distribute an environment

Fully concretized specs are in spack.lock


{
  "concrete_specs": {
   "teneqii2xv5u6zl5r6qi3pwurc6pmypz": {
    "xz": {
      "version": "5.2.4",
      "arch": {
        "platform": "linux",
        "platform_os": "ubuntu16.04",
      "target": "x86_64"
 },
 ...
                
Using either spack.yaml or spack.lock you can recreate an environment

Coming soon in Spack environments...

Associate a view with an environment


spack:
  specs:
  - hdf5+mpi
  - bzip2

  view: True
                                

$ ls .spack-env/view/bin
h5clear   h5diff   ...   h5unjam
h5copy    h5dump   ...   ph5diff
h5debug   ...      ...

$ ls .spack-env/view/include
H5ACpublic.h     ...   hdf5.h
H5Apublic.h      ...   zconf.h
H5Cpublic.h      ...   zlib.h
                                
Views are projections of the Spack combinatorial space into a single prefix

Spack: next big things

Highlights from what's planned for 2019

CI infrastructure for source and binary packages

YAML format to describe entire stacks


spack:
  matrices:
  - specs:
    - zlib@1.2.8
    - zlib@1.2.11
    - hdf5~mpi@1.10.2
    - hdf5+mpi@1.10.2
    toolchains:
    - ['%gcc@4.9.3', ^mvapich2@2.2]
    toolchain-generator:
    - ['%gcc@7.3.0', '%intel@18.0.0']
    - [^mvapich2@2.2, ^mvapich2@2.3]
    exclude:
    - '%intel@18.0.0 ^mvapich2@2.2'

  - specs:
    - cmake@3.8.2
    - python@2.7.15
    toolchains:
    - ['%gcc@7.3.0']
                
Single command deployment at HPC facilities

Chain instances to read upstream databases

It's Spack all the way down!

Specific target information in specs

Given a target automatically activate optimizations

Concretization prefers already available binaries

Probably the most wanted feature in Spack

Thanks for listening! Questions?