Hi all,
Sorry for the delayed response. I've been trying to catch up on email.
Thanks to Ondrej for writing this up and for talking to me while I was at
LANL.
I'll put comments inline below.
On 4/21/15, 1:06 PM, "Ondřej Čertík" <
ondrej...@gmail.com> wrote:
>Hi,
>
>Todd Gamblin (the author of Spack:
>
https://github.com/scalability-llnl/spack) and I just met for few
>hours when Todd visited LANL and we discussed how Spack and Hashdist
>works inside, and I wanted to share what we found out (Todd, feel free
>to correct me if something is inaccurate).
>
>Unlike Conda, Easybuild and other systems, Spack and Hashdist are
>actually extremely similar and almost all the features that Todd and I
>discussed can be done in both systems, one way or another.
>
>Hashdist is very meticulous about hashes, making sure that if you have
>two packages or profiles that have the same hash, then they are build
>*exactly* the same way (same dependencies, versions, build scripts,
>...), in other words, that they are identical. Spack is going in this
>direction as well --- it has hashes, though they currently don't seem
>to always hash everything (some packages only have a name+version, not
>a hash yet). I don't exactly understand all the exceptions, but one
>can essentially imagine as everything having hashes as well (for the
>most part it behaves like that).
Spack currently hashes *just* the spec DAG. So if you want to draw an
analog with hashdist, you might call it "dagdist", where instead of a
hash, a particular configuration is more rigidly parameterized. The idea
was originally that once you got down to version, compiler, compiler
version, arch, *named* variants, and all that for all dependencies, you've
got the key parts of the space covered, and an admin, application user, or
a student can easily name a package and the constraints they care about.
It was *not* really designed with developers directly in mind, the way
hashdist was, so it currently doesn't hash the entire build script. It's
supposed to be a package manager, not a build system, and I think that's
where a lot of the differences in focus come from. I think Jimmy drew
this distinction a while ago, and I'm sorry I didn't get a chance to
respond back then.
I would like to add hashes, at the very least as a way to maintain build
provenance. There is concern at LLNL that exposing this to users generates
a lot of false- positives when you decide whether or not to rebuild. E.g.
What if I just add another version descriptor, or I mess with a
conditional that does not affect the current build? There are a lot of
equivalent builds in that space. I will probably end up adding full
hashing because I think its useful and would've helped me out a number of
times, but I doubt we'd expose it to end users -- we really want them to
be able to just say the name of a package and have it magically appear for
them.
>
>Both Hashdist and Spack have a database where all the packages are
>installed, each package into its own directory based on a hash (in
>Spack case, the hash is not always there, but you can imagine it is).
Yep the hash currently abridges the spec of dependencies in the DAG. We
don't write the hash for packages w/o deps. I think I will change this in
either the next version (0.9) or 1.0.
>You can have more versions of the same package and version, that
>differ perhaps with just a configure option or a patch that was
>applied.
Spack has named variants that are intended to handle things like configure
issues. E.g. You can have miranda+longdouble or something like that. I
intentionally didn't want to expose compiler options to the naming system,
because the idea is to keep that namespace curated and intuitive.
>Hashdist has 'hit', Spack has 'spack', which is a tool written in
>Python that operates on this database. 'spack' is way better in terms
>of providing the user useful information about the various packages
>and dependencies. I posted some examples here:
>
https://gist.github.com/certik/16471771e6b6fc29246e
>We need to improve 'hit' to show this info as well. But the
>information is there in both Hashdist and Spack.
"spack find" also reuses the install spec as a query language. E.g. You
could find all the versions of something built with any gcc and any mpich
with "spack find foo %gcc ^mpich". In general in spack, you can refer to
particularly points in the configuration space ambiguously, and Spack
tries to resolve them to either a) a concrete spec that must be built or
b) a match with something installed. So if the user installed libelf, he
can keep referring to it as just libelf until he installs another version,
at which point he needs to supply @version.
>
>When you install a package into this database, Hashdist uses a profile
>that you have to write by hand, that's currently the only way. Spack's
>only way is a command line --- essentially you specify (more or less)
>the same info, but on a command line. But it is essentially equivalent
>--- the Hashdist profile could (after we implement it) be generated
>from a command line, and Spack could (if it is implemented) to read
>the profile from a file. Both tools install all the packages specified
>in the profile into the database, each into its own directory based on
>hash.
The focus in Spack has always been on allowing users to specify far less
of this -- basically as much as they want, up to the point they care.
Hashdist's yaml files are nice for getting control, but you can add much
of that to a Spack package.py. Spack is trying to manage constraints from
a lot of corners: the user or admin who requests the install, the site
policy (e.g.: prefer mvapich at LLNL and openmpi at LANL if a specific mpi
is not specified), package constraints (e.g. "this package is only
compatible with boost versions 1.47.0 and 1.55.0), and others. All that
is merged when you type "spack install" and the result is a build spec
that tries to satisfy all these constraints.
>
>Hashdist then creates a "profile", which is a unix like structure,
>with symlinks. Spack currently does not do that (though it does it for
>the Python package, by linking the python packages like numpy, scipy
>into it).
Yep. I like the profiles, although I see them as focused mainly on a
single user who is the developer, installer, and user. Spack is designed
to install HPC software for everyone on a system, and to manage it across
a large organization. I don't think we're there yet, but that is the
intent. Might also explain why Spack generates modules and dotkits while
hashdist does not.
>
>Spack creates "module" files, so you can load packages using modules,
>common on HPC machines. I love this, and we should do that.
Yay!
>
>Besides modules, I am currently unclear how else to use the packages from
>Spack.
It's currently the only way. I am leaning towards implementing something
like a profile, because I think I'd use it for development, and I think it
would help people construct a stack. The profile essentially helps with
what Spack calls "concretization". If I install a package, other packages
I install after it that depend on it should try to match its version. I
like that a lot.
There is another use case that I think neither tool currently considers,
and that is the use case of a large HPC machine, with lots of teams and
lots of needs. In this scenario, everything is NOT installed or merged
into a common prefix, and users interact with packages through modules.
Packages are installed into unique prefixes that users know about and use
directly, so you have basically a different way of specifying gc roots.
This is what I want to move towards at LLNL for managing software, and I'd
like a good way to specify it. Some type of generalization of the profile
idea seems like a good way to go to me.
>Compiler support is great in Spack --- you can build some of the
>dependencies with one compiler and the rest with another. We need to
>implement this in Hashdist. Essentially each package knows which
>compiler it is build with. The only way that I know of in Hashdist is
>to set the PROLOGUE (CC, FC, CXX), but that only allows to use one
>compiler for everything.
>
>Spack creates compiler wrappers, for ld, cc, c++, fc, ... and passes
>the RPATH options using them (no need for patchelf). Hashdist is using
>CXXFLAGS, FCFLAGS, LDFLAGS, and uses patchelf to patch the few
>packages whose build system does not allow setting these flags. The
>advantage of compiler wrappers is that you have much better control
>over how things are compiled and linked, which Hashdist needs to rely
>on the package's build system, that it does the right thing (which in
>many cases it doesn't).
Yep -- right now I don't think there's a good generalization in either
system of compilers or architectures, particularly for things like
cross-compiling and arch-specific flags. EasyBuild actually gets this
more right, and another LLNL meta-build system called MixDown had some
nice features for cross-cutting flag settings. I think if you get this
right you can accelerate porting to new, exotic machines, and you can
simplify package files a lot. It's on our roadmap for this year, esp. now
that we have a production code team at LLNL relying on Spack.
>Spack doesn't cache source files (tarballs, git), but allows to create
>"mirrors", which essentially do that.
This could be improved, but the reason there's no central cache right now
is so that we can farm out a build to lots of nodes. Caching is done
separately per build so that we can build the dep DAG in parallel.
>Overall, Spack is more polished from the user/admin perspective.
>Hashdist has a lot more packages (i.e. ~170 in Spack vs ~400 in
>Hashstack), works better on Mac and Windows, and I think it's better
>from a developer (as opposed to admin) perspective (e.g. Hashdist can
>create a profile with symlinks, and can also do a throw away profile
>which you can write into and destroy, without breaking the database).
>Spack has better compiler support. Spack has 'modules' support.
>
>Todd, did I forget anything?
Seems like a good summary to me. I think one thing that may not come out
above is Spack's "concretization" process and how that relates to
hashdist. The output of your gist shows the results of the process:
https://gist.github.com/certik/16471771e6b6fc29246e
Top is the user's input spec, next is the normalized version, and bottom
is *after* concretization is run on the spec, which substitutes in virtual
deps, resolves constraints according to policies, and repeats that until
the spec is no longer ambiguous. I am not 100% clear on hashdist's analog
to that process.
-Todd
>
>Ondrej