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") 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