Skip to content

Commit

Permalink
postgresql11: preliminary JIT support
Browse files Browse the repository at this point in the history
This adds preliminary support for JIT'ing SQL queries via LLVM to
PostgreSQL, enabled on versions 11+, on Linux. The default stdenv of
PostgreSQL itself and all exposed sub-packages are overridden to use a
particular major version of llvmPackages.stdenv so that 'clang' is
chosen as the default compiler. Currently, we use llvmPackages_6. To do
this, we expose another component from postgresqlXXPackages -- a new
.stdenv attribute, which exposes which stdenv PostgreSQL was built with.

PostgreSQL JIT support works by compiling all of the source code for the
system into LLVM bitcode, and shipping this as part of the binary
distribution (under the .lib output, in our case, $lib/lib/bitcode/). At
runtime, Postgres uses the LLVM API in order to load this bitcode and
JIT queries directly against the source code. This allows inlining
database code into queries, in particular inlining operator and
expression definitions for custom types, in any extensions. This feature
is enabled via the '--with-llvm' flag during configurePhase.

This feature is integrated with 'PGXS', the Makefile infrastructure for
writing and distributing Postgres extensions. If an extension is being
compiled against a version of PostgreSQL that has LLVM JIT support, then
the extension code is *also* compiled to bitcode and distributed
transparently in the binary output, alongside the extension shared
object. In order to ensure consistent bitcode is emitted, when Postgres
is compiled with LLVM support, it *must* be compiled with Clang (hence
the stdenv choice), and it also *must* embed the copy/path of Clang into
the resulting binaries, so PGXS can use the exact same compiler later on
during 3rd party extension builds. This design decision is likely
because on systems such as Debian, multiple versions of Clang can exist,
so any compiled Postgres code/extensions must use a consistent compiler
for all future builds.

However, this decision has extremely negative consequences for Nix-based
packages, because it inserts LLVM and Clang into the closure of the
PostgreSQL derivations as a hard runtime-dependency. This bloats the
closure size by over a gigabyte (~140MB -> 1.4GB), which is fairly
unwieldly and unlikely to be permissible by default. Currently this
bloat only applies to the .out (binary) outputs.

But this is made worse by the fact that the .lib output is also bloated
by having a hard runtime dependency on llvmPackages.llvm.lib. This is
because postgresql.lib now ships libllvmjit.so which talks to
libLLVM.so, but postgresql.lib also contains client libraries like
libpq.so. This effectively bloats every libpq client expression as well
by about 200MB.

Finally, because of the way PGXS's default installation logic works, it
wants to install binary artifacts into the postgresql lib/ directory,
which obviously isn't possible in the Nix store as it's read-only.
Hence, we create environments composed of all extensions outputs and
patch postgresql to load that. But this means the installPhase for every
extension is currently a custom hand-written script, and *that* means
every extension must now contain logic to install LLVM .bc files on top
of .sql and .so files.

Instead, we should probably patch PGXS to install to a proper external
directory so its install logic can take over and we can remove custom
installPhase scripts for most extensions. Postgres' LLVM support logic
in its configure script and PGXS code will need to be patched to remove
hard-coded references to clang-wrapper, since we always control the
exact version of clang used and can remove it as a run-time dependency.
Finally, bitcode should probably be moved to separate .bitcode
derivations for all server versions and extension outputs, so that libpq
clients aren't bloated by indirect dependencies on libLLVM.so (by way of
libllvmjit.so).

Oh, and PostGIS fails to build with JIT support/clang as the compiler,
for some reason.

As a result of these significant complications, this support is disabled
by default, and should only be considered supported for vanilla
PostgreSQL with no third-party extensions.

Darwin may also be supported in the future; it may even build, but can't
be tested.

Signed-off-by: Austin Seipp <[email protected]>
  • Loading branch information
thoughtpolice authored and basvandijk committed Sep 9, 2018
1 parent f30de35 commit dcd9455
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 7 deletions.
31 changes: 26 additions & 5 deletions pkgs/servers/sql/postgresql/default.nix
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
{ stdenv, lib, fetchurl, makeWrapper
, glibc, zlib, readline, libossp_uuid, openssl, libxml2, tzdata, systemd
}:

# Gate JIT support right now behind a flag; it increases closure size
# dramatically due to the PostgreSQL build system requiring a hard dependency
# on clang-wrapper (~140MB -> 1.4GB). This must be worked around before it can
# be enabled by default by making clang-wrapper a build-time only dependency.
, llvmPackages, enableJitSupport ? false
}@deps:

let

common = { version, sha256, psqlSchema }:
let atLeast = lib.versionAtLeast version; in stdenv.mkDerivation (rec {
let
atLeast = lib.versionAtLeast version;

# JIT is only supported on Linux, for now. (Darwin may build, but must be
# tested).
jitEnabled = atLeast "11" && enableJitSupport && deps.stdenv.isLinux;

# Note: use deps.stdenv, not just 'stdenv', otherwise infinite recursion
# will occur due to lexical scoping rules.
stdenv = if jitEnabled then llvmPackages.stdenv else deps.stdenv;
in stdenv.mkDerivation (rec {
name = "postgresql-${version}";
inherit version;

Expand All @@ -20,7 +36,8 @@ let
buildInputs =
[ zlib readline openssl libxml2 makeWrapper ]
++ lib.optionals (!stdenv.isDarwin) [ libossp_uuid ]
++ lib.optionals (atLeast "9.6" && !stdenv.isDarwin) [ systemd ];
++ lib.optionals (atLeast "9.6" && !stdenv.isDarwin) [ systemd ]
++ lib.optionals jitEnabled (with llvmPackages; [ clang llvm ]);

enableParallelBuilding = true;

Expand All @@ -39,6 +56,7 @@ let
"--with-system-tzdata=${tzdata}/share/zoneinfo"
(lib.optionalString (atLeast "9.6" && !stdenv.isDarwin) "--with-systemd")
(if stdenv.isDarwin then "--with-uuid=e2fs" else "--with-ossp-uuid")
(lib.optionalString jitEnabled "--with-llvm")
];

patches =
Expand Down Expand Up @@ -87,11 +105,14 @@ let

doInstallCheck = false; # needs a running daemon?

disallowedReferences = [ stdenv.cc ];
disallowedReferences = lib.optionals (!jitEnabled) [ stdenv.cc ];

passthru = {
inherit readline psqlSchema;
# Note: we export 'stdenv', because the chosen stdenv *might* be a llvmPackages-based
# one, and we want to propagate that to all extensions.
inherit readline psqlSchema stdenv;
compareVersion = builtins.compareVersions version;
hasJitSupport = jitEnabled;
};

meta = with lib; {
Expand Down
4 changes: 4 additions & 0 deletions pkgs/servers/sql/postgresql/ext/postgis.nix
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ in stdenv.mkDerivation rec {
"raster/scripts/python/Makefile";
'';

passthru = {
versionCheck = postgresql.hasJitSupport == false;
};

meta = with stdenv.lib; {
description = "Geographic Objects for PostgreSQL";
homepage = http://postgis.refractions.net;
Expand Down
6 changes: 4 additions & 2 deletions pkgs/servers/sql/postgresql/packages.nix
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{ pkgs, lib }:

let
postgresqlPackages = pkgs.callPackages ./default.nix {};
llvmPackages = pkgs.llvmPackages_6;
postgresqlPackages = pkgs.callPackages ./default.nix { inherit llvmPackages; };

# Filter out any versions which fail a version check.
filterPackages = lib.filterAttrs (_: drv: drv.versionCheck or true);

makePackageSet = postgresql:
let
callPackage = p: args: pkgs.callPackage p (args // { inherit postgresql; });
stdenv = postgresql.stdenv; # Use the stdenv for the particular version of Postgres
callPackage = p: args: pkgs.callPackage p (args // { inherit postgresql stdenv; });
in
filterPackages {
# Convenience function for end-users to easily build packages against a specific
Expand Down

0 comments on commit dcd9455

Please sign in to comment.