-
Notifications
You must be signed in to change notification settings - Fork 549
Add get_aie_coredump_elf() API for generating coredump (ET_CORE) ELF #9997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
627ddc0
ec9db67
4faa92d
6eb994f
a5c4ec7
ca1e98e
08078ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,20 +5,27 @@ | |||||||
| #define XRT_CORE_COMMON_SOURCE // in same dll as core_common | ||||||||
| #include "xrt/experimental/xrt_aie.h" | ||||||||
| #include "xrt/experimental/xrt_elf.h" | ||||||||
| #include "xrt/xrt_hw_context.h" | ||||||||
| #include "xrt/xrt_uuid.h" | ||||||||
|
|
||||||||
| #include "elf_int.h" | ||||||||
| #include "elf_patcher.h" | ||||||||
| #include "core/common/aiebu/src/cpp/elf/aie_elf_constants.h" | ||||||||
| #include "core/common/aiebu/src/cpp/include/aiebu/aiebu_assembler.h" | ||||||||
| #include "core/common/config_reader.h" | ||||||||
| #include "core/common/device.h" | ||||||||
| #include "core/common/error.h" | ||||||||
| #include "core/common/message.h" | ||||||||
| #include "core/common/query_requests.h" | ||||||||
| #include "core/common/system.h" | ||||||||
| #include "core/common/trace.h" | ||||||||
| #include "core/common/xclbin_parser.h" | ||||||||
| #include "core/common/runner/capture.h" | ||||||||
|
|
||||||||
| #include <boost/interprocess/streams/bufferstream.hpp> | ||||||||
| #include <elfio/elfio.hpp> | ||||||||
|
|
||||||||
| #include <chrono> | ||||||||
| #include <cstdint> | ||||||||
| #include <map> | ||||||||
| #include <memory> | ||||||||
|
|
@@ -1661,6 +1668,102 @@ get_filename(const xrt::elf_impl* elf_impl) | |||||||
| : ""; | ||||||||
| } | ||||||||
|
|
||||||||
| aiebu::aiebu_assembler::buffer_type | ||||||||
| osabi_to_coredump_type(uint8_t os_abi) | ||||||||
| { | ||||||||
| switch (os_abi) { | ||||||||
| case aiebu::osabi_aie2p: | ||||||||
| return aiebu::aiebu_assembler::buffer_type::coredump_aie2p; | ||||||||
| case aiebu::osabi_aie2ps: | ||||||||
| return aiebu::aiebu_assembler::buffer_type::coredump_aie2ps; | ||||||||
| case aiebu::osabi_aie4: | ||||||||
| return aiebu::aiebu_assembler::buffer_type::coredump_aie4; | ||||||||
| case aiebu::osabi_aie4a: | ||||||||
| return aiebu::aiebu_assembler::buffer_type::coredump_aie4a; | ||||||||
| case aiebu::osabi_aie4z: | ||||||||
| return aiebu::aiebu_assembler::buffer_type::coredump_aie4z; | ||||||||
| default: | ||||||||
| throw std::runtime_error("AIE coredump not supported for this ELF architecture"); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| std::vector<char> | ||||||||
| make_aie_coredump_elf(const xrt::elf& elf, const std::vector<char>& blob, | ||||||||
| const xrt_core::device* device, uint32_t slot, | ||||||||
| const std::string& uuid) | ||||||||
| { | ||||||||
| // Fail fast: verify arch is supported before doing any device queries. | ||||||||
| auto buf_type = osabi_to_coredump_type(elf.get_handle()->get_os_abi()); | ||||||||
|
|
||||||||
| aiebu::aie_coredump_meta meta{}; | ||||||||
| meta.timestamp_ns = static_cast<uint64_t>( | ||||||||
| std::chrono::duration_cast<std::chrono::nanoseconds>( | ||||||||
| std::chrono::system_clock::now().time_since_epoch()).count()); | ||||||||
| meta.uuid = uuid; | ||||||||
|
|
||||||||
| try { | ||||||||
| boost::property_tree::ptree pt_xrt; | ||||||||
| xrt_core::get_driver_info(pt_xrt); | ||||||||
| std::string drv_str; | ||||||||
| if (const auto drivers = pt_xrt.get_child_optional("drivers")) { | ||||||||
| for (const auto& kv : *drivers) { | ||||||||
| const auto& drv = kv.second; | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is generally preferred to use structured bindings for anything return tuples.
Suggested change
|
||||||||
| auto name = drv.get<std::string>("name", ""); | ||||||||
| auto ver = drv.get<std::string>("version", ""); | ||||||||
| if (!name.empty() && !ver.empty() && ver != "unknown") { | ||||||||
| if (!drv_str.empty()) | ||||||||
| drv_str += "; "; | ||||||||
|
|
||||||||
| drv_str += name + " " + ver; | ||||||||
|
stsoe marked this conversation as resolved.
|
||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
| meta.driver_version = drv_str; | ||||||||
| } | ||||||||
| catch (const std::exception&) { | ||||||||
| /* leave empty if not available */ | ||||||||
| } | ||||||||
|
|
||||||||
| try { | ||||||||
| auto data = xrt_core::device_query<xrt_core::query::aie_partition_info>(device); | ||||||||
| auto islot = static_cast<int>(slot); | ||||||||
|
|
||||||||
| for (const auto& entry : data) { | ||||||||
| if (std::stoi(entry.metadata.id) != islot) | ||||||||
| continue; | ||||||||
|
|
||||||||
| meta.context_status = entry.is_suspended | ||||||||
| ? aiebu::aie_context_status::idle | ||||||||
| : aiebu::aie_context_status::running; | ||||||||
| break; | ||||||||
| } | ||||||||
| } | ||||||||
| catch (const std::exception&) { | ||||||||
| /* leave as default idle if query not supported */ | ||||||||
| } | ||||||||
|
|
||||||||
| try { | ||||||||
| auto fw = xrt_core::device_query<xrt_core::query::firmware_version>( | ||||||||
| device, | ||||||||
| xrt_core::query::firmware_version::firmware_type::npu_firmware); | ||||||||
| meta.fw_version = std::to_string(fw.major) + "." + std::to_string(fw.minor) | ||||||||
| + "." + std::to_string(fw.patch) + "." + std::to_string(fw.build); | ||||||||
| } | ||||||||
| catch (const std::exception&) { | ||||||||
| /* leave empty if not supported */ | ||||||||
| } | ||||||||
|
|
||||||||
| try { | ||||||||
| meta.device_info = xrt_core::device_query<xrt_core::query::rom_vbnv>(device); | ||||||||
| } | ||||||||
| catch (const std::exception&) { | ||||||||
| /* leave empty if not supported */ | ||||||||
| } | ||||||||
|
|
||||||||
| aiebu::aiebu_assembler a(buf_type, blob, meta); | ||||||||
| return a.get_elf(); | ||||||||
| } | ||||||||
|
|
||||||||
| } // xrt_core::elf_int | ||||||||
|
|
||||||||
| //////////////////////////////////////////////////////////////// | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -718,6 +718,22 @@ class hw_context_impl : public std::enable_shared_from_this<hw_context_impl> | |
| } | ||
| } | ||
|
|
||
| // Public-API path — picks any ELF for OS/ABI; UUID is left empty because | ||
| // no single ELF is attributable for a partition-level dump. | ||
| std::vector<char> | ||
| get_aie_coredump_elf() const | ||
|
stsoe marked this conversation as resolved.
|
||
| { | ||
| xrt::elf elf = [this] { | ||
| std::lock_guard lk(m_mutex); | ||
| if (m_elf_map.empty()) | ||
| throw std::runtime_error("AIE coredump ELF not available: no ELF loaded in this context"); | ||
| return m_elf_map.begin()->second; | ||
| }(); | ||
|
|
||
| return xrt_core::elf_int::make_aie_coredump_elf( | ||
| elf, get_aie_coredump(), m_core_device.get(), m_hdl->get_slotidx(), ""); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You defaulted the uuid string in make_aie_coredump_elf, which I think is fine, but then this function should not mention anything about UUID and not call with the empty string. |
||
| } | ||
|
|
||
| // Returns map of kernel names to their corresponding elf files | ||
| // registered with this hardware context | ||
| std::map<std::string, xrt::elf> | ||
|
|
@@ -858,6 +874,16 @@ append_dtrace_result(const xrt::hw_context& hwctx, | |
| hwctx.get_handle()->append_dtrace_result(key, result_json); | ||
| } | ||
|
|
||
| std::vector<char> | ||
| get_aie_coredump_elf(const xrt::hw_context& hwctx, const xrt::elf& elf) | ||
| { | ||
| auto* impl = hwctx.get_handle().get(); | ||
| return xrt_core::elf_int::make_aie_coredump_elf( | ||
| elf, impl->get_aie_coredump(), impl->get_core_device().get(), | ||
| static_cast<uint32_t>(static_cast<xrt_core::hwctx_handle*>(hwctx)->get_slotidx()), | ||
| elf.get_cfg_uuid().to_string()); | ||
| } | ||
|
|
||
| } // xrt_core::hw_context_int | ||
|
|
||
| //////////////////////////////////////////////////////////////// | ||
|
|
@@ -1015,6 +1041,13 @@ get_aie_coredump() const | |
| return get_handle()->get_aie_coredump(); | ||
| } | ||
|
|
||
| std::vector<char> | ||
| hw_context:: | ||
| get_aie_coredump_elf() const | ||
| { | ||
| return get_handle()->get_aie_coredump_elf(); | ||
| } | ||
|
|
||
|
stsoe marked this conversation as resolved.
|
||
| } // xrt | ||
|
|
||
| //////////////////////////////////////////////////////////////// | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3154,7 +3154,10 @@ class run_impl : public std::enable_shared_from_this<run_impl> | |
| } | ||
|
|
||
| // abort_coredump_or_noop() - AIE coredump if enabled | ||
| // Dump core and abort, or do nothing. | ||
| // Write AIE coredump ELF to the configured file then abort. | ||
| // std::abort() ensures the OS reclaims driver resources (hw_context, hardware | ||
| // state) after a timeout. Users who set xrt.ini to capture AIE coredump | ||
| // have already observed the timeout exception on a prior run. | ||
| void | ||
| abort_coredump_or_noop(ert_cmd_state state) const | ||
| { | ||
|
|
@@ -3167,12 +3170,22 @@ class run_impl : public std::enable_shared_from_this<run_impl> | |
|
|
||
| try { | ||
| auto hwctx = kernel->get_hw_context(); | ||
| auto core = hwctx.get_aie_coredump(); // may throw | ||
| // Use the ELF from this run's own module | ||
| // Each ELF has its own UUID; using the run's module ensures the | ||
| // correct UUID is embedded in the coredump metadata. | ||
| if (!m_module) | ||
| throw std::runtime_error("AIE coredump ELF not available: no ELF associated with this run"); | ||
|
|
||
| auto elf = xrt::elf{xrt_core::module_int::get_elf_handle(m_module)}; | ||
|
|
||
| auto core = xrt_core::hw_context_int::get_aie_coredump_elf(hwctx, elf); | ||
|
|
||
| std::ofstream ostr{file, std::ios::binary}; | ||
| if (!ostr) | ||
| throw std::runtime_error("Could not open '" + file + "' for writing"); | ||
|
|
||
| ostr.write(core.data(), static_cast<std::streamsize>(core.size())); | ||
| ostr.flush(); // flush before abort — destructors do not run after std::abort() | ||
| std::abort(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there was a mention that we should not abort on coredump, but the original spec said we should. I want to make sure remove std::abort() is indeed correct.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should keep the std::abort() to make sure driver clean up hw_context after timeout. We don't have to get the exception message and coredump() at one run. When usesrs set xrt.ini to save aie coredump, they already see the timeout and exception message. |
||
| } | ||
| catch (const std::exception& ex) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was previously in a nested unnamed namespace, I suggested either moving the namespace or making the function static,