From 4562bbb1d23757e15c189bcc62d82ee245554abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Tue, 13 Jan 2026 09:38:38 +0100 Subject: [PATCH] =?UTF-8?q?transformations:=20Add=20=E2=80=98--amd-gpu?= =?UTF-8?q?=E2=80=99=20transformation=20option.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/transformations.scm (split-on-commas): New procedure, moved from… (transform-package-toolchain): … here. (package-amd-gpu-specialization, transform-package-amd-gpu-targets): New procedures. (%transformations, %options): Add ‘amd-gpu’. * tests/transformations.scm ("options->transformations, amd-gpu") ("options->transformations, amd-gpu, not applicable") ("options->transformations, amd-gpu, missing clang-rocm input") ("options->transformations, amd-gpu, wrong GPU"): New tests. * doc/guix.texi (Package Transformation Options): Document it. Change-Id: I56bf0dffbf12bc08cf6318fe56952473b395c303 Signed-off-by: Ludovic Courtès Merges: #5583 --- doc/guix.texi | 33 +++++++++++- guix/transformations.scm | 105 ++++++++++++++++++++++++++++++++++++-- tests/transformations.scm | 41 ++++++++++++++- 3 files changed, 173 insertions(+), 6 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index 14c3c3327d9..b08c30cb954 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -22,7 +22,7 @@ @set SUBSTITUTE-URLS https://@value{SUBSTITUTE-SERVER-1} https://@value{SUBSTITUTE-SERVER-2} @copying -Copyright @copyright{} 2012--2025 Ludovic Courtès@* +Copyright @copyright{} 2012--2026 Ludovic Courtès@* Copyright @copyright{} 2013, 2014, 2016, 2024 Andreas Enge@* Copyright @copyright{} 2013 Nikita Karetnikov@* Copyright @copyright{} 2014, 2015, 2016 Alex Kost@* @@ -13664,6 +13664,37 @@ coarse-grain counterpart of @dfn{function multi-versioning} as implemented by the GNU tool chain (@pxref{Function Multiversioning,,, gcc, Using the GNU Compiler Collection (GCC)}). +@cindex GPUs, AMD compilation targets +@cindex AMD GPUs +@cindex ROCm/HIP GPU targets +@vindex amd-gpu-targets +@anchor{amd-gpu-transformation-option} +@item --amd-gpu=@var{targets} +Build relevant packages for the AMD GPUs specified by @var{targets}. +Only packages with an @code{amd-gpu-targets} property are affected. +@var{targets} must be a comma-separated list of +@uref{https://llvm.org/docs/AMDGPUUsage.html#amdgpu-processor-table, AMD +GPU target identifiers}. For example, the command below builds the GPU +code of @code{rocm-bandwidth-test} for AMD Instinct MI250 +(@code{gfx90a}) and for AMD Instinct MI300 (@code{gfx942}): + +@example +guix build --amd-gpu=gfx90a,gfx942 rocm-bandwidth-test +@end example + +To know the identifier(s) of the GPU(s) available on your machine, run: + +@example +guix shell rocminfo -- rocm_agent_enumerator +@end example + +Under the hood, these GPU identifiers are +passed to Clang's @option{--offload-arch} option. + +When @option{--amd-gpu} is omitted, packages are built for a default set +of GPUs, that we hope covers common needs. Building for more GPUs +increases build time significantly and leads to bigger package binaries. + @item --with-source=@var{source} @itemx --with-source=@var{package}=@var{source} @itemx --with-source=@var{package}@@@var{version}=@var{source} diff --git a/guix/transformations.scm b/guix/transformations.scm index 198b55ed23c..0cad18ba6e6 100644 --- a/guix/transformations.scm +++ b/guix/transformations.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2016-2024 Ludovic Courtès +;;; Copyright © 2016-2024, 2026 Ludovic Courtès ;;; Copyright © 2021 Marius Bakke ;;; Copyright © 2023 Sarthak Shah ;;; Copyright © 2023-2025 Efraim Flashner @@ -422,15 +422,15 @@ TOOLCHAIN must be an input list." (not (memq p set)))) #:deep? #t)))) +(define split-on-commas + (cute string-tokenize <> (char-set-complement (char-set #\,)))) + (define (transform-package-toolchain replacement-specs) "Return a procedure that, when passed a package, changes its toolchain or that of its dependencies according to REPLACEMENT-SPECS. REPLACEMENT-SPECS is a list of strings like \"fftw=gcc-toolchain@10\" meaning that the package to the left of the equal sign must be built with the toolchain to the right of the equal sign." - (define split-on-commas - (cute string-tokenize <> (char-set-complement (char-set #\,)))) - (define (specification->input spec) (let ((package (specification->package spec))) (list (package-name package) package))) @@ -704,6 +704,97 @@ for MICRO-ARCHITECTURE, a string suitable for GCC's '-march'." (rewrite obj) obj)))))) +(define (package-for-amd-gpu-targets p targets) + "Return a variant of P compiled for TARGETS, a list of strings denoting AMD +GPU targets." + (package/inherit p + (properties + `((amd-gpu-targets . ,targets) + ,@(alist-delete 'amd-gpu-targets (package-properties p)))))) + +(define (assert-valid-amd-gpu-targets package targets) + "Raise an error if the AMD GPU identifiers listed in TARGETS are not known +to the compiler of PACKAGE." + (define (compiler-amd-gpu-targets package) + (assoc-ref (package-properties package) 'compiler-amd-gpu-targets)) + + (match (any (match-lambda + ((label (? package? package)) + (and (compiler-amd-gpu-targets package) + package)) + (_ #f)) + (package-direct-inputs package)) + (#f + (raise (make-compound-condition + (formatted-message + (G_ "~a: no ROCm compiler was found among the inputs") + (package-full-name package)) + (condition (&error-location + (location (package-location package))))))) + (compiler + (let ((supported (compiler-amd-gpu-targets compiler))) + ;; This is quadratic but on small lists. + (and=> (find (negate (cut member <> supported)) targets) + (lambda (unsupported) + (raise + (make-compound-condition + (formatted-message + (G_ "compiler ~a does not support AMD GPU target ~a") + (package-full-name compiler) unsupported) + (condition (&error-location + (location (package-location compiler)))) + (condition + (&fix-hint + (hint (format #f (G_ "Compiler ~a supports the following +AMD GPU targets: + +@quotation +~a +@end quotation") + (package-full-name compiler "@@") + (string-join supported ", "))))))))))))) + +(define package-amd-gpu-specialization + (mlambda (targets) + "Return a procedure that maps the given package to its counterpart built +for the given ROCm TARGETS, a list of GPU architectures." + (define rewriting-property + (gensym " package-amd-gpu-specialization")) + + (define (mark p) + ;; Mark P as already processed. + (package/inherit p + (properties `((,rewriting-property . #t) + ,@(package-properties p))))) + + (package-mapping (lambda (p) + (cond ((assq rewriting-property (package-properties p)) + p) + ((assq 'amd-gpu-targets (package-properties p)) + (assert-valid-amd-gpu-targets p targets) + (info (N_ "compiling ~a for AMD GPU~{ ~a~}~%" + "compiling ~a for these AMD GPUs:~{ ~a~}~%" + (length targets)) + (package-full-name p) targets) + (mark (package-for-amd-gpu-targets p targets))) + (else + p))) + (lambda (p) + (assq rewriting-property (package-properties p))) + #:deep? #t))) + +(define (transform-package-amd-gpu-targets targets) + "Return a procedure that, when applied to a package, returns that package +such that the package itself and all its dependencies are specialized for +TARGET-LIST, a list of strings denoting AMD GPUs." + (match targets + ((targets _ ...) + (let* ((rewrite (package-amd-gpu-specialization targets))) + (lambda (obj) + (if (package? obj) + (rewrite obj) + obj)))))) + (define (transform-package-with-debug-info specs) "Return a procedure that, when passed a package, set its 'replacement' field to the same package but with #:strip-binaries? #f in its 'arguments' field." @@ -999,6 +1090,7 @@ are replaced by the specified upstream version." (with-git-url . ,transform-package-source-git-url) (with-c-toolchain . ,transform-package-toolchain) (tune . ,transform-package-tuning) + (amd-gpu . ,transform-package-amd-gpu-targets) (with-debug-info . ,transform-package-with-debug-info) (without-tests . ,transform-package-tests) (with-configure-flag . ,transform-package-configure-flag) @@ -1085,6 +1177,11 @@ building for ~a instead of ~a, so tuning cannot be guessed~%") result) (alist-delete 'tune result)) rest))) + (option '("amd-gpu") #t #f + (lambda (opt name arg result . rest) + (apply values + (alist-cons 'amd-gpu (split-on-commas arg) result) + rest))) (option '("with-debug-info") #t #f (parser 'with-debug-info)) (option '("without-tests") #t #f diff --git a/tests/transformations.scm b/tests/transformations.scm index 9f5aacc41b4..1db54a0e196 100644 --- a/tests/transformations.scm +++ b/tests/transformations.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2016-2017, 2019-2024 Ludovic Courtès +;;; Copyright © 2016-2017, 2019-2024, 2026 Ludovic Courtès ;;; Copyright © 2021 Marius Bakke ;;; ;;; This file is part of GNU Guix. @@ -638,6 +638,45 @@ (package->bag (t p)) #f))) +(test-equal "options->transformations, amd-gpu" + '("gfx90a" "gfx942") + (let ((p (dummy-package "amd-gpu-code" + (native-inputs + (list (@ (gnu packages llvm) clang-rocm))) + (properties '((amd-gpu-targets . ("whatever")))))) + (t (options->transformation '((amd-gpu . ("gfx90a" "gfx942")))))) + (assoc-ref (package-properties (t p)) 'amd-gpu-targets))) + +(test-equal "options->transformations, amd-gpu, not applicable" + #f + (let ((p (dummy-package "not-amd-gpu-code")) + (t (options->transformation '((amd-gpu . ("gfx90a" "gfx942")))))) + (assoc-ref (package-properties (t p)) 'amd-gpu-targets))) + +(test-assert "options->transformations, amd-gpu, missing clang-rocm input" + (let ((p (dummy-package "amd-gpu-code" + (properties '((amd-gpu-targets . ("whatever")))))) + (t (options->transformation '((amd-gpu . ("generic")))))) + ;; Since 'clang-rocm' is not among the inputs, an error should be raised. + (guard (c ((formatted-message? c) + (string-contains (formatted-message-string c) + "no ROCm compiler"))) + (t p) + #f))) + +(test-assert "options->transformations, amd-gpu, wrong GPU" + (let ((p (dummy-package "amd-gpu-code" + (native-inputs + (list (@ (gnu packages llvm) clang-rocm))) + (properties '((amd-gpu-targets . ("whatever")))))) + (t (options->transformation '((amd-gpu . ("does-not-exist")))))) + ;; Since this AMD GPU target is not known to 'clang-rocm', an error should + ;; be raised. + (guard (c ((formatted-message? c) + (member "does-not-exist" (formatted-message-arguments c)))) + (t p) + #f))) + (test-equal "options->transformation + package->manifest-entry" '((transformations . ((without-tests . "foo")))) (let* ((p (dummy-package "foo"))