背景
之前将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
。