Archived
1
0
Fork 0

derivations: Add 'substitution-oracle' and use it.

This makes 'guix environment PACKAGE' significantly faster when
substitutes are enabled.  Before that, it would lead to many invocations
of 'guix substitute-binary', one per 'derivation-prerequisites-to-build'
call.  Now, all these are replaced by a single invocation.

* guix/derivations.scm (derivation-output-paths, substitution-oracle):
  New procedures.
  (derivation-prerequisites-to-build): Replace #:use-substitutes? with
  #:substitutable?.  Remove the local 'derivation-output-paths' and
  'substitutable?'.
* guix/ui.scm (show-what-to-build): Add 'substitutable?'.  Pass it to
  'derivation-prerequisites-to-build'.
  [built-or-substitutable?]: Use it instead of 'has-substitutes?'.
* tests/derivations.scm ("derivation-prerequisites-to-build and
  substitutes"): Use #:substitutable? instead of #:use-substitutes?.
This commit is contained in:
Ludovic Courtès 2015-01-10 00:39:59 +01:00
parent 0b6af195fe
commit e9651e39b3
3 changed files with 52 additions and 31 deletions

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -62,6 +62,7 @@
fixed-output-derivation? fixed-output-derivation?
offloadable-derivation? offloadable-derivation?
substitutable-derivation? substitutable-derivation?
substitution-oracle
derivation-hash derivation-hash
read-derivation read-derivation
@ -184,39 +185,52 @@ download with a fixed hash (aka. `fetchurl')."
;; synonymous, see <http://bugs.gnu.org/18747>. ;; synonymous, see <http://bugs.gnu.org/18747>.
offloadable-derivation?) offloadable-derivation?)
(define (derivation-output-paths drv sub-drvs)
"Return the output paths of outputs SUB-DRVS of DRV."
(match drv
(($ <derivation> outputs)
(map (lambda (sub-drv)
(derivation-output-path (assoc-ref outputs sub-drv)))
sub-drvs))))
(define* (substitution-oracle store drv)
"Return a one-argument procedure that, when passed a store file name,
returns #t if it's substitutable and #f otherwise. The returned procedure
knows about all substitutes for all the derivations listed in DRV and their
prerequisites.
Creating a single oracle (thus making a single 'substitutable-paths' call) and
reusing it is much more efficient than calling 'has-substitutes?' or similar
repeatedly, because it avoids the costs associated with launching the
substituter many times."
(let* ((paths (delete-duplicates
(fold (lambda (drv result)
(let ((self (match (derivation->output-paths drv)
(((names . paths) ...)
paths)))
(deps (append-map derivation-input-output-paths
(derivation-prerequisites
drv))))
(append self deps result)))
'()
drv)))
(subst (substitutable-paths store paths)))
(cut member <> subst)))
(define* (derivation-prerequisites-to-build store drv (define* (derivation-prerequisites-to-build store drv
#:key #:key
(outputs (outputs
(derivation-output-names drv)) (derivation-output-names drv))
(use-substitutes? #t)) (substitutable?
(substitution-oracle store
(list drv))))
"Return two values: the list of derivation-inputs required to build the "Return two values: the list of derivation-inputs required to build the
OUTPUTS of DRV and not already available in STORE, recursively, and the list OUTPUTS of DRV and not already available in STORE, recursively, and the list
of required store paths that can be substituted. When USE-SUBSTITUTES? is #f, of required store paths that can be substituted. SUBSTITUTABLE? must be a
that second value is the empty list." one-argument procedure similar to that returned by 'substitution-oracle'."
(define (derivation-output-paths drv sub-drvs)
(match drv
(($ <derivation> outputs)
(map (lambda (sub-drv)
(derivation-output-path (assoc-ref outputs sub-drv)))
sub-drvs))))
(define built? (define built?
(cut valid-path? store <>)) (cut valid-path? store <>))
(define substitutable?
;; Return true if the given path is substitutable. Call
;; `substitutable-paths' upfront, to benefit from parallelism in the
;; substituter.
(if use-substitutes?
(let ((s (substitutable-paths store
(append
(derivation-output-paths drv outputs)
(append-map
derivation-input-output-paths
(derivation-prerequisites drv))))))
(cut member <> s))
(const #f)))
(define input-built? (define input-built?
(compose (cut any built? <>) derivation-input-output-paths)) (compose (cut any built? <>) derivation-input-output-paths))

View file

@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU ;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012, 2013, 2014 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2013 Mark H Weaver <mhw@netris.org> ;;; Copyright © 2013 Mark H Weaver <mhw@netris.org>
;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org> ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2014 Alex Kost <alezost@gmail.com> ;;; Copyright © 2014 Alex Kost <alezost@gmail.com>
@ -299,21 +299,27 @@ error."
derivations listed in DRV. Return #t if there's something to build, #f derivations listed in DRV. Return #t if there's something to build, #f
otherwise. When USE-SUBSTITUTES?, check and report what is prerequisites are otherwise. When USE-SUBSTITUTES?, check and report what is prerequisites are
available for download." available for download."
(define substitutable?
;; Call 'substitutation-oracle' upfront so we don't end up launching the
;; substituter many times. This makes a big difference, especially when
;; DRV is a long list as is the case with 'guix environment'.
(if use-substitutes?
(substitution-oracle store drv)
(const #f)))
(define (built-or-substitutable? drv) (define (built-or-substitutable? drv)
(let ((out (derivation->output-path drv))) (let ((out (derivation->output-path drv)))
;; If DRV has zero outputs, OUT is #f. ;; If DRV has zero outputs, OUT is #f.
(or (not out) (or (not out)
(or (valid-path? store out) (or (valid-path? store out)
(and use-substitutes? (substitutable? out)))))
(has-substitutes? store out))))))
(let*-values (((build download) (let*-values (((build download)
(fold2 (lambda (drv build download) (fold2 (lambda (drv build download)
(let-values (((b d) (let-values (((b d)
(derivation-prerequisites-to-build (derivation-prerequisites-to-build
store drv store drv
#:use-substitutes? #:substitutable? substitutable?)))
use-substitutes?)))
(values (append b build) (values (append b build)
(append d download)))) (append d download))))
'() '() '() '()

View file

@ -589,7 +589,8 @@
(derivation-prerequisites-to-build store drv)) (derivation-prerequisites-to-build store drv))
((build* download*) ((build* download*)
(derivation-prerequisites-to-build store drv (derivation-prerequisites-to-build store drv
#:use-substitutes? #f))) #:substitutable?
(const #f))))
(and (null? build) (and (null? build)
(equal? download (list output)) (equal? download (list output))
(null? download*) (null? download*)