Jachin Shen
Jachin Shen

Categories

Tags

背景

之前将NixOS的ROCm版本更新到了6.2.2,更新完之后发现6.3.1版本已经发布,NixOS 也更新到了24.11版本,因此打算在新版 NixOS 上继续更新到最新版本。大部分组件都可以很简单地更新,只需要更新源码包重新编译即可,本文主要记录比较复杂的更新问题。

NixOS 24.11 更新

NixOS 更新到 24.11 版本后,主要变化在于标准编译环境 stdenv 升级到了 GCC14,同时 cc-wrapper 也有一些改变。

cc-wrapper

在这个 Commit 7047ba9 中,对于使用 clang 的编译环境会增加 -nostdlibinc 参数,这是为了解决其他 issue 中提到的问题,但是在这里会导致 ROCm 编译环境无法使用 gcc 的 libstdc++,因此需要暂时关闭这个参数。(后续补充:在 Commit 7d27fd2 中修复了这个问题。)

stdenv

使用 GCC14 编译 LLVM 没有问题,但是基于 GCC14 构建编译环境会出现找不到头文件的问题,猜测应该是一些路径上的问题,因为使用 clang -v 可以看到很多 GCC14 的头文件路径因为不存在被忽略了。目前还没有详细检查,暂时使用 GCC13 编译环境。

基础环境 CLR

之前在更新 ROCm 6.2.2 的时候,主要问题就在 CLR 中对于 magic number 的检查。原本以为在新版中这个问题应该已经修复了,但是只修复了一半,hip_code_object.cpp#L531:

// This will be moved to COMGR eventually
hipError_t CodeObject::extractCodeObjectFromFatBinary(
    const void* data, const std::vector<std::string>& agent_triple_target_ids,
    std::vector<std::pair<const void*, size_t>>& code_objs) {
  std::string magic((const char*)data, kOffloadBundleUncompressedMagicStrSize);
  if (magic.compare(kOffloadBundleUncompressedMagicStr)) {
    return hipErrorInvalidKernelFile;
  }

  // ......
}

这里比较时依然没有考虑字符串结尾的 \0。参考最新版本,修改成了:

// This will be moved to COMGR eventually
hipError_t CodeObject::extractCodeObjectFromFatBinary(
    const void* data, const std::vector<std::string>& agent_triple_target_ids,
    std::vector<std::pair<const void*, size_t>>& code_objs) {
    bool isCompressed = false;
    if (!IsClangOffloadMagicBundle(data, isCompressed) || isCompressed) {
        LogPrintfInfo("IsClangOffloadMagicBundle(%s) return false or isCompressed is true", (const char*)data);
        return hipErrorInvalidKernelFile;
    }

    // ......
}

后续测试 onnxruntime 时,出现了 segment fault 。增加 AMD_LOG_LEVEL=5 打印调试信息后,问题出在 extractCodeObjectFromFatBinary 返回了 hipErrorInvalidKernelFile,原因是这段 fatbin 是 compressed 的,应该是因为 onnxruntime 更新后使用了新的格式,不过 extractCodeObjectFromFatBinary 没有处理 compressed 的情况,所以直接返回了 hipErrorInvalidKernelFile。那么就需要把调用 extractCodeObjectFromFatBinary 替换成支持 compressed 的 extractCodeObjectFromFatBinaryUsingComgr:

// This will be moved to COMGR eventually
hipError_t CodeObject::ExtractCodeObjectFromFile(
    amd::Os::FileDesc fdesc, size_t fsize, const void** image,
    const std::vector<std::string>& device_names,
    std::vector<std::pair<const void*, size_t>>& code_objs) {
  if (!amd::Os::isValidFileDesc(fdesc)) {
    return hipErrorFileNotFound;
  }

  // Map the file to memory, with offset 0.
  // file will be unmapped in ModuleUnload
  // const void* image = nullptr;
  if (!amd::Os::MemoryMapFileDesc(fdesc, fsize, 0, image)) {
    return hipErrorInvalidValue;
  }

  // retrieve code_objs{binary_image, binary_size} for devices
  return extractCodeObjectFromFatBinaryUsingComgr(*image, 0, device_names, code_objs);
}

// This will be moved to COMGR eventually
hipError_t CodeObject::ExtractCodeObjectFromMemory(
    const void* data, const std::vector<std::string>& device_names,
    std::vector<std::pair<const void*, size_t>>& code_objs, std::string& uri) {
  // Get the URI from memory
  if (!amd::Os::GetURIFromMemory(data, 0, uri)) {
    return hipErrorInvalidValue;
  }

  return extractCodeObjectFromFatBinaryUsingComgr(data, 0, device_names, code_objs);
}

继续测试 onnxruntime ,显示无法找到匹配 gfx1030 架构的 fatbin ,应该是新版本只支持了新的硬件架构,无奈之下回退到 ROCm 6.2.4 的 onnxruntime ,幸好接口没有变化,测试顺利通过。

amdclang

新版 ROCm 在更多库上使用 amdclang 替换 hipcc,但是旧版 NixOS 的编译配置中并没有 amdclang,ROCm 文档中也没有多少对于 amdclang 的描述,所以只能自己摸索了。最后发现 amdclang 位于 clang-tools-extra/amdllvm ,主要功能就是指向具体的 clang。由于 NixOS 下对于 cc 的包装比较麻烦,暂时停留在 hipcc,把相关库中对于 amdclang 的调用替换成 hipcc