Add libomptarget discovery to prevent OpenMP/HIP segfaults (#1043)

This PR fixes a segmentation fault seen when running rocprof-sys-sample with multi-process OpenMP/HIP applications.
The crash was caused by missing libomptarget.so on the runtime loader path or incorrect LD_PRELOAD settings.

Fixes SWDEV-552804

---------

Co-authored-by: David Galiffi <David.Galiffi@amd.com>
This commit is contained in:
habajpai-amd
2025-10-01 19:21:26 +05:30
committed by GitHub
szülő 36a1fd87af
commit 74fc268a32
8 fájl változott, egészen pontosan 239 új sor hozzáadva és 48 régi sor törölve
@@ -204,6 +204,14 @@ get_initial_environment()
get_env<int>("ROCPROFSYS_THREAD_POOL_SIZE", 0));
update_env(_env, "ROCPROFSYS_LAUNCHER", "rocprof-sys-causal");
// Ensure libomptarget.so can be found by the target (OpenMP/HIP apps)
if(auto llvm_dir =
rocprofsys::common::discover_llvm_libdir_for_ompt(get_verbose() > 0);
!llvm_dir.empty())
{
update_env(_env, "LD_LIBRARY_PATH", llvm_dir, /*append=*/true);
}
return _env;
}
@@ -351,13 +359,13 @@ update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_va
if(_env_var == "LD_PRELOAD")
{
itr =
strdup(join('=', _env_var, join(_join_delim, _val, _env_val))
strdup(join('=', _env_var, join(_join_delim, _env_val, _val))
.c_str());
}
else
{
itr =
strdup(join('=', _env_var, join(_join_delim, _env_val, _val))
strdup(join('=', _env_var, join(_join_delim, _val, _env_val))
.c_str());
}
}
@@ -82,31 +82,112 @@ to_string(bool _v)
namespace
{
auto original_envs = std::set<std::string>{};
enum update_mode : int
{
UPD_REPLACE = 0, // no PREPEND/APPEND bits set
UPD_PREPEND = 1 << 0, // 0x01
UPD_APPEND = 1 << 1, // 0x02
UPD_WEAK = 1 << 2, // 0x04
};
std::string
get_rocprofsys_root(void)
{
char* _tmp = realpath("/proc/self/exe", nullptr);
std::string _exe = (_tmp) ? std::string{ _tmp } : std::string{};
if(_tmp) free(_tmp);
auto _pos = _exe.find_last_of('/');
auto _dir = std::string{ "./" };
if(_pos != std::string::npos) _dir = _exe.substr(0, _pos);
return rocprofsys::common::join("/", _dir, "..");
}
std::string
get_internal_libpath(const std::string& _lib)
{
auto _exe = std::string_view{ realpath("/proc/self/exe", nullptr) };
auto _pos = _exe.find_last_of('/');
auto _dir = std::string{ "./" };
if(_pos != std::string_view::npos) _dir = _exe.substr(0, _pos);
return rocprofsys::common::join("/", _dir, "..", "lib", _lib);
auto _root = get_rocprofsys_root();
return rocprofsys::common::join("/", _root, "lib", _lib);
}
parser_data_t&
get_initial_environment(parser_data_t& _data)
std::string
get_internal_script_path(void)
{
if(environ != nullptr)
auto _root = get_rocprofsys_root();
return rocprofsys::common::join("/", _root, "libexec", "rocprofiler-systems");
}
std::string
get_realpath(const std::string& _v)
{
if(auto* _tmp = realpath(_v.c_str(), nullptr))
{
int idx = 0;
while(environ[idx] != nullptr)
{
auto* _v = environ[idx++];
_data.initial.emplace(_v);
_data.current.emplace_back(strdup(_v));
}
std::string _ret{ _tmp };
free(_tmp);
return _ret;
}
return {};
}
template <typename Tp>
void
update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_val,
update_mode&& _mode, std::string_view _join_delim = ":")
{
auto _prepend = (_mode & UPD_PREPEND) != 0;
auto _append = (_mode & UPD_APPEND) != 0;
auto _weak_upd = (_mode & UPD_WEAK) != 0;
// if both flags are set, prefer append
if(_prepend && _append)
{
_prepend = false;
}
return _data;
auto _key = join("", _env_var, "=");
for(auto& itr : _environ)
{
if(!itr) continue;
if(std::string_view{ itr }.find(_key) == 0)
{
if(_weak_upd)
{
// if the value has changed, do not update but allow overridding the value
// inherited from the initial env
if(original_envs.find(std::string{ itr }) == original_envs.end()) return;
}
if(_prepend || _append)
{
if(std::string_view{ itr }.find(join("", _env_val)) ==
std::string_view::npos)
{
auto _val = std::string{ itr }.substr(_key.length());
free(itr);
if(_prepend)
itr =
strdup(join('=', _env_var, join(_join_delim, _env_val, _val))
.c_str());
else
itr =
strdup(join('=', _env_var, join(_join_delim, _val, _env_val))
.c_str());
}
}
else
{
free(itr);
itr = strdup(rocprofsys::common::join('=', _env_var, _env_val).c_str());
}
return;
}
}
_environ.emplace_back(
strdup(rocprofsys::common::join('=', _env_var, _env_val).c_str()));
}
int
@@ -121,13 +202,40 @@ get_verbose(parser_data_t& _data)
return verbose;
}
std::string
get_realpath(const std::string& _v)
parser_data_t&
get_initial_environment(parser_data_t& _data)
{
auto* _tmp = realpath(_v.c_str(), nullptr);
auto _ret = std::string{ _tmp };
free(_tmp);
return _ret;
if(environ != nullptr)
{
int idx = 0;
while(environ[idx] != nullptr)
{
auto* _v = environ[idx++];
_data.initial.emplace(_v);
_data.current.emplace_back(strdup(_v));
original_envs.emplace(_v);
}
}
auto _libexecpath = get_realpath(get_internal_script_path());
if(!_libexecpath.empty())
{
update_env(_data.current, "ROCPROFSYS_SCRIPT_PATH", _libexecpath, UPD_REPLACE);
_data.updated.emplace("ROCPROFSYS_SCRIPT_PATH");
}
const bool verbose = (get_verbose(_data) > 0);
if(auto llvm_dir = rocprofsys::common::discover_llvm_libdir_for_ompt(verbose);
!llvm_dir.empty())
{
update_env(_data.current, "LD_LIBRARY_PATH", llvm_dir, UPD_APPEND);
_data.updated.emplace("LD_LIBRARY_PATH");
auto current_ld = getenv("LD_LIBRARY_PATH");
std::string new_ld = current_ld ? (llvm_dir + ":" + current_ld) : llvm_dir;
setenv("LD_LIBRARY_PATH", new_ld.c_str(), 1);
}
return _data;
}
auto
@@ -132,6 +132,13 @@ get_initial_environment()
update_env(_env, "LD_LIBRARY_PATH", tim::filepath::dirname(_dl_libpath), UPD_APPEND);
update_env(_env, "ROCPROFSYS_SCRIPT_PATH", _libexecpath, UPD_REPLACE);
// Discover LLVM libdir containing libomptarget.so and append to LD_LIBRARY_PATH
if(auto llvm_dir = rocprofsys::common::discover_llvm_libdir_for_ompt(verbose > 0);
!llvm_dir.empty())
{
update_env(_env, "LD_LIBRARY_PATH", llvm_dir, UPD_APPEND);
}
auto _mode = get_env<std::string>("ROCPROFSYS_MODE", "sampling", false);
update_env(_env, "ROCPROFSYS_USE_SAMPLING", (_mode != "causal"));
@@ -223,9 +230,15 @@ update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_va
{
updated_envs.emplace(_env_var);
auto _prepend = (_mode & UPD_PREPEND) == UPD_PREPEND;
auto _append = (_mode & UPD_APPEND) == UPD_APPEND;
auto _weak_upd = (_mode & UPD_WEAK) == UPD_WEAK;
auto _prepend = (_mode & UPD_PREPEND) != 0;
auto _append = (_mode & UPD_APPEND) != 0;
auto _weak_upd = (_mode & UPD_WEAK) != 0;
// if both flags are set, prefer append
if(_prepend && _append)
{
_prepend = false;
}
auto _key = join("", _env_var, "=");
for(auto& itr : _environ)
@@ -249,11 +262,11 @@ update_env(std::vector<char*>& _environ, std::string_view _env_var, Tp&& _env_va
free(itr);
if(_prepend)
itr =
strdup(join('=', _env_var, join(_join_delim, _val, _env_val))
strdup(join('=', _env_var, join(_join_delim, _env_val, _val))
.c_str());
else
itr =
strdup(join('=', _env_var, join(_join_delim, _env_val, _val))
strdup(join('=', _env_var, join(_join_delim, _val, _env_val))
.c_str());
}
}
@@ -28,10 +28,10 @@
enum update_mode : int
{
UPD_REPLACE = 0x1,
UPD_PREPEND = 0x2,
UPD_APPEND = 0x3,
UPD_WEAK = 0x4,
UPD_REPLACE = 0, // no PREPEND/APPEND bits set
UPD_PREPEND = 1 << 0, // 0x01
UPD_APPEND = 1 << 1, // 0x02
UPD_WEAK = 1 << 2, // 0x04
};
std::string