From eb45c0935649a1a8784c6e1de58de4486ebe7548 Mon Sep 17 00:00:00 2001 From: Simeon David Schaub Date: Sun, 30 Nov 2025 13:41:24 +0100 Subject: [PATCH 1/2] [ROCm] introduce HSARuntime_jll My eventual goal here is to ship the entire ROCm stack repackaged from ROCm nightlies. The HSA runtime is needed to determine the ROCm platform we should ship artifacts for. The next step would be to introduce a `rocm_sdk_core_jll` that uses platform augmentation based on this jll to select the right artifact, which I already have a proof of concept for locally. --- R/ROCm/HSARuntime/build_tarballs.jl | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 R/ROCm/HSARuntime/build_tarballs.jl diff --git a/R/ROCm/HSARuntime/build_tarballs.jl b/R/ROCm/HSARuntime/build_tarballs.jl new file mode 100644 index 00000000000..ac196c69901 --- /dev/null +++ b/R/ROCm/HSARuntime/build_tarballs.jl @@ -0,0 +1,47 @@ +using BinaryBuilder, Pkg + +name = "HSARuntime" +version = v"7.0.01120251130" + +sources = [ + FileSource("https://rocm.nightlies.amd.com/v2/gfx1150/rocm_sdk_core-7.11.0a20251130-py3-none-linux_x86_64.whl", + "01250b8baa92d45f0af2a32456db8e2d6d42f575afb781ef1b8fee47fe644ed2"), + FileSource("https://raw.githubusercontent.com/ROCm/rocm-systems/refs/heads/develop/projects/rocr-runtime/LICENSE.txt", + "ffa5a77ce21419e276bd9068faec94333128e49e1c95426d9c1d35435e8fe835"), +] + +script = raw""" +cd ${WORKSPACE}/srcdir + +unzip rocm_sdk_core-*.whl + +# Extract the specific libraries +install -Dvm 755 _rocm_sdk_core/lib/libhsa-runtime64.so.1 ${libdir}/libhsa-runtime64.so.1 +install -Dvm 755 _rocm_sdk_core/lib/librocprofiler-register.so.0 ${libdir}/librocprofiler-register.so.0 + +# Copy the rocm_sysdeps folder +cp -rv _rocm_sdk_core/lib/rocm_sysdeps ${libdir}/ + +install_license LICENSE.txt + +# Create soname symlinks +cd ${libdir} +ln -s libhsa-runtime64.so.1 libhsa-runtime64.so +ln -s librocprofiler-register.so.0 librocprofiler-register.so +""" + +# ROCm only supports x86_64 Linux with glibc +platforms = [ + Platform("x86_64", "linux"; libc="glibc", cxxstring_abi="cxx11"), +] + +products = [ + LibraryProduct("libhsa-runtime64", :libhsa_runtime64), +] + +dependencies = [ + Dependency(PackageSpec(name="CompilerSupportLibraries_jll", uuid="e66e0078-7015-5450-92f7-15fbd957f2ae")) +] + +build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; + julia_compat="1.6") From 2a4676bd54aae871f8d1f4fc046149ce2c58914c Mon Sep 17 00:00:00 2001 From: Simeon David Schaub Date: Sun, 30 Nov 2025 13:53:41 +0100 Subject: [PATCH 2/2] [ROCm] create rocm_sdk_core_jll and introduce a platform augmentation mechanism for the ROCm platform. Ref #12672 --- R/ROCm/rocm_sdk_core/build_tarballs.jl | 79 +++++++++ R/ROCm/rocm_sdk_core/platform_augmentation.jl | 164 ++++++++++++++++++ platforms/rocm.jl | 115 ++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 R/ROCm/rocm_sdk_core/build_tarballs.jl create mode 100644 R/ROCm/rocm_sdk_core/platform_augmentation.jl create mode 100644 platforms/rocm.jl diff --git a/R/ROCm/rocm_sdk_core/build_tarballs.jl b/R/ROCm/rocm_sdk_core/build_tarballs.jl new file mode 100644 index 00000000000..676d8e42c3a --- /dev/null +++ b/R/ROCm/rocm_sdk_core/build_tarballs.jl @@ -0,0 +1,79 @@ +using BinaryBuilder, Pkg + +const YGGDRASIL_DIR = "../../.." +include(joinpath(YGGDRASIL_DIR, "fancy_toys.jl")) +include(joinpath(YGGDRASIL_DIR, "platforms", "rocm.jl")) + +name = "rocm_sdk_core" +build_version = "7.11.0a20251130" +version = v"7.0.01120251130" + +augment_platform_block = read(joinpath(@__DIR__, "platform_augmentation.jl"), String) + +script = raw""" +cd ${WORKSPACE}/srcdir + +unzip rocm_sdk_core-*.whl + +# Copy the rocm_sysdeps folder +cp -rv _rocm_sdk_core/* ${prefix}/ + +install_license LICENSE.md +""" + +products = [ + ExecutableProduct("ld.lld", :lld, "lib/llvm/bin"), + LibraryProduct("libamdhip64", :libhip), + FileProduct("lib/llvm/amdgcn/bitcode", :amdgcn_bitcode_dir) +] + +dependencies = [ + Dependency(PackageSpec(name="CompilerSupportLibraries_jll", uuid="e66e0078-7015-5450-92f7-15fbd957f2ae")) + RuntimeDependency(PackageSpec(name="HSARuntime_jll", uuid="0a197bc1-b33e-53f1-a9ca-cd02b99357ac"); compat = "7") +] + + +# determine exactly which tarballs we should build +builds = [] +for augmented_platform in ROCm.supported_platforms() + should_build_platform(triplet(augmented_platform)) || continue + + p = augmented_platform["rocm_platform"] + sha256sum, build = Dict( + "gfx101x_dgpu" => ("4a1903f4afece374b008d376825a81b9d0d5901844c78db0dce82c17c0c66f8f", build_version), + "gfx103x_dgpu" => ("dd4e9eceb3bc93b4f235e27d2572bedae470e32f03609487129fba14f6d512b2", build_version), + "gfx110x_all" => ("45327fb6874797c104275617541e6cce9b706159a962f17b410e06d9c4f66008", build_version), + #"gfx110x_dgpu" => ("b0d27556dd07d30345624eb487ca2c7cf40060ec5f94ba6e3d788c2fead4b345", build_version), + "gfx1150" => ("01250b8baa92d45f0af2a32456db8e2d6d42f575afb781ef1b8fee47fe644ed2", build_version), + "gfx1151" => ("565b7e96e04b3f0cdd743eef5e498f697ee407c70c9a0b3702f10d3d0dcb6fc5", build_version), + "gfx120x_all" => ("bbeb58b80951aa0ba4c5df8ce49fc6a493012ecc49910574175fd84c948b1eb2", build_version), + "gfx90x_dcgpu" => ("1a1ae75beabba18d5a7d94942f128801ba2448a0e4cdc74da5d9c4b26789bdbe", build_version), + "gfx94x_dcgpu" => ("f18fda3295a8e6aa54f2d04b7dcb4631c0c7a2aac57fc774fbacf32f6071bbe0", build_version), + "gfx950_dcgpu" => ("ff4aade1cafb8359fd6c2b39fa691f68f14bdf06557e2e5d3c61ef8bea2190e8", "7.11.0a20251129"), + )[p] + p = replace(p, "x_" => "X-", "_" => "-") + sources = [ + FileSource("https://rocm.nightlies.amd.com/v2/$p/rocm_sdk_core-$build-py3-none-linux_x86_64.whl", + sha256sum), + FileSource("https://raw.githubusercontent.com/ROCm/rocm-systems/fd61b0f5073a6c4c3b6693532d3cfb8972b1951f/projects/hip/LICENSE.md", + "b185aaa652b0bf066c37a0d6314ce4bf4521e4a3c9bf46edd2f6a777ac522223"), + ] + + push!(builds, + (; platforms=[augmented_platform], sources) + ) +end + +# don't allow `build_tarballs` to override platform selection based on ARGS. +# we handle that ourselves by calling `should_build_platform` +non_platform_ARGS = filter(arg -> startswith(arg, "--"), ARGS) + +# `--register` should only be passed to the latest `build_tarballs` invocation +non_reg_ARGS = filter(arg -> arg != "--register", non_platform_ARGS) + +for (i,build) in enumerate(builds) + build_tarballs(i == lastindex(builds) ? non_platform_ARGS : non_reg_ARGS, + name, version, build.sources, script, + build.platforms, products, dependencies; + skip_audit = true, julia_compat="1.6", lazy_artifacts=true, augment_platform_block) +end diff --git a/R/ROCm/rocm_sdk_core/platform_augmentation.jl b/R/ROCm/rocm_sdk_core/platform_augmentation.jl new file mode 100644 index 00000000000..828d3d701f5 --- /dev/null +++ b/R/ROCm/rocm_sdk_core/platform_augmentation.jl @@ -0,0 +1,164 @@ +using Base.BinaryPlatforms + +const rocm_sdk_core_jll_uuid = Base.UUID("9ab9228b-5f62-5ec0-95ae-72487824505f") +const preferences = Base.get_preferences(rocm_sdk_core_jll_uuid) +Base.record_compiletime_preference(rocm_sdk_core_jll_uuid, "local") + +const local_preference = if haskey(preferences, "local") + if isa(preferences["local"], Bool) + preferences["local"] + elseif isa(preferences["local"], String) + use_local = tryparse(Bool, preferences["local"]) + if use_local === nothing + @error "ROCm local preference is not valid; expected a boolean, but got '$(preferences["local"])'" + missing + else + use_local + end + else + @error "ROCm local preference is not valid; expected a boolean, but got '$(preferences["local"])'" + missing + end +else + missing +end + +try + using HSARuntime_jll +catch + # during initial package installation, HSARuntime_jll may not be available. + # in that case, we just won't select an artifact. +end + +struct hsa_agent_t + handle::UInt64 +end + +const HSA_AGENT_INFO_NAME::Cint = 0 + +@enum hsa_status_t::Cint begin + HSA_STATUS_SUCCESS = 0x0 + HSA_STATUS_INFO_BREAK = 0x1 + + HSA_STATUS_ERROR = 0x1000 + HSA_STATUS_ERROR_INVALID_ARGUMENT = 0x1001 + HSA_STATUS_ERROR_INVALID_QUEUE_CREATION = 0x1002 + HSA_STATUS_ERROR_INVALID_ALLOCATION = 0x1003 + HSA_STATUS_ERROR_INVALID_AGENT = 0x1004 + HSA_STATUS_ERROR_INVALID_REGION = 0x1005 + HSA_STATUS_ERROR_INVALID_SIGNAL = 0x1006 + HSA_STATUS_ERROR_INVALID_QUEUE = 0x1007 + HSA_STATUS_ERROR_OUT_OF_RESOURCES = 0x1008 + HSA_STATUS_ERROR_INVALID_PACKET_FORMAT = 0x1009 + HSA_STATUS_ERROR_RESOURCE_FREE = 0x100A + HSA_STATUS_ERROR_NOT_INITIALIZED = 0x100B + HSA_STATUS_ERROR_REFCOUNT_OVERFLOW = 0x100C + HSA_STATUS_ERROR_INCOMPATIBLE_ARGUMENTS = 0x100D + HSA_STATUS_ERROR_INVALID_INDEX = 0x100E + HSA_STATUS_ERROR_INVALID_ISA = 0x100F + + HSA_STATUS_ERROR_INVALID_CODE_OBJECT = 0x1010 + HSA_STATUS_ERROR_INVALID_EXECUTABLE = 0x1011 + HSA_STATUS_ERROR_FROZEN_EXECUTABLE = 0x1012 + HSA_STATUS_ERROR_INVALID_SYMBOL_NAME = 0x1013 + HSA_STATUS_ERROR_VARIABLE_ALREADY_DEFINED = 0x1014 + HSA_STATUS_ERROR_VARIABLE_UNDEFINED = 0x1015 + HSA_STATUS_ERROR_EXCEPTION = 0x1016 + HSA_STATUS_ERROR_INVALID_ISA_NAME = 0x1017 + HSA_STATUS_ERROR_INVALID_CODE_SYMBOL = 0x1018 + HSA_STATUS_ERROR_INVALID_EXECUTABLE_SYMBOL = 0x1019 + + HSA_STATUS_ERROR_INVALID_FILE = 0x1020 + HSA_STATUS_ERROR_INVALID_CODE_OBJECT_READER = 0x1021 + HSA_STATUS_ERROR_INVALID_CACHE = 0x1022 + HSA_STATUS_ERROR_INVALID_WAVEFRONT = 0x1023 + HSA_STATUS_ERROR_INVALID_SIGNAL_GROUP = 0x1024 + HSA_STATUS_ERROR_INVALID_RUNTIME_STATE = 0x1025 + HSA_STATUS_ERROR_FATAL = 0x1026 +end + +function callback(agent::hsa_agent_t, data::Ptr{Vector{String}}) + a = Base.unsafe_pointer_to_objref(data) + _name = zeros(Cchar, 64) + status = @ccall libhsa_runtime64.hsa_agent_get_info(agent::hsa_agent_t, HSA_AGENT_INFO_NAME::Cint, _name::Ptr{Cchar})::hsa_status_t + if status == HSA_STATUS_SUCCESS + GC.@preserve _name push!(a, Base.unsafe_string(pointer(_name))) + end + return status +end + +function agent_names() + r = Ref(String[]) + ptr = Base.unsafe_convert(Ptr{Vector{String}}, r) + cb = @cfunction(callback, hsa_status_t, (hsa_agent_t, Ptr{Vector{String}})) + status = @ccall libhsa_runtime64.hsa_init()::hsa_status_t + status != HSA_STATUS_SUCCESS && error(status) + status = @ccall libhsa_runtime64.hsa_iterate_agents(cb::Ptr{Cvoid}, ptr::Ptr{Vector{String}})::hsa_status_t + status != HSA_STATUS_SUCCESS && error(status) + status = @ccall libhsa_runtime64.hsa_shut_down()::hsa_status_t + status != HSA_STATUS_SUCCESS && error(status) + return r[] +end + +function name_to_platform(name::String) + if startswith(name, "gfx101") + return "gfx101x_dgpu" + elseif startswith(name, "gfx103") + return "gfx103x_dgpu" + elseif startswith(name, "gfx110") + return "gfx110x_all" + elseif name == "gfx1150" + return "gfx1150" + elseif name == "gfx1151" + return "gfx1151" + elseif startswith(name, "gfx120") + return "gfx120x_all" + elseif startswith(name, "gfx90") + return "gfx90x_dcgpu" + elseif startswith(name, "gfx94") + return "gfx94x_dcgpu" + elseif startswith(name, "gfx950") + return "gfx950_dcgpu" + else + return nothing + end +end + +function detect_rocm_platform() + names = try + agent_names() + catch e + @warn "Failed to detect ROCm platform: $e" + String[] + end + filter!(startswith("gfx"), names) + + if isempty(names) + @warn "No ROCm GPU agents detected on this system." + return "none" + end + + platforms = unique!(filter(!isnothing, map(name_to_platform, names))) + if isempty(platforms) + @warn "Unrecognized ROCm GPU agents detected on this system: $(join(names, ", "))." + return "none" + elseif length(platforms) > 1 + @warn "Multiple supported ROCm platforms detected on this system: $(join(platforms, ", ")). Using the first one. Override by setting the `rocm_platform` preference." + end + + return first(platforms) +end + +function augment_platform!(platform::Platform) + # Only augment Linux x86_64 platforms + if Sys.islinux() && arch(platform) == "x86_64" + if !haskey(platform, "rocm_platform") + platform["rocm_platform"] = detect_rocm_platform() + end + + # Store the fact that we're using a local ROCm installation + platform["rocm_local"] = string(local_preference !== missing && local_preference) + end + + return platform +end diff --git a/platforms/rocm.jl b/platforms/rocm.jl new file mode 100644 index 00000000000..78f0152fcd3 --- /dev/null +++ b/platforms/rocm.jl @@ -0,0 +1,115 @@ +module ROCm + +using Pkg + +using BinaryBuilder + +using Base.BinaryPlatforms +using Base.BinaryPlatforms: arch, os, tags + +# the "rocm_platform" platform tag contains the GPU architecture (e.g., "gfx103X-dgpu") +# detected by querying the HSA runtime, and is used to select artifacts that depend on ROCm. + +const augment = """ + using Base.BinaryPlatforms + + try + using rocm_sdk_core_jll + catch + # during initial package installation, rocm_sdk_core_jll may not be available. + # in that case, we just won't select an artifact. + end + + # can't use Preferences for the same reason + const rocm_sdk_core_jll_uuid = Base.UUID("9ab9228b-5f62-5ec0-95ae-72487824505f") + const preferences = Base.get_preferences(rocm_sdk_core_jll_uuid) + Base.record_compiletime_preference(rocm_sdk_core_jll_uuid, "local") + const local_toolkit = something(tryparse(Bool, get(preferences, "local", "false")), false) + + function rocm_comparison_strategy(a::String, b::String, a_requested::Bool, b_requested::Bool) + # if we're using a local toolkit, we can't use artifacts + if local_toolkit + return false + end + return a == b + end + + function augment_platform!(platform::Platform) + if !@isdefined(rocm_sdk_core_jll) + # don't set to nothing or Pkg will download any artifact + platform["rocm_platform"] = "none" + end + + if !haskey(platform, "rocm_platform") + rocm_sdk_core_jll.augment_platform!(platform) + end + BinaryPlatforms.set_compare_strategy!(platform, "rocm_platform", rocm_comparison_strategy) + + return platform + end""" + +# Known ROCm GPU architectures +const rocm_platforms = [ + "gfx101x_dgpu", + "gfx103x_dgpu", + "gfx110x_all", + #"gfx110x_dgpu", + "gfx1150", + "gfx1151", + "gfx120x_all", + "gfx90x_dcgpu", + "gfx94x_dcgpu", + "gfx950_dcgpu", +] + +""" + supported_platforms(; platforms=rocm_platforms) + +Return a list of supported platforms to build ROCm artifacts for. + +# Arguments +- `platforms=rocm_platforms`: List of ROCm GPU architectures to target. +""" +function supported_platforms(; platforms=rocm_platforms) + base_platforms = [ + Platform("x86_64", "linux"; libc = "glibc", cxxstring_abi = "cxx11"), + ] + + # augment with ROCm platforms + result = Platform[] + for base_platform in base_platforms + for rocm_platform in platforms + platform = deepcopy(base_platform) + platform["rocm_platform"] = rocm_platform + push!(result, platform) + end + end + + return result +end + +""" + is_supported(platform) + +Check if a platform is supported by ROCm, and whether we can build artifacts for it. +""" +function is_supported(platform) + return Sys.islinux(platform) && arch(platform) == "x86_64" +end + +""" + required_dependencies(platform) + +Return a list of dependencies required to build and use ROCm artifacts for a given platform. +""" +function required_dependencies(platform) + if !haskey(tags(platform), "rocm_platform") || tags(platform)["rocm_platform"] == "none" + return BinaryBuilder.AbstractDependency[] + end + + return BinaryBuilder.AbstractDependency[ + RuntimeDependency(PackageSpec(name="rocm_sdk_core_jll")) + ] +end + +end