diff --git a/src/runtime_src/core/common/xdp/CMakeLists.txt b/src/runtime_src/core/common/xdp/CMakeLists.txt index 8f564feda82..3fe9cd48bc4 100644 --- a/src/runtime_src/core/common/xdp/CMakeLists.txt +++ b/src/runtime_src/core/common/xdp/CMakeLists.txt @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved. +# Copyright (C) 2022-2025 Advanced Micro Devices, Inc. All rights reserved. add_library(core_common_xdp_profile_objects OBJECT profile.cpp ) @@ -14,4 +14,10 @@ if (XDP_CLIENT_BUILD_CMAKE STREQUAL "yes") PRIVATE XDP_CLIENT_BUILD=1 ) + +elseif (XDP_VE2_BUILD_CMAKE STREQUAL "yes") + target_compile_definitions(core_common_xdp_profile_objects + PRIVATE + XDP_VE2_BUILD=1 + ) endif() diff --git a/src/runtime_src/core/common/xdp/profile.cpp b/src/runtime_src/core/common/xdp/profile.cpp index 4c75bc638b1..e5dcb1cb00b 100644 --- a/src/runtime_src/core/common/xdp/profile.cpp +++ b/src/runtime_src/core/common/xdp/profile.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright (C) 2023-2024 Advanced Micro Devices, Inc. - All rights reserved +// Copyright (C) 2023-2025 Advanced Micro Devices, Inc. - All rights reserved #define XRT_CORE_COMMON_SOURCE #include "core/common/xdp/profile.h" @@ -140,11 +140,12 @@ std::function finish_flush_device_cb; void register_callbacks(void* handle) { - #ifdef XDP_CLIENT_BUILD + #if defined(XDP_CLIENT_BUILD) || defined(XDP_VE2_BUILD) using ftype = void (*)(void*); update_device_cb = reinterpret_cast(xrt_core::dlsym(handle, "updateDeviceMLTmln")); finish_flush_device_cb = reinterpret_cast(xrt_core::dlsym(handle, "finishflushDeviceMLTmln")); + #else (void)handle; #endif @@ -461,6 +462,18 @@ update_device(void* handle) xrt_core::xdp::aie_pc::update_device(handle); } +#elif defined(XDP_VE2_BUILD) + + if (xrt_core::config::get_ml_timeline()) { + try { + xrt_core::xdp::ml_timeline::load(); + } + catch (...) { + return; + } + xrt_core::xdp::ml_timeline::update_device(handle); + } + #else if (xrt_core::config::get_pl_deadlock_detection() @@ -495,6 +508,11 @@ finish_flush_device(void* handle) if (xrt_core::config::get_aie_pc()) xrt_core::xdp::aie_pc::finish_flush_device(handle); +#elif defined(XDP_VE2_BUILD) + + if (xrt_core::config::get_ml_timeline()) + xrt_core::xdp::ml_timeline::finish_flush_device(handle); + #else if (xrt_core::config::get_pl_deadlock_detection() diff --git a/src/runtime_src/xdp/profile/plugin/CMakeLists.txt b/src/runtime_src/xdp/profile/plugin/CMakeLists.txt index 467f464ab07..47b69ea2991 100644 --- a/src/runtime_src/xdp/profile/plugin/CMakeLists.txt +++ b/src/runtime_src/xdp/profile/plugin/CMakeLists.txt @@ -1,10 +1,11 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2022-2023 Advanced Micro Devices, Inc. All rights reserved. +# Copyright (C) 2022-2025 Advanced Micro Devices, Inc. All rights reserved. # if(XDP_VE2_BUILD_CMAKE STREQUAL "yes") add_subdirectory(aie_profile) add_subdirectory(aie_trace) + add_subdirectory(ml_timeline) elseif (XDP_CLIENT_BUILD_CMAKE STREQUAL "yes") diff --git a/src/runtime_src/xdp/profile/plugin/ml_timeline/CMakeLists.txt b/src/runtime_src/xdp/profile/plugin/ml_timeline/CMakeLists.txt index 884df83a2aa..baff54ec7fc 100644 --- a/src/runtime_src/xdp/profile/plugin/ml_timeline/CMakeLists.txt +++ b/src/runtime_src/xdp/profile/plugin/ml_timeline/CMakeLists.txt @@ -1,15 +1,20 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. +# Copyright (C) 2023-2025 Advanced Micro Devices, Inc. All rights reserved. # -# =========================================================================== -# This builds the ML Timeline plugin. It is currently built on Windows Only. -# =========================================================================== +# ======================================================================================== +# This builds the ML Timeline plugin. +# It is currently built for Client on Windows and Linux, and also for VE2 Device on Linux. +# ======================================================================================== if (XDP_CLIENT_BUILD_CMAKE STREQUAL "yes") set(IMPL_DIR "${PROFILE_DIR}/plugin/ml_timeline/clientDev") endif() +if (XDP_VE2_BUILD_CMAKE STREQUAL "yes") + set(IMPL_DIR "${PROFILE_DIR}/plugin/ml_timeline/ve2") +endif() + file(GLOB ML_TIMELINE_PLUGIN_FILES "${PROFILE_DIR}/plugin/ml_timeline/*.h" "${PROFILE_DIR}/plugin/ml_timeline/*.cpp" @@ -31,4 +36,21 @@ if (XDP_CLIENT_BUILD_CMAKE STREQUAL "yes") LIBRARY DESTINATION ${XDP_PLUGIN_INSTALL_DIR} ) +elseif (XDP_VE2_BUILD_CMAKE STREQUAL "yes") + +add_library(xdp_ml_timeline_plugin MODULE ${ML_TIMELINE_PLUGIN_FILES}) +add_dependencies(xdp_ml_timeline_plugin xdp_core xrt_coreutil) + +target_include_directories(xdp_ml_timeline_plugin PRIVATE ${CMAKE_SOURCE_DIR}/src) + +target_link_libraries(xdp_ml_timeline_plugin PRIVATE xdp_core xrt_coreutil) + +target_compile_definitions(xdp_ml_timeline_plugin PRIVATE XDP_VE2_BUILD=1) + +set_target_properties(xdp_ml_timeline_plugin PROPERTIES VERSION ${XRT_VERSION_STRING} SOVERSION ${XRT_SOVERSION}) + +install (TARGETS xdp_ml_timeline_plugin + LIBRARY DESTINATION ${XDP_PLUGIN_INSTALL_DIR} +) + endif() diff --git a/src/runtime_src/xdp/profile/plugin/ml_timeline/ml_timeline_plugin.cpp b/src/runtime_src/xdp/profile/plugin/ml_timeline/ml_timeline_plugin.cpp index 375d59e0a5a..6098287555b 100644 --- a/src/runtime_src/xdp/profile/plugin/ml_timeline/ml_timeline_plugin.cpp +++ b/src/runtime_src/xdp/profile/plugin/ml_timeline/ml_timeline_plugin.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2023-2024 Advanced Micro Devices, Inc. - All rights reserved + * Copyright (C) 2023-2025 Advanced Micro Devices, Inc. - All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the @@ -30,6 +30,8 @@ #ifdef XDP_CLIENT_BUILD #include "xdp/profile/plugin/ml_timeline/clientDev/ml_timeline.h" +#elif defined (XDP_VE2_BUILD) +#include "xdp/profile/plugin/ml_timeline/ve2/ml_timeline.h" #endif namespace xdp { @@ -114,6 +116,9 @@ namespace xdp { void MLTimelinePlugin::updateDevice(void* hwCtxImpl) { + xrt_core::message::send(xrt_core::message::severity_level::info, "XRT", + "In ML Timeline Plugin : updateDevice."); + #ifdef XDP_CLIENT_BUILD if (mMultiImpl.find(hwCtxImpl) != mMultiImpl.end()) { @@ -138,12 +143,47 @@ namespace xdp { auto mlImpl = mMultiImpl[hwCtxImpl].second.get(); mlImpl->updateDevice(hwCtxImpl); -#endif +#elif defined (XDP_VE2_BUILD) + + if (mMultiImpl.find(hwCtxImpl) != mMultiImpl.end()) { + // Same Hardware Context Implementation uses the same impl and buffer + return; + } + + if (0 == mBufSz) + mBufSz = ParseMLTimelineBufferSizeConfig(); + + xrt::hw_context hwContext = xrt_core::hw_context_int::create_hw_context_from_implementation(hwCtxImpl); + std::shared_ptr coreDevice = xrt_core::hw_context_int::get_core_device(hwContext); + + xclDeviceHandle h = coreDevice->get_device_handle(); + if (nullptr == h) { + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "In ML Timeline Plugin for VE2 Device : Devicehandle is NULL"); + return; + } + + uint64_t implId = mMultiImpl.size(); + + std::string deviceName = "ve2_device" + std::to_string(implId); + uint64_t deviceId = db->addDevice(deviceName); + (db->getStaticInfo()).updateDeviceClient(deviceId, coreDevice, false); + (db->getStaticInfo()).setDeviceName(deviceId, deviceName); + + mMultiImpl[hwCtxImpl] = std::make_pair(implId, std::make_unique(db, mBufSz)); + auto mlImpl = mMultiImpl[hwCtxImpl].second.get(); + mlImpl->updateDevice(h); + + #endif + } void MLTimelinePlugin::finishflushDevice(void* hwCtxImpl) { -#ifdef XDP_CLIENT_BUILD + xrt_core::message::send(xrt_core::message::severity_level::info, "XRT", + "In ML Timeline Plugin : finish flush Device."); + +#if defined(XDP_CLIENT_BUILD) || defined(XDP_VE2_BUILD) if (mMultiImpl.empty()) { xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", "In ML Timeline Plugin : No active HW Context found. So no data flush done."); @@ -167,7 +207,7 @@ namespace xdp { void MLTimelinePlugin::writeAll(bool /*openNewFiles*/) { -#ifdef XDP_CLIENT_BUILD +#if defined(XDP_CLIENT_BUILD) || defined(XDP_VE2_BUILD) for (auto &e : mMultiImpl) { if (nullptr == e.second.second) continue; diff --git a/src/runtime_src/xdp/profile/plugin/ml_timeline/ve2/ml_timeline.cpp b/src/runtime_src/xdp/profile/plugin/ml_timeline/ve2/ml_timeline.cpp new file mode 100644 index 00000000000..31e43c6e5a6 --- /dev/null +++ b/src/runtime_src/xdp/profile/plugin/ml_timeline/ve2/ml_timeline.cpp @@ -0,0 +1,222 @@ +/** + * Copyright (C) 2025 Advanced Micro Devices, Inc. - All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may + * not use this file except in compliance with the License. A copy of the + * License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +#define XDP_PLUGIN_SOURCE + +#include +#include + +#include +#include +#include + +#include "shim/shim.h" + +#include "core/common/device.h" +#include "core/common/message.h" + +#include "core/include/xrt/xrt_bo.h" +#include "core/include/xrt/xrt_kernel.h" + +#include "xdp/profile/plugin/ml_timeline/ve2/ml_timeline.h" +#include "xdp/profile/plugin/vp_base/utility.h" + +namespace xdp { + + class VE2ResultBO + { + private: + aiarm::shim* mDev; + std::unique_ptr mBufHandle; + uint32_t *mBOptr = nullptr; + bool mNoUnmap = false; + + uint32_t* mapAndChk() + { + mBOptr = reinterpret_cast(mBufHandle->map(xrt_core::buffer_handle::map_type::write)); + if (!mBOptr) + throw std::runtime_error("Failed mapping bo of " + std::to_string(size()) + "bytes."); + return mBOptr; + } + + public: + VE2ResultBO(aiarm::shim* devHandle, size_t size) + : mDev(devHandle) + { + xcl_bo_flags flags {0}; + flags.flags = XRT_BO_FLAGS_CACHEABLE; + flags.access = XRT_BO_ACCESS_LOCAL; + flags.dir = XRT_BO_ACCESS_READ_WRITE; + flags.use = XRT_BO_USE_DEBUG; + mBufHandle = mDev->xclAllocBO(size, flags.all); + mapAndChk(); + } + + ~VE2ResultBO() + { + if (!mNoUnmap) + mBufHandle->unmap(mBOptr); + } + + xrt_core::buffer_handle* get() { return mBufHandle.get(); } + + uint32_t *map() { return mBOptr; } + + void set_no_unmap() { mNoUnmap = true; } + + size_t size() { return mBufHandle->get_properties().size; } + }; + + MLTimelineVE2Impl::MLTimelineVE2Impl(VPDatabase*dB, uint32_t sz) + : MLTimelineImpl(dB, sz) + { + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "Created ML Timeline Plugin for VE2 Device."); + } + + MLTimelineVE2Impl::~MLTimelineVE2Impl() + { + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "In destructor for ML Timeline Plugin for VE2 Device."); + } + + void MLTimelineVE2Impl::updateDevice(void* devH) + { + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "In MLTimelineVE2Impl::updateDevice"); + try { + mResultBOHolder = std::make_unique(reinterpret_cast(devH), mBufSz); + memset(mResultBOHolder->map(), 0, mBufSz); + + } catch (std::exception& e) { + std::stringstream msg; + msg << "Unable to create/initialize result buffer of size " + << std::hex << mBufSz << std::dec + << " Bytes for Record Timer Values. Cannot get ML Timeline info. " + << e.what() << std::endl; + xrt_core::message::send(xrt_core::message::severity_level::warning, "XRT", msg.str()); + return; + } + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "Allocated buffer In MLTimelineVE2Impl::updateDevice"); + } + + void MLTimelineVE2Impl::finishflushDevice(void* /*hwCtxImpl*/, uint64_t implId) + { + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "In MLTimelineVE2Impl::finishflushDevice"); + + if (!mResultBOHolder) + return; + + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", + "Using Allocated buffer In MLTimelineVE2Impl::finishflushDevice"); + +// mResultBOHolder->syncFromDevice(); + uint32_t* ptr = mResultBOHolder->map(); + + boost::property_tree::ptree ptTop; + boost::property_tree::ptree ptHeader; + boost::property_tree::ptree ptRecordTimerTS; + + // Header for JSON + ptHeader.put("date", xdp::getCurrentDateTime()); + ptHeader.put("time_created", xdp::getMsecSinceEpoch()); + + boost::property_tree::ptree ptSchema; + ptSchema.put("major", "1"); + ptSchema.put("minor", "1"); + ptSchema.put("patch", "0"); + ptHeader.add_child("schema_version", ptSchema); + ptHeader.put("device", "Client"); + ptHeader.put("clock_freq_MHz", 1000); + ptHeader.put("id_size", sizeof(uint32_t)); + ptHeader.put("cycle_size", 2*sizeof(uint32_t)); + ptHeader.put("buffer_size", mBufSz); + ptTop.add_child("header", ptHeader); + + // Record Timer TS in JSON + // Assuming correct Stub has been called and Write Buffer contains valid data + + uint32_t maxCount = mBufSz / RECORD_TIMER_ENTRY_SZ_IN_BYTES; + // Each record timer entry has 32bit ID and 32bit AIE High Timer + 32bit AIE Low Timer value. + + uint32_t numEntries = maxCount; + std::stringstream msg; + msg << "A maximum of " << numEntries << " record can be accommodated in given buffer of bytes size 0x" + << std::hex << mBufSz << std::dec << std::endl; + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", msg.str()); + + if (numEntries <= maxCount) { + for (uint32_t i = 0 ; i < numEntries; i++) { + boost::property_tree::ptree ptIdTS; + uint32_t id = *ptr; + ptIdTS.put("id", *ptr); + ptr++; + + uint64_t ts64 = *ptr; + ts64 = ts64 << 32; + ptr++; + ts64 |= (*ptr); + if (0 == ts64 && 0 == id) { + // Zero value for Timestamp in cycles (and id too) indicates end of recorded data + std::string msgEntries = "Got " + std::to_string(i) + " records in buffer."; + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", msgEntries); + break; + } + ptIdTS.put("cycle", ts64); + ptr++; + + ptRecordTimerTS.push_back(std::make_pair("", ptIdTS)); + } + } + + if (ptRecordTimerTS.empty()) { + boost::property_tree::ptree ptEmpty; + ptRecordTimerTS.push_back(std::make_pair("", ptEmpty)); + } + ptTop.add_child("record_timer_ts", ptRecordTimerTS); + + // Write output file + std::ostringstream oss; + boost::property_tree::write_json(oss, ptTop); + + // Remove quotes from value strings + std::regex reg("\\\"((-?[0-9]+\\.{0,1}[0-9]*)|(null)|())\\\"(?!\\:)"); + std::string result = std::regex_replace(oss.str(), reg, "$1"); + + std::string outFName; + if (0 == implId) { + outFName = "record_timer_ts.json"; + } else { + outFName = "record_timer_ts_" + std::to_string(implId) + ".json"; + } + std::ofstream fOut; + fOut.open(outFName); + fOut << result; + fOut.close(); + + std::stringstream msg1; + msg1 << "Finished writing " << outFName << " in MLTimelineVE2Impl::finishflushDevice." << std::endl; + xrt_core::message::send(xrt_core::message::severity_level::debug, "XRT", msg1.str()); + + /* Delete the result BO so that AIE Profile/Debug Plugins, if enabled, + * can use their own Debug BO to capture their data. + */ + mResultBOHolder.reset(nullptr); + } +} + diff --git a/src/runtime_src/xdp/profile/plugin/ml_timeline/ve2/ml_timeline.h b/src/runtime_src/xdp/profile/plugin/ml_timeline/ve2/ml_timeline.h new file mode 100644 index 00000000000..b56cd0bdf04 --- /dev/null +++ b/src/runtime_src/xdp/profile/plugin/ml_timeline/ve2/ml_timeline.h @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2025 Advanced Micro Devices, Inc. - All rights reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"). You may + * not use this file except in compliance with the License. A copy of the + * License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +#ifndef XDP_PLUGIN_ML_TIMELINE_VE2_IMPL_H +#define XDP_PLUGIN_ML_TIMELINE_VE2_IMPL_H + +#include "xdp/config.h" +#include "xdp/profile/plugin/ml_timeline/ml_timeline_impl.h" + +namespace xdp { + + class VE2ResultBO; + class MLTimelineVE2Impl : public MLTimelineImpl + { + std::unique_ptr mResultBOHolder; + public : + MLTimelineVE2Impl(VPDatabase* dB, uint32_t sz); + + ~MLTimelineVE2Impl(); + + virtual void updateDevice(void* devH); + virtual void finishflushDevice(void* hwCtxImpl, uint64_t implId = 0); + }; + +} + +#endif +