From a61f825ba5a3a680accd999b6ec852c52975aac1 Mon Sep 17 00:00:00 2001 From: rfwang07 Date: Tue, 3 Dec 2024 11:37:12 +0800 Subject: [PATCH 1/4] update libkperf dependence and adapt code for oeaware 2.0 --- 0001-update-libkperf-dependence.patch | 70 +++ 0002-adapt-the-code-for-oeaware-2.0.patch | 626 ++++++++++++++++++++++ 0003-adapt-include-dir-for-oeaware.patch | 80 +++ D-FOT.spec | 41 +- 4 files changed, 790 insertions(+), 27 deletions(-) create mode 100644 0001-update-libkperf-dependence.patch create mode 100644 0002-adapt-the-code-for-oeaware-2.0.patch create mode 100644 0003-adapt-include-dir-for-oeaware.patch diff --git a/0001-update-libkperf-dependence.patch b/0001-update-libkperf-dependence.patch new file mode 100644 index 0000000..a7a4170 --- /dev/null +++ b/0001-update-libkperf-dependence.patch @@ -0,0 +1,70 @@ +From 2cd49e73b30659f6faa9ff439083506f0ccec712 Mon Sep 17 00:00:00 2001 +From: rfwang07 +Date: Tue, 3 Dec 2024 15:40:47 +0800 +Subject: [PATCH] update libkperf dependence + +--- + CMakeLists.txt | 9 --------- + include/opt.h | 2 +- + src/startup_opt.cc | 5 ++--- + 3 files changed, 3 insertions(+), 13 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 00675c2..df8006e 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -19,10 +19,6 @@ endif() + + add_compile_options(-fPIC -Wall -Wextra) + +-# libkperf +-message("-- libkperf library path: ${LIB_KPERF_LIBPATH}") +-message("-- libkperf include path: ${LIB_KPERF_INCPATH}") +- + set(dfot_tuner_sysboost_src + src/oeaware_plugins/instance.cc + src/oeaware_plugins/tuner_sysboost.cc +@@ -37,11 +33,6 @@ add_library(dfot SHARED ${dfot_tuner_sysboost_src}) + + include_directories(dfot PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include +- ${LIB_KPERF_INCPATH} +-) +- +-target_link_directories(dfot PUBLIC +- ${LIB_KPERF_LIBPATH} + ) + + target_link_libraries(dfot kperf sym dl log4cplus boost_system boost_filesystem) +diff --git a/include/opt.h b/include/opt.h +index f998501..2c40cbe 100644 +--- a/include/opt.h ++++ b/include/opt.h +@@ -14,7 +14,7 @@ + + #include + +-#include "pmu.h" ++#include "libkperf/pmu.h" + #include "configs.h" + + extern bool check_dependence_ready(); +diff --git a/src/startup_opt.cc b/src/startup_opt.cc +index b408205..5b2ad9c 100644 +--- a/src/startup_opt.cc ++++ b/src/startup_opt.cc +@@ -9,9 +9,8 @@ + + #include "boost/filesystem.hpp" + +-// libkperf +-#include "pmu.h" +-#include "symbol.h" ++#include "libkperf/pmu.h" ++#include "libkperf/symbol.h" + + // D-FOT + #include "interface.h" +-- +2.39.5 (Apple Git-154) + diff --git a/0002-adapt-the-code-for-oeaware-2.0.patch b/0002-adapt-the-code-for-oeaware-2.0.patch new file mode 100644 index 0000000..8e5314a --- /dev/null +++ b/0002-adapt-the-code-for-oeaware-2.0.patch @@ -0,0 +1,626 @@ +From 82bd0304d05a4f4c7ca913eab7d0863912bccfa3 Mon Sep 17 00:00:00 2001 +From: rfwang07 +Date: Tue, 3 Dec 2024 23:05:06 +0800 +Subject: [PATCH] adapt the code for oeaware 2.0 + +--- + CMakeLists.txt | 11 +- + include/interface.h | 74 -------- + include/logs.h | 12 +- + include/opt.h | 2 +- + include/tuner.h | 21 ++- + src/configs.cc | 2 +- + src/oeaware_plugins/instance.cc | 11 +- + src/oeaware_plugins/tuner_sysboost.cc | 249 ++++++++++++-------------- + src/startup_opt.cc | 14 +- + 9 files changed, 158 insertions(+), 238 deletions(-) + delete mode 100644 include/interface.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index df8006e..dda676e 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,8 +1,6 @@ + cmake_minimum_required(VERSION 3.15) + project(D-FOT) + +-set(CMAKE_CXX_STANDARD 11) +- + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message("-- Build type: Debug") + add_compile_options(-g3 -O0) +@@ -17,7 +15,7 @@ else() + add_compile_options(-O3) + endif() + +-add_compile_options(-fPIC -Wall -Wextra) ++add_compile_options(-std=c++17 -fPIC -Wall -Wextra) + + set(dfot_tuner_sysboost_src + src/oeaware_plugins/instance.cc +@@ -31,8 +29,13 @@ set(dfot_tuner_sysboost_src + + add_library(dfot SHARED ${dfot_tuner_sysboost_src}) + ++ + include_directories(dfot PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include ++ # 因为oeAware头文件问题,此处临时适配 ++ /usr/include/libkperf ++ /usr/include/oeaware ++ /usr/include/oeaware/interface + ) + +-target_link_libraries(dfot kperf sym dl log4cplus boost_system boost_filesystem) ++target_link_libraries(dfot boundscheck kperf sym dl log4cplus boost_system boost_filesystem) +diff --git a/include/interface.h b/include/interface.h +deleted file mode 100644 +index 0a49743..0000000 +--- a/include/interface.h ++++ /dev/null +@@ -1,74 +0,0 @@ +-/****************************************************************************** +- * Copyright (c) 2024 Huawei Technologies Co., Ltd. +- * oeAware is licensed under Mulan PSL v2. +- * You can use this software according to the terms and conditions of the Mulan PSL v2. +- * You may obtain a copy of Mulan PSL v2 at: +- * http://license.coscl.org.cn/MulanPSL2 +- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +- * See the Mulan PSL v2 for more details. +- ******************************************************************************/ +-#ifndef __INTERFACE_H__ +-#define __INTERFACE_H__ +- +-#include +-#include +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-struct DataBuf { +- int len; +- void *data; +-}; +- +-struct DataRingBuf { +- /* instance name */ +- const char *instance_name; +- /* buf write index, initial value is -1 */ +- int index; +- /* instance run times */ +- uint64_t count; +- struct DataBuf *buf; +- int buf_len; +-}; +- +-struct Param { +- const struct DataRingBuf **ring_bufs; +- int len; +-}; +- +-struct Interface { +- const char* (*get_version)(); +- /* The instance name is a unique identifier in the system. */ +- const char* (*get_name)(); +- const char* (*get_description)(); +- /* Specifies the instance dependencies, which is used as the input information +- * for instance execution. +- */ +- const char* (*get_dep)(); +- /* Instance scheduling priority. In a uniform time period, a instance with a +- * lower priority is scheduled first. +- */ +- int (*get_priority)(); +- int (*get_type)(); +- /* Instance execution period. */ +- int (*get_period)(); +- bool (*enable)(); +- void (*disable)(); +- const struct DataRingBuf* (*get_ring_buf)(); +- void (*run)(const struct Param*); +-}; +- +-/* Obtains the instances from the plugin. +- * The return value is the number of instances. +- */ +-int get_instance(struct Interface **interface); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif +diff --git a/include/logs.h b/include/logs.h +index f27d289..331060c 100644 +--- a/include/logs.h ++++ b/include/logs.h +@@ -22,11 +22,11 @@ + + #define DFOT_LOG_PATH "/etc/dfot/dfot.log" + +-#define DEBUG(fmt) LOG4CPLUS_DEBUG(logger.get(), fmt) +-#define INFO(fmt) LOG4CPLUS_INFO(logger.get(), fmt) +-#define WARN(fmt) LOG4CPLUS_WARN(logger.get(), fmt) +-#define ERROR(fmt) LOG4CPLUS_ERROR(logger.get(), fmt) +-#define FATAL(fmt) LOG4CPLUS_FATAL(logger.get(), fmt) ++#define DEBUG(fmt) LOG4CPLUS_DEBUG(dfot_logger.get(), fmt) ++#define INFO(fmt) LOG4CPLUS_INFO(dfot_logger.get(), fmt) ++#define WARN(fmt) LOG4CPLUS_WARN(dfot_logger.get(), fmt) ++#define ERROR(fmt) LOG4CPLUS_ERROR(dfot_logger.get(), fmt) ++#define FATAL(fmt) LOG4CPLUS_FATAL(dfot_logger.get(), fmt) + + static std::map LOG_LEVEL = { + {"DEBUG", log4cplus::DEBUG_LOG_LEVEL}, +@@ -51,6 +51,6 @@ private: + log4cplus::Initializer initializer; + }; + +-extern Logger logger; ++extern Logger dfot_logger; + + #endif +diff --git a/include/opt.h b/include/opt.h +index 2c40cbe..ff0241b 100644 +--- a/include/opt.h ++++ b/include/opt.h +@@ -14,7 +14,7 @@ + + #include + +-#include "libkperf/pmu.h" ++#include + #include "configs.h" + + extern bool check_dependence_ready(); +diff --git a/include/tuner.h b/include/tuner.h +index 326615c..46db4f7 100644 +--- a/include/tuner.h ++++ b/include/tuner.h +@@ -12,8 +12,25 @@ + #ifndef __TUNER_H__ + #define __TUNER_H__ + +-#include "interface.h" ++#include ++#include ++#include + +-extern struct Interface sysboost_tuner; ++class SysboostTuner : public oeaware::Interface { ++public: ++ SysboostTuner(); ++ ~SysboostTuner(); ++ oeaware::Result OpenTopic(const oeaware::Topic &topic) override; ++ void CloseTopic(const oeaware::Topic &topic) override; ++ void UpdateData(const DataList &dataList) override; ++ oeaware::Result Enable(const std::string ¶m) override; ++ void Disable() override; ++ void Run() override; ++ ++private: ++ oeaware::Topic depTopic; ++ void *processingArea; ++ size_t processingAreaSize; ++}; + + #endif +diff --git a/src/configs.cc b/src/configs.cc +index 9cc0c38..9aa6d36 100644 +--- a/src/configs.cc ++++ b/src/configs.cc +@@ -81,7 +81,7 @@ int parse_general(boost::property_tree::ptree pt) + } else { + configs->log_level = it->second; + } +- logger.setLogLevel(configs->log_level); ++ dfot_logger.setLogLevel(configs->log_level); + configs->sampling_strategy = pt.get("general.COLLECTOR_SAMPLING_STRATEGY"); + configs->high_load_threshold = pt.get("general.COLLECTOR_HIGH_LOAD_THRESHOLD"); + configs->collector_sampling_period = pt.get("general.COLLECTOR_SAMPLING_PERIOD"); +diff --git a/src/oeaware_plugins/instance.cc b/src/oeaware_plugins/instance.cc +index 5a5e7bf..b51c987 100644 +--- a/src/oeaware_plugins/instance.cc ++++ b/src/oeaware_plugins/instance.cc +@@ -1,12 +1,11 @@ +-#include "logs.h" ++#include + +-#include "interface.h" ++#include "logs.h" + #include "tuner.h" + +-Logger __attribute__((visibility("hidden"))) logger("D-FOT"); ++Logger __attribute__((visibility("hidden"))) dfot_logger("D-FOT"); + +-extern "C" int get_instance(struct Interface **interface) ++extern "C" void GetInstance(std::vector> &interface) + { +- *interface = &sysboost_tuner; +- return 1; ++ interface.emplace_back(std::make_shared()); + } +diff --git a/src/oeaware_plugins/tuner_sysboost.cc b/src/oeaware_plugins/tuner_sysboost.cc +index 8bca214..cfab1fc 100644 +--- a/src/oeaware_plugins/tuner_sysboost.cc ++++ b/src/oeaware_plugins/tuner_sysboost.cc +@@ -1,163 +1,163 @@ + #include ++#include ++ ++#include ++#include + + #include "logs.h" + #include "utils.h" + #include "configs.h" + #include "records.h" +-#include "interface.h" + + #include "opt.h" +- +-// 当前优化插件需要的采样数据来源于oeaware-collector采样实例PMU_CYCLES_SAMPLING +-// 本插件不显式依赖该PMU_CYCLES_SAMPLING(因为可以预置profile来优化) +-// 注意如果oeaware-collector仓库对应采样实例名字有变化时,此处也要同步修改 +-#define PMU_CYCLES_SAMPLING "pmu_cycles_sampling" ++#include "tuner.h" ++ ++// 当前优化插件需要的采样数据来源于oeaware-manager采样实例pmu_sampling_collector ++// 本插件通过订阅获取pmu_sampling_collector的采样数据,也可以预置profile来优化 ++// 注意如果oeaware-manager仓库对应采样实例名字有变化时,此处也要同步修改 ++#define DEP_INSTANCE_NAME "pmu_sampling_collector" ++// 订阅性能事件 ++#define DEP_TOPIC_NAME "cycles" + // sysboost优化插件实例名 + #define TUNER_INSTANCE_NAME "dfot_tuner_sysboost" + +-// 从collector获取ringbuf +-void get_collector_ringbuf( +- const struct Param *param, const struct DataRingBuf **ringbuf, uint64_t *cnt) ++SysboostTuner::SysboostTuner() + { +- const struct DataRingBuf *buf = nullptr; +- static int last_record_index = -1; // 记录上一次处理的ring_bufs下标 +- static uint64_t last_record_count = 0; // 记录上一次处理时采集插件的运行次数 +- +- *ringbuf = nullptr; +- *cnt = 0; +- +- // 如果插件无变化,可以快速找到对应param +- if (last_record_index >= 0 && last_record_index < param->len && +- param->ring_bufs[last_record_index] != nullptr && +- strcmp(param->ring_bufs[last_record_index]->instance_name, PMU_CYCLES_SAMPLING) == 0) { +- buf = param->ring_bufs[last_record_index]; +- } else { +- for (int i = 0; i < param->len; i++) { +- if (param->ring_bufs[i] == nullptr) { +- continue; +- } +- if (strcmp(param->ring_bufs[i]->instance_name, PMU_CYCLES_SAMPLING) == 0) { +- buf = param->ring_bufs[i]; +- last_record_index = i; +- break; +- } +- } +- } +- +- if (buf == nullptr) { +- last_record_index = -1; +- last_record_count = 0; +- return; +- } ++ // 基类参数 ++ name = TUNER_INSTANCE_NAME; ++ version = "1.0.0"; ++ description = "dfot tuner: sysboost"; ++ priority = 2; ++ type = oeaware::TUNE; ++ period = 1000; ++ ++ depTopic.instanceName = DEP_INSTANCE_NAME; ++ depTopic.topicName = DEP_TOPIC_NAME; ++ ++ processingArea = nullptr; ++ processingAreaSize = 0; ++} + +- if (buf->count > last_record_count) { +- // 数据有更新,注意DataBuf已经全部刷新的场景 +- *ringbuf = buf; +- *cnt = std::min(buf->count - last_record_count, (uint64_t)buf->buf_len); +- last_record_count = buf->count; +- } else if (buf->count < last_record_count) { +- // 异常场景 +- WARN("[run] record data count: " << last_record_count +- << " is large than " << "current count: " << buf->count); +- *ringbuf = nullptr; +- last_record_count = 0; ++SysboostTuner::~SysboostTuner() ++{ ++ if (processingArea != nullptr) { ++ free(processingArea); ++ processingArea = nullptr; ++ processingAreaSize = 0; + } + } + +-void get_sampling_data_from_collector(const struct Param *param) ++/// @brief 调优插件不需要打开topic ++/// @param topic ++/// @return ++oeaware::Result SysboostTuner::OpenTopic(const oeaware::Topic &topic) + { +- const struct DataRingBuf *ringbuf = nullptr; +- uint64_t cnt = 0; // 需要处理的DataBuf的个数,小于buf_len ++ (void)topic; ++ return oeaware::Result(OK); ++} + +- int64_t start_ts = get_current_timestamp(); ++/// @brief 调优插件不需要关闭topic ++/// @param topic ++void SysboostTuner::CloseTopic(const oeaware::Topic &topic) ++{ ++ (void)topic; ++} + +- get_collector_ringbuf(param, &ringbuf, &cnt); +- if (ringbuf == nullptr || cnt == 0) { ++/// @brief 处理依赖采集插件实例的新采样数据 ++/// @param dataList 采样数据 ++void SysboostTuner::UpdateData(const DataList &dataList) ++{ ++ if (configs == nullptr) { ++ FATAL("[update] no valid configs found"); + return; + } + +- // 从ringbuf->index开始,倒序处理cnt个DataBuf,同时校验PmuData的ts; ++ static bool processing = false; ++ if (processing) { ++ DEBUG("[update] last processing is not finished, skip"); ++ return; ++ } ++ processing = true; ++ ++ int64_t start_ts = get_current_timestamp(); + uint64_t total_samples = 0; +- for (int i = 0; i < (int)cnt; i++) { +- int index = (ringbuf->buf_len + ringbuf->index - i) % ringbuf->buf_len; +- process_pmudata((struct PmuData *)(ringbuf->buf[index].data), ringbuf->buf[index].len); +- total_samples += (uint64_t)ringbuf->buf[index].len; ++ for (unsigned long long i = 0; i < dataList.len; i++) { ++ PmuSamplingData *data = (PmuSamplingData *)(dataList.data[i]); ++ ++ // 复制一份采样数据到插件公共内存中,防止数据被覆盖, ++ // 如果内存不足,则重新申请内存 ++ if (processingArea == nullptr || ++ processingAreaSize < sizeof(PmuData) * data->len) { ++ if (processingArea != nullptr) { ++ free(processingArea); ++ } ++ processingArea = malloc(sizeof(PmuData) * data->len); ++ if (processingArea == nullptr) { ++ processingAreaSize = 0; ++ continue; ++ } ++ processingAreaSize = sizeof(PmuData) * data->len; ++ } ++ auto ret = memcpy_s( ++ processingArea, processingAreaSize, data->pmuData, sizeof(PmuData) * data->len); ++ if (ret != EOK) { ++ continue; ++ } ++ process_pmudata((PmuData *)processingArea, data->len); ++ total_samples += data->len; + } + records.processed_samples += total_samples; + + int64_t end_ts = get_current_timestamp(); +- DEBUG("[run] processing pmudata cost: " << (end_ts - start_ts) << " ms, " ++ DEBUG("[update] processing pmudata cost: " << (end_ts - start_ts) << " ms, " + << "current: " << total_samples << " samples, " + << "total: " << records.processed_samples << " samples"); ++ processing = false; + } + +-const char *sysboost_get_version() ++/// @brief 使能调优插件实例 ++/// @param param 预留参数 ++/// @return ++oeaware::Result SysboostTuner::Enable(const std::string ¶m) + { +- return "v1.0"; +-} +- +-const char *sysboost_get_name() +-{ +- return TUNER_INSTANCE_NAME; +-} +- +-const char *sysboost_get_description() +-{ +- return "dfot tuner: sysboost"; +-} +- +-const char *sysboost_get_dep() +-{ +- // 本插件启动时,不依赖采样插件,兼容使用预置profile的场景 +- // 本插件启动后,增加对PMU_CYCLES_SAMPLING的依赖,方便获取ringbuf数据 +- // configs非空即表示插件已启动 +- return configs != nullptr ? PMU_CYCLES_SAMPLING : nullptr; +-} +- +-int sysboost_get_priority() +-{ +- return 0; +-} +- +-int sysboost_get_type() +-{ +- return -1; +-} +- +-// 每隔多少ms执行一次run +-int sysboost_get_period() +-{ +- return configs != nullptr ? configs->tuner_check_period : 1000; +-} +- +-bool sysboost_enable() +-{ +- logger.init(); ++ (void)param; ++ ++ dfot_logger.init(); + + if (configs == nullptr && + parse_dfot_ini(DEFAULT_DFOT_CONFIG_PATH) != DFOT_OK) { + ERROR("[enable] instance [" << TUNER_INSTANCE_NAME << "] init configs failed"); +- return false; ++ return oeaware::Result(FAILED); + } + + if (!check_configs_valid()) { + ERROR("[enable] invalid configs"); +- return false; ++ return oeaware::Result(FAILED); + } + + if (!check_dependence_ready()) { + ERROR("[enable] dependencies are not ready"); +- return false; ++ return oeaware::Result(FAILED); + } + + reset_records(); + ++ if (Subscribe(depTopic).code != OK) { ++ ERROR("[enable] subscribe dep topic error"); ++ return oeaware::Result(FAILED); ++ } ++ + INFO("[enable] plugin instance [" << TUNER_INSTANCE_NAME << "] enabled"); +- return true; ++ return oeaware::Result(OK); + } + +-void sysboost_disable() ++/// @brief 禁用调优插件实例 ++void SysboostTuner::Disable() + { ++ if (Unsubscribe(depTopic).code != OK) { ++ ERROR("[disable] unsubscribe dep topic error"); ++ } ++ + for (auto it = configs->apps.begin(); it != configs->apps.end(); ++it) { + AppConfig *app = *it; + if (app->status != OPTIMIZED) { +@@ -167,20 +167,14 @@ void sysboost_disable() + } + + cleanup_configs(); +- INFO("[disable] plugin " << TUNER_INSTANCE_NAME << " disabled"); ++ INFO("[disable] instance [" << TUNER_INSTANCE_NAME << "] disabled"); + } + +-const struct DataRingBuf *sysboost_get_ring_buf() ++/// @brief 调优插件主逻辑 ++void SysboostTuner::Run() + { +- // 调优插件不需要向其他插件提供数据 +- return nullptr; +-} +- +-void sysboost_run(const struct Param *param) +-{ +- // 1. 刷新采样数据 +- // 2. 检查优化条件 +- // 3. 获取profile,实施优化 ++ // 1. 检查优化条件 ++ // 2. 获取profile,实施优化 + static bool optimizing = false; + + if (configs == nullptr) { +@@ -196,9 +190,6 @@ void sysboost_run(const struct Param *param) + + optimizing = true; + +- // step1: 刷新采样数据 +- get_sampling_data_from_collector(param); +- + for (auto it = configs->apps.begin(); it != configs->apps.end(); ++it) { + AppConfig *app = *it; + // step2: 检查应用是否满足优化条件 +@@ -217,17 +208,3 @@ void sysboost_run(const struct Param *param) + + optimizing = false; + } +- +-struct Interface sysboost_tuner = { +- .get_version = sysboost_get_version, +- .get_name = sysboost_get_name, +- .get_description = sysboost_get_description, +- .get_dep = sysboost_get_dep, +- .get_priority = sysboost_get_priority, +- .get_type = sysboost_get_type, +- .get_period = sysboost_get_period, +- .enable = sysboost_enable, +- .disable = sysboost_disable, +- .get_ring_buf = sysboost_get_ring_buf, +- .run = sysboost_run, +-}; +\ No newline at end of file +diff --git a/src/startup_opt.cc b/src/startup_opt.cc +index 5b2ad9c..5abb16f 100644 +--- a/src/startup_opt.cc ++++ b/src/startup_opt.cc +@@ -7,13 +7,11 @@ + #include + #include + +-#include "boost/filesystem.hpp" ++#include + +-#include "libkperf/pmu.h" +-#include "libkperf/symbol.h" ++#include ++#include + +-// D-FOT +-#include "interface.h" + #include "utils.h" + #include "configs.h" + #include "records.h" +@@ -159,7 +157,7 @@ int dump_app_addrs_to_file(AppConfig *app) + return DFOT_ERROR; + } + +- // 当前仅处理PMU_CYCLES_SAMPLING数据,性能事件固定为cycles ++ // 当前仅处理pmu_sampling_collector数据,性能事件固定为cycles + fprintf(fp, "cycles\n"); + for (auto it = app->profile.addrs.begin(); it != app->profile.addrs.end(); ++it) { + fprintf(fp, "%lx %d\n", it->first, it->second.count); +@@ -265,7 +263,7 @@ void dump_app_profile_to_file(AppConfig *app) + ERROR("[run] fopen " << app->collected_profile << " error"); + return; + } +- // 当前仅处理PMU_CYCLES_SAMPLING数据,性能事件固定为cycles ++ // 当前仅处理pmu_sampling_collector数据,性能事件固定为cycles + fprintf(fp, "no_lbr cycles:\n"); + for (auto it1 = app->profile.funcs.begin(); it1 != app->profile.funcs.end(); ++it1) { + for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) { +@@ -411,7 +409,7 @@ void process_pmudata(struct PmuData *data, int len) + } + + for (AppConfig* app : updated_apps) { +- DEBUG("[run] collected addrs for [" << app->app_name ++ DEBUG("[update] collected addrs for [" << app->app_name + << ": " << app->instances.size() - 1 << "]: " + << app->profile.addrs.size()); + +-- +2.39.5 (Apple Git-154) + diff --git a/0003-adapt-include-dir-for-oeaware.patch b/0003-adapt-include-dir-for-oeaware.patch new file mode 100644 index 0000000..03ee774 --- /dev/null +++ b/0003-adapt-include-dir-for-oeaware.patch @@ -0,0 +1,80 @@ +From 80257a974c20bb8c966e310aedb2aff3faaed94f Mon Sep 17 00:00:00 2001 +From: rfwang07 +Date: Sat, 7 Dec 2024 14:48:47 +0800 +Subject: [PATCH] adapt include dir for oeaware + +--- + CMakeLists.txt | 4 ---- + include/tuner.h | 4 ++-- + src/oeaware_plugins/instance.cc | 2 +- + src/oeaware_plugins/tuner_sysboost.cc | 7 ++++--- + 4 files changed, 7 insertions(+), 10 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index dda676e..0dd5c51 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -32,10 +32,6 @@ add_library(dfot SHARED ${dfot_tuner_sysboost_src}) + + include_directories(dfot PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/include +- # 因为oeAware头文件问题,此处临时适配 +- /usr/include/libkperf +- /usr/include/oeaware +- /usr/include/oeaware/interface + ) + + target_link_libraries(dfot boundscheck kperf sym dl log4cplus boost_system boost_filesystem) +diff --git a/include/tuner.h b/include/tuner.h +index 46db4f7..b72cc3c 100644 +--- a/include/tuner.h ++++ b/include/tuner.h +@@ -13,8 +13,8 @@ + #define __TUNER_H__ + + #include +-#include +-#include ++#include ++#include + + class SysboostTuner : public oeaware::Interface { + public: +diff --git a/src/oeaware_plugins/instance.cc b/src/oeaware_plugins/instance.cc +index b51c987..767b1aa 100644 +--- a/src/oeaware_plugins/instance.cc ++++ b/src/oeaware_plugins/instance.cc +@@ -1,4 +1,4 @@ +-#include ++#include + + #include "logs.h" + #include "tuner.h" +diff --git a/src/oeaware_plugins/tuner_sysboost.cc b/src/oeaware_plugins/tuner_sysboost.cc +index cfab1fc..0c99a5a 100644 +--- a/src/oeaware_plugins/tuner_sysboost.cc ++++ b/src/oeaware_plugins/tuner_sysboost.cc +@@ -1,8 +1,9 @@ + #include + #include + +-#include +-#include ++#include ++#include ++#include + + #include "logs.h" + #include "utils.h" +@@ -15,7 +16,7 @@ + // 当前优化插件需要的采样数据来源于oeaware-manager采样实例pmu_sampling_collector + // 本插件通过订阅获取pmu_sampling_collector的采样数据,也可以预置profile来优化 + // 注意如果oeaware-manager仓库对应采样实例名字有变化时,此处也要同步修改 +-#define DEP_INSTANCE_NAME "pmu_sampling_collector" ++#define DEP_INSTANCE_NAME OE_PMU_SAMPLING_COLLECTOR + // 订阅性能事件 + #define DEP_TOPIC_NAME "cycles" + // sysboost优化插件实例名 +-- +2.39.5 (Apple Git-154) + diff --git a/D-FOT.spec b/D-FOT.spec index 669f6a0..0ea5496 100644 --- a/D-FOT.spec +++ b/D-FOT.spec @@ -1,49 +1,31 @@ Name: D-FOT Version: v1.0.1 -Release: 1 +Release: 2 Summary: %{name} is a dynamic feedback-directed optimization tool for openEuler. License: Mulan PSL v2 URL: https://gitee.com/openeuler/%{name} Source0: %{name}-%{version}.tar.gz -BuildRequires: cmake make gcc-c++ boost-devel log4cplus-devel numactl-devel -BuildRequires: git +Patch1: 0001-update-libkperf-dependence.patch +Patch2: 0002-adapt-the-code-for-oeaware-2.0.patch +Patch3: 0003-adapt-include-dir-for-oeaware.patch -Requires: oeAware-manager llvm-bolt +BuildRequires: cmake make gcc-c++ +BuildRequires: boost-devel log4cplus-devel numactl-devel libkperf-devel oeAware-manager-devel +Requires: log4cplus boost libboundscheck oeAware-manager libkperf llvm-bolt ExclusiveArch: aarch64 -%global libkperf_name libkperf -%global libkperf_tagver v1.2.1 -%global libkperf_source https://gitee.com/openeuler/libkperf.git - %description %{name} is a dynamic feedback-directed optimization tool for openEuler. %prep -%autosetup -n %{name}-%{version} -mkdir thirdparty && cd thirdparty -git clone --recurse-submodules %{libkperf_source} -cd %{libkperf_name} -git checkout %{libkperf_tagver} -cd .. -mv %{libkperf_name} %{libkperf_name}-%{libkperf_tagver} -cd .. +%autosetup -n %{name}-%{version} -p1 %build -# build libkperf.so -cd thirdparty/%{libkperf_name}-%{libkperf_tagver} -sh build.sh -cd ../../ - -# build libdfot.so mkdir build && cd build -cmake .. \ - -DLIB_KPERF_LIBPATH=%{_builddir}/%{name}-%{version}/thirdparty/%{libkperf_name}-%{libkperf_tagver}/output/lib \ - -DLIB_KPERF_INCPATH=%{_builddir}/%{name}-%{version}/thirdparty/%{libkperf_name}-%{libkperf_tagver}/output/include \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo \ - -DCMAKE_SKIP_RPATH=TRUE +%{cmake} .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_SKIP_RPATH=TRUE make %install @@ -58,6 +40,11 @@ install -D -m 0640 ./configs/dfot.ini ${RPM_BUILD_ROOT}/etc/dfot/ %attr(0440,root,root) %{_libdir}/oeAware-plugin/libdfot.so %changelog +* Tue Dec 3 2024 rfwang07 - v1.0.1-2 +- ID:NA +- SUG:NA +- DESC: update libkperf dependence and adapt code for oeaware 2.0 + * Wed Nov 27 2024 rfwang07 - v1.0.1-1 - ID:NA - SUG:NA -- Gitee From edbb41b8ffbacc51e9c478fd94ce2224665caae3 Mon Sep 17 00:00:00 2001 From: rfwang07 Date: Tue, 10 Dec 2024 09:53:35 +0800 Subject: [PATCH 2/4] update to v1.0.2 --- 0001-update-libkperf-dependence.patch | 70 --- 0002-adapt-the-code-for-oeaware-2.0.patch | 626 ---------------------- 0003-adapt-include-dir-for-oeaware.patch | 80 --- D-FOT-v1.0.1.tar.gz | Bin 20382 -> 0 bytes D-FOT-v1.0.2.tar.gz | Bin 0 -> 19843 bytes D-FOT.spec | 13 +- 6 files changed, 7 insertions(+), 782 deletions(-) delete mode 100644 0001-update-libkperf-dependence.patch delete mode 100644 0002-adapt-the-code-for-oeaware-2.0.patch delete mode 100644 0003-adapt-include-dir-for-oeaware.patch delete mode 100644 D-FOT-v1.0.1.tar.gz create mode 100644 D-FOT-v1.0.2.tar.gz diff --git a/0001-update-libkperf-dependence.patch b/0001-update-libkperf-dependence.patch deleted file mode 100644 index a7a4170..0000000 --- a/0001-update-libkperf-dependence.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 2cd49e73b30659f6faa9ff439083506f0ccec712 Mon Sep 17 00:00:00 2001 -From: rfwang07 -Date: Tue, 3 Dec 2024 15:40:47 +0800 -Subject: [PATCH] update libkperf dependence - ---- - CMakeLists.txt | 9 --------- - include/opt.h | 2 +- - src/startup_opt.cc | 5 ++--- - 3 files changed, 3 insertions(+), 13 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 00675c2..df8006e 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -19,10 +19,6 @@ endif() - - add_compile_options(-fPIC -Wall -Wextra) - --# libkperf --message("-- libkperf library path: ${LIB_KPERF_LIBPATH}") --message("-- libkperf include path: ${LIB_KPERF_INCPATH}") -- - set(dfot_tuner_sysboost_src - src/oeaware_plugins/instance.cc - src/oeaware_plugins/tuner_sysboost.cc -@@ -37,11 +33,6 @@ add_library(dfot SHARED ${dfot_tuner_sysboost_src}) - - include_directories(dfot PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/include -- ${LIB_KPERF_INCPATH} --) -- --target_link_directories(dfot PUBLIC -- ${LIB_KPERF_LIBPATH} - ) - - target_link_libraries(dfot kperf sym dl log4cplus boost_system boost_filesystem) -diff --git a/include/opt.h b/include/opt.h -index f998501..2c40cbe 100644 ---- a/include/opt.h -+++ b/include/opt.h -@@ -14,7 +14,7 @@ - - #include - --#include "pmu.h" -+#include "libkperf/pmu.h" - #include "configs.h" - - extern bool check_dependence_ready(); -diff --git a/src/startup_opt.cc b/src/startup_opt.cc -index b408205..5b2ad9c 100644 ---- a/src/startup_opt.cc -+++ b/src/startup_opt.cc -@@ -9,9 +9,8 @@ - - #include "boost/filesystem.hpp" - --// libkperf --#include "pmu.h" --#include "symbol.h" -+#include "libkperf/pmu.h" -+#include "libkperf/symbol.h" - - // D-FOT - #include "interface.h" --- -2.39.5 (Apple Git-154) - diff --git a/0002-adapt-the-code-for-oeaware-2.0.patch b/0002-adapt-the-code-for-oeaware-2.0.patch deleted file mode 100644 index 8e5314a..0000000 --- a/0002-adapt-the-code-for-oeaware-2.0.patch +++ /dev/null @@ -1,626 +0,0 @@ -From 82bd0304d05a4f4c7ca913eab7d0863912bccfa3 Mon Sep 17 00:00:00 2001 -From: rfwang07 -Date: Tue, 3 Dec 2024 23:05:06 +0800 -Subject: [PATCH] adapt the code for oeaware 2.0 - ---- - CMakeLists.txt | 11 +- - include/interface.h | 74 -------- - include/logs.h | 12 +- - include/opt.h | 2 +- - include/tuner.h | 21 ++- - src/configs.cc | 2 +- - src/oeaware_plugins/instance.cc | 11 +- - src/oeaware_plugins/tuner_sysboost.cc | 249 ++++++++++++-------------- - src/startup_opt.cc | 14 +- - 9 files changed, 158 insertions(+), 238 deletions(-) - delete mode 100644 include/interface.h - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index df8006e..dda676e 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -1,8 +1,6 @@ - cmake_minimum_required(VERSION 3.15) - project(D-FOT) - --set(CMAKE_CXX_STANDARD 11) -- - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - message("-- Build type: Debug") - add_compile_options(-g3 -O0) -@@ -17,7 +15,7 @@ else() - add_compile_options(-O3) - endif() - --add_compile_options(-fPIC -Wall -Wextra) -+add_compile_options(-std=c++17 -fPIC -Wall -Wextra) - - set(dfot_tuner_sysboost_src - src/oeaware_plugins/instance.cc -@@ -31,8 +29,13 @@ set(dfot_tuner_sysboost_src - - add_library(dfot SHARED ${dfot_tuner_sysboost_src}) - -+ - include_directories(dfot PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/include -+ # 因为oeAware头文件问题,此处临时适配 -+ /usr/include/libkperf -+ /usr/include/oeaware -+ /usr/include/oeaware/interface - ) - --target_link_libraries(dfot kperf sym dl log4cplus boost_system boost_filesystem) -+target_link_libraries(dfot boundscheck kperf sym dl log4cplus boost_system boost_filesystem) -diff --git a/include/interface.h b/include/interface.h -deleted file mode 100644 -index 0a49743..0000000 ---- a/include/interface.h -+++ /dev/null -@@ -1,74 +0,0 @@ --/****************************************************************************** -- * Copyright (c) 2024 Huawei Technologies Co., Ltd. -- * oeAware is licensed under Mulan PSL v2. -- * You can use this software according to the terms and conditions of the Mulan PSL v2. -- * You may obtain a copy of Mulan PSL v2 at: -- * http://license.coscl.org.cn/MulanPSL2 -- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, -- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, -- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -- * See the Mulan PSL v2 for more details. -- ******************************************************************************/ --#ifndef __INTERFACE_H__ --#define __INTERFACE_H__ -- --#include --#include -- --#ifdef __cplusplus --extern "C" { --#endif -- --struct DataBuf { -- int len; -- void *data; --}; -- --struct DataRingBuf { -- /* instance name */ -- const char *instance_name; -- /* buf write index, initial value is -1 */ -- int index; -- /* instance run times */ -- uint64_t count; -- struct DataBuf *buf; -- int buf_len; --}; -- --struct Param { -- const struct DataRingBuf **ring_bufs; -- int len; --}; -- --struct Interface { -- const char* (*get_version)(); -- /* The instance name is a unique identifier in the system. */ -- const char* (*get_name)(); -- const char* (*get_description)(); -- /* Specifies the instance dependencies, which is used as the input information -- * for instance execution. -- */ -- const char* (*get_dep)(); -- /* Instance scheduling priority. In a uniform time period, a instance with a -- * lower priority is scheduled first. -- */ -- int (*get_priority)(); -- int (*get_type)(); -- /* Instance execution period. */ -- int (*get_period)(); -- bool (*enable)(); -- void (*disable)(); -- const struct DataRingBuf* (*get_ring_buf)(); -- void (*run)(const struct Param*); --}; -- --/* Obtains the instances from the plugin. -- * The return value is the number of instances. -- */ --int get_instance(struct Interface **interface); -- --#ifdef __cplusplus --} --#endif -- --#endif -diff --git a/include/logs.h b/include/logs.h -index f27d289..331060c 100644 ---- a/include/logs.h -+++ b/include/logs.h -@@ -22,11 +22,11 @@ - - #define DFOT_LOG_PATH "/etc/dfot/dfot.log" - --#define DEBUG(fmt) LOG4CPLUS_DEBUG(logger.get(), fmt) --#define INFO(fmt) LOG4CPLUS_INFO(logger.get(), fmt) --#define WARN(fmt) LOG4CPLUS_WARN(logger.get(), fmt) --#define ERROR(fmt) LOG4CPLUS_ERROR(logger.get(), fmt) --#define FATAL(fmt) LOG4CPLUS_FATAL(logger.get(), fmt) -+#define DEBUG(fmt) LOG4CPLUS_DEBUG(dfot_logger.get(), fmt) -+#define INFO(fmt) LOG4CPLUS_INFO(dfot_logger.get(), fmt) -+#define WARN(fmt) LOG4CPLUS_WARN(dfot_logger.get(), fmt) -+#define ERROR(fmt) LOG4CPLUS_ERROR(dfot_logger.get(), fmt) -+#define FATAL(fmt) LOG4CPLUS_FATAL(dfot_logger.get(), fmt) - - static std::map LOG_LEVEL = { - {"DEBUG", log4cplus::DEBUG_LOG_LEVEL}, -@@ -51,6 +51,6 @@ private: - log4cplus::Initializer initializer; - }; - --extern Logger logger; -+extern Logger dfot_logger; - - #endif -diff --git a/include/opt.h b/include/opt.h -index 2c40cbe..ff0241b 100644 ---- a/include/opt.h -+++ b/include/opt.h -@@ -14,7 +14,7 @@ - - #include - --#include "libkperf/pmu.h" -+#include - #include "configs.h" - - extern bool check_dependence_ready(); -diff --git a/include/tuner.h b/include/tuner.h -index 326615c..46db4f7 100644 ---- a/include/tuner.h -+++ b/include/tuner.h -@@ -12,8 +12,25 @@ - #ifndef __TUNER_H__ - #define __TUNER_H__ - --#include "interface.h" -+#include -+#include -+#include - --extern struct Interface sysboost_tuner; -+class SysboostTuner : public oeaware::Interface { -+public: -+ SysboostTuner(); -+ ~SysboostTuner(); -+ oeaware::Result OpenTopic(const oeaware::Topic &topic) override; -+ void CloseTopic(const oeaware::Topic &topic) override; -+ void UpdateData(const DataList &dataList) override; -+ oeaware::Result Enable(const std::string ¶m) override; -+ void Disable() override; -+ void Run() override; -+ -+private: -+ oeaware::Topic depTopic; -+ void *processingArea; -+ size_t processingAreaSize; -+}; - - #endif -diff --git a/src/configs.cc b/src/configs.cc -index 9cc0c38..9aa6d36 100644 ---- a/src/configs.cc -+++ b/src/configs.cc -@@ -81,7 +81,7 @@ int parse_general(boost::property_tree::ptree pt) - } else { - configs->log_level = it->second; - } -- logger.setLogLevel(configs->log_level); -+ dfot_logger.setLogLevel(configs->log_level); - configs->sampling_strategy = pt.get("general.COLLECTOR_SAMPLING_STRATEGY"); - configs->high_load_threshold = pt.get("general.COLLECTOR_HIGH_LOAD_THRESHOLD"); - configs->collector_sampling_period = pt.get("general.COLLECTOR_SAMPLING_PERIOD"); -diff --git a/src/oeaware_plugins/instance.cc b/src/oeaware_plugins/instance.cc -index 5a5e7bf..b51c987 100644 ---- a/src/oeaware_plugins/instance.cc -+++ b/src/oeaware_plugins/instance.cc -@@ -1,12 +1,11 @@ --#include "logs.h" -+#include - --#include "interface.h" -+#include "logs.h" - #include "tuner.h" - --Logger __attribute__((visibility("hidden"))) logger("D-FOT"); -+Logger __attribute__((visibility("hidden"))) dfot_logger("D-FOT"); - --extern "C" int get_instance(struct Interface **interface) -+extern "C" void GetInstance(std::vector> &interface) - { -- *interface = &sysboost_tuner; -- return 1; -+ interface.emplace_back(std::make_shared()); - } -diff --git a/src/oeaware_plugins/tuner_sysboost.cc b/src/oeaware_plugins/tuner_sysboost.cc -index 8bca214..cfab1fc 100644 ---- a/src/oeaware_plugins/tuner_sysboost.cc -+++ b/src/oeaware_plugins/tuner_sysboost.cc -@@ -1,163 +1,163 @@ - #include -+#include -+ -+#include -+#include - - #include "logs.h" - #include "utils.h" - #include "configs.h" - #include "records.h" --#include "interface.h" - - #include "opt.h" -- --// 当前优化插件需要的采样数据来源于oeaware-collector采样实例PMU_CYCLES_SAMPLING --// 本插件不显式依赖该PMU_CYCLES_SAMPLING(因为可以预置profile来优化) --// 注意如果oeaware-collector仓库对应采样实例名字有变化时,此处也要同步修改 --#define PMU_CYCLES_SAMPLING "pmu_cycles_sampling" -+#include "tuner.h" -+ -+// 当前优化插件需要的采样数据来源于oeaware-manager采样实例pmu_sampling_collector -+// 本插件通过订阅获取pmu_sampling_collector的采样数据,也可以预置profile来优化 -+// 注意如果oeaware-manager仓库对应采样实例名字有变化时,此处也要同步修改 -+#define DEP_INSTANCE_NAME "pmu_sampling_collector" -+// 订阅性能事件 -+#define DEP_TOPIC_NAME "cycles" - // sysboost优化插件实例名 - #define TUNER_INSTANCE_NAME "dfot_tuner_sysboost" - --// 从collector获取ringbuf --void get_collector_ringbuf( -- const struct Param *param, const struct DataRingBuf **ringbuf, uint64_t *cnt) -+SysboostTuner::SysboostTuner() - { -- const struct DataRingBuf *buf = nullptr; -- static int last_record_index = -1; // 记录上一次处理的ring_bufs下标 -- static uint64_t last_record_count = 0; // 记录上一次处理时采集插件的运行次数 -- -- *ringbuf = nullptr; -- *cnt = 0; -- -- // 如果插件无变化,可以快速找到对应param -- if (last_record_index >= 0 && last_record_index < param->len && -- param->ring_bufs[last_record_index] != nullptr && -- strcmp(param->ring_bufs[last_record_index]->instance_name, PMU_CYCLES_SAMPLING) == 0) { -- buf = param->ring_bufs[last_record_index]; -- } else { -- for (int i = 0; i < param->len; i++) { -- if (param->ring_bufs[i] == nullptr) { -- continue; -- } -- if (strcmp(param->ring_bufs[i]->instance_name, PMU_CYCLES_SAMPLING) == 0) { -- buf = param->ring_bufs[i]; -- last_record_index = i; -- break; -- } -- } -- } -- -- if (buf == nullptr) { -- last_record_index = -1; -- last_record_count = 0; -- return; -- } -+ // 基类参数 -+ name = TUNER_INSTANCE_NAME; -+ version = "1.0.0"; -+ description = "dfot tuner: sysboost"; -+ priority = 2; -+ type = oeaware::TUNE; -+ period = 1000; -+ -+ depTopic.instanceName = DEP_INSTANCE_NAME; -+ depTopic.topicName = DEP_TOPIC_NAME; -+ -+ processingArea = nullptr; -+ processingAreaSize = 0; -+} - -- if (buf->count > last_record_count) { -- // 数据有更新,注意DataBuf已经全部刷新的场景 -- *ringbuf = buf; -- *cnt = std::min(buf->count - last_record_count, (uint64_t)buf->buf_len); -- last_record_count = buf->count; -- } else if (buf->count < last_record_count) { -- // 异常场景 -- WARN("[run] record data count: " << last_record_count -- << " is large than " << "current count: " << buf->count); -- *ringbuf = nullptr; -- last_record_count = 0; -+SysboostTuner::~SysboostTuner() -+{ -+ if (processingArea != nullptr) { -+ free(processingArea); -+ processingArea = nullptr; -+ processingAreaSize = 0; - } - } - --void get_sampling_data_from_collector(const struct Param *param) -+/// @brief 调优插件不需要打开topic -+/// @param topic -+/// @return -+oeaware::Result SysboostTuner::OpenTopic(const oeaware::Topic &topic) - { -- const struct DataRingBuf *ringbuf = nullptr; -- uint64_t cnt = 0; // 需要处理的DataBuf的个数,小于buf_len -+ (void)topic; -+ return oeaware::Result(OK); -+} - -- int64_t start_ts = get_current_timestamp(); -+/// @brief 调优插件不需要关闭topic -+/// @param topic -+void SysboostTuner::CloseTopic(const oeaware::Topic &topic) -+{ -+ (void)topic; -+} - -- get_collector_ringbuf(param, &ringbuf, &cnt); -- if (ringbuf == nullptr || cnt == 0) { -+/// @brief 处理依赖采集插件实例的新采样数据 -+/// @param dataList 采样数据 -+void SysboostTuner::UpdateData(const DataList &dataList) -+{ -+ if (configs == nullptr) { -+ FATAL("[update] no valid configs found"); - return; - } - -- // 从ringbuf->index开始,倒序处理cnt个DataBuf,同时校验PmuData的ts; -+ static bool processing = false; -+ if (processing) { -+ DEBUG("[update] last processing is not finished, skip"); -+ return; -+ } -+ processing = true; -+ -+ int64_t start_ts = get_current_timestamp(); - uint64_t total_samples = 0; -- for (int i = 0; i < (int)cnt; i++) { -- int index = (ringbuf->buf_len + ringbuf->index - i) % ringbuf->buf_len; -- process_pmudata((struct PmuData *)(ringbuf->buf[index].data), ringbuf->buf[index].len); -- total_samples += (uint64_t)ringbuf->buf[index].len; -+ for (unsigned long long i = 0; i < dataList.len; i++) { -+ PmuSamplingData *data = (PmuSamplingData *)(dataList.data[i]); -+ -+ // 复制一份采样数据到插件公共内存中,防止数据被覆盖, -+ // 如果内存不足,则重新申请内存 -+ if (processingArea == nullptr || -+ processingAreaSize < sizeof(PmuData) * data->len) { -+ if (processingArea != nullptr) { -+ free(processingArea); -+ } -+ processingArea = malloc(sizeof(PmuData) * data->len); -+ if (processingArea == nullptr) { -+ processingAreaSize = 0; -+ continue; -+ } -+ processingAreaSize = sizeof(PmuData) * data->len; -+ } -+ auto ret = memcpy_s( -+ processingArea, processingAreaSize, data->pmuData, sizeof(PmuData) * data->len); -+ if (ret != EOK) { -+ continue; -+ } -+ process_pmudata((PmuData *)processingArea, data->len); -+ total_samples += data->len; - } - records.processed_samples += total_samples; - - int64_t end_ts = get_current_timestamp(); -- DEBUG("[run] processing pmudata cost: " << (end_ts - start_ts) << " ms, " -+ DEBUG("[update] processing pmudata cost: " << (end_ts - start_ts) << " ms, " - << "current: " << total_samples << " samples, " - << "total: " << records.processed_samples << " samples"); -+ processing = false; - } - --const char *sysboost_get_version() -+/// @brief 使能调优插件实例 -+/// @param param 预留参数 -+/// @return -+oeaware::Result SysboostTuner::Enable(const std::string ¶m) - { -- return "v1.0"; --} -- --const char *sysboost_get_name() --{ -- return TUNER_INSTANCE_NAME; --} -- --const char *sysboost_get_description() --{ -- return "dfot tuner: sysboost"; --} -- --const char *sysboost_get_dep() --{ -- // 本插件启动时,不依赖采样插件,兼容使用预置profile的场景 -- // 本插件启动后,增加对PMU_CYCLES_SAMPLING的依赖,方便获取ringbuf数据 -- // configs非空即表示插件已启动 -- return configs != nullptr ? PMU_CYCLES_SAMPLING : nullptr; --} -- --int sysboost_get_priority() --{ -- return 0; --} -- --int sysboost_get_type() --{ -- return -1; --} -- --// 每隔多少ms执行一次run --int sysboost_get_period() --{ -- return configs != nullptr ? configs->tuner_check_period : 1000; --} -- --bool sysboost_enable() --{ -- logger.init(); -+ (void)param; -+ -+ dfot_logger.init(); - - if (configs == nullptr && - parse_dfot_ini(DEFAULT_DFOT_CONFIG_PATH) != DFOT_OK) { - ERROR("[enable] instance [" << TUNER_INSTANCE_NAME << "] init configs failed"); -- return false; -+ return oeaware::Result(FAILED); - } - - if (!check_configs_valid()) { - ERROR("[enable] invalid configs"); -- return false; -+ return oeaware::Result(FAILED); - } - - if (!check_dependence_ready()) { - ERROR("[enable] dependencies are not ready"); -- return false; -+ return oeaware::Result(FAILED); - } - - reset_records(); - -+ if (Subscribe(depTopic).code != OK) { -+ ERROR("[enable] subscribe dep topic error"); -+ return oeaware::Result(FAILED); -+ } -+ - INFO("[enable] plugin instance [" << TUNER_INSTANCE_NAME << "] enabled"); -- return true; -+ return oeaware::Result(OK); - } - --void sysboost_disable() -+/// @brief 禁用调优插件实例 -+void SysboostTuner::Disable() - { -+ if (Unsubscribe(depTopic).code != OK) { -+ ERROR("[disable] unsubscribe dep topic error"); -+ } -+ - for (auto it = configs->apps.begin(); it != configs->apps.end(); ++it) { - AppConfig *app = *it; - if (app->status != OPTIMIZED) { -@@ -167,20 +167,14 @@ void sysboost_disable() - } - - cleanup_configs(); -- INFO("[disable] plugin " << TUNER_INSTANCE_NAME << " disabled"); -+ INFO("[disable] instance [" << TUNER_INSTANCE_NAME << "] disabled"); - } - --const struct DataRingBuf *sysboost_get_ring_buf() -+/// @brief 调优插件主逻辑 -+void SysboostTuner::Run() - { -- // 调优插件不需要向其他插件提供数据 -- return nullptr; --} -- --void sysboost_run(const struct Param *param) --{ -- // 1. 刷新采样数据 -- // 2. 检查优化条件 -- // 3. 获取profile,实施优化 -+ // 1. 检查优化条件 -+ // 2. 获取profile,实施优化 - static bool optimizing = false; - - if (configs == nullptr) { -@@ -196,9 +190,6 @@ void sysboost_run(const struct Param *param) - - optimizing = true; - -- // step1: 刷新采样数据 -- get_sampling_data_from_collector(param); -- - for (auto it = configs->apps.begin(); it != configs->apps.end(); ++it) { - AppConfig *app = *it; - // step2: 检查应用是否满足优化条件 -@@ -217,17 +208,3 @@ void sysboost_run(const struct Param *param) - - optimizing = false; - } -- --struct Interface sysboost_tuner = { -- .get_version = sysboost_get_version, -- .get_name = sysboost_get_name, -- .get_description = sysboost_get_description, -- .get_dep = sysboost_get_dep, -- .get_priority = sysboost_get_priority, -- .get_type = sysboost_get_type, -- .get_period = sysboost_get_period, -- .enable = sysboost_enable, -- .disable = sysboost_disable, -- .get_ring_buf = sysboost_get_ring_buf, -- .run = sysboost_run, --}; -\ No newline at end of file -diff --git a/src/startup_opt.cc b/src/startup_opt.cc -index 5b2ad9c..5abb16f 100644 ---- a/src/startup_opt.cc -+++ b/src/startup_opt.cc -@@ -7,13 +7,11 @@ - #include - #include - --#include "boost/filesystem.hpp" -+#include - --#include "libkperf/pmu.h" --#include "libkperf/symbol.h" -+#include -+#include - --// D-FOT --#include "interface.h" - #include "utils.h" - #include "configs.h" - #include "records.h" -@@ -159,7 +157,7 @@ int dump_app_addrs_to_file(AppConfig *app) - return DFOT_ERROR; - } - -- // 当前仅处理PMU_CYCLES_SAMPLING数据,性能事件固定为cycles -+ // 当前仅处理pmu_sampling_collector数据,性能事件固定为cycles - fprintf(fp, "cycles\n"); - for (auto it = app->profile.addrs.begin(); it != app->profile.addrs.end(); ++it) { - fprintf(fp, "%lx %d\n", it->first, it->second.count); -@@ -265,7 +263,7 @@ void dump_app_profile_to_file(AppConfig *app) - ERROR("[run] fopen " << app->collected_profile << " error"); - return; - } -- // 当前仅处理PMU_CYCLES_SAMPLING数据,性能事件固定为cycles -+ // 当前仅处理pmu_sampling_collector数据,性能事件固定为cycles - fprintf(fp, "no_lbr cycles:\n"); - for (auto it1 = app->profile.funcs.begin(); it1 != app->profile.funcs.end(); ++it1) { - for (auto it2 = it1->second.begin(); it2 != it1->second.end(); ++it2) { -@@ -411,7 +409,7 @@ void process_pmudata(struct PmuData *data, int len) - } - - for (AppConfig* app : updated_apps) { -- DEBUG("[run] collected addrs for [" << app->app_name -+ DEBUG("[update] collected addrs for [" << app->app_name - << ": " << app->instances.size() - 1 << "]: " - << app->profile.addrs.size()); - --- -2.39.5 (Apple Git-154) - diff --git a/0003-adapt-include-dir-for-oeaware.patch b/0003-adapt-include-dir-for-oeaware.patch deleted file mode 100644 index 03ee774..0000000 --- a/0003-adapt-include-dir-for-oeaware.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 80257a974c20bb8c966e310aedb2aff3faaed94f Mon Sep 17 00:00:00 2001 -From: rfwang07 -Date: Sat, 7 Dec 2024 14:48:47 +0800 -Subject: [PATCH] adapt include dir for oeaware - ---- - CMakeLists.txt | 4 ---- - include/tuner.h | 4 ++-- - src/oeaware_plugins/instance.cc | 2 +- - src/oeaware_plugins/tuner_sysboost.cc | 7 ++++--- - 4 files changed, 7 insertions(+), 10 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index dda676e..0dd5c51 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -32,10 +32,6 @@ add_library(dfot SHARED ${dfot_tuner_sysboost_src}) - - include_directories(dfot PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/include -- # 因为oeAware头文件问题,此处临时适配 -- /usr/include/libkperf -- /usr/include/oeaware -- /usr/include/oeaware/interface - ) - - target_link_libraries(dfot boundscheck kperf sym dl log4cplus boost_system boost_filesystem) -diff --git a/include/tuner.h b/include/tuner.h -index 46db4f7..b72cc3c 100644 ---- a/include/tuner.h -+++ b/include/tuner.h -@@ -13,8 +13,8 @@ - #define __TUNER_H__ - - #include --#include --#include -+#include -+#include - - class SysboostTuner : public oeaware::Interface { - public: -diff --git a/src/oeaware_plugins/instance.cc b/src/oeaware_plugins/instance.cc -index b51c987..767b1aa 100644 ---- a/src/oeaware_plugins/instance.cc -+++ b/src/oeaware_plugins/instance.cc -@@ -1,4 +1,4 @@ --#include -+#include - - #include "logs.h" - #include "tuner.h" -diff --git a/src/oeaware_plugins/tuner_sysboost.cc b/src/oeaware_plugins/tuner_sysboost.cc -index cfab1fc..0c99a5a 100644 ---- a/src/oeaware_plugins/tuner_sysboost.cc -+++ b/src/oeaware_plugins/tuner_sysboost.cc -@@ -1,8 +1,9 @@ - #include - #include - --#include --#include -+#include -+#include -+#include - - #include "logs.h" - #include "utils.h" -@@ -15,7 +16,7 @@ - // 当前优化插件需要的采样数据来源于oeaware-manager采样实例pmu_sampling_collector - // 本插件通过订阅获取pmu_sampling_collector的采样数据,也可以预置profile来优化 - // 注意如果oeaware-manager仓库对应采样实例名字有变化时,此处也要同步修改 --#define DEP_INSTANCE_NAME "pmu_sampling_collector" -+#define DEP_INSTANCE_NAME OE_PMU_SAMPLING_COLLECTOR - // 订阅性能事件 - #define DEP_TOPIC_NAME "cycles" - // sysboost优化插件实例名 --- -2.39.5 (Apple Git-154) - diff --git a/D-FOT-v1.0.1.tar.gz b/D-FOT-v1.0.1.tar.gz deleted file mode 100644 index 5f60da1f323be37105aecebd82d458d03b032940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20382 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 literal 0 HcmV?d00001 diff --git a/D-FOT.spec b/D-FOT.spec index 0ea5496..cc9a8bb 100644 --- a/D-FOT.spec +++ b/D-FOT.spec @@ -1,16 +1,12 @@ Name: D-FOT -Version: v1.0.1 -Release: 2 +Version: v1.0.2 +Release: 1 Summary: %{name} is a dynamic feedback-directed optimization tool for openEuler. License: Mulan PSL v2 URL: https://gitee.com/openeuler/%{name} Source0: %{name}-%{version}.tar.gz -Patch1: 0001-update-libkperf-dependence.patch -Patch2: 0002-adapt-the-code-for-oeaware-2.0.patch -Patch3: 0003-adapt-include-dir-for-oeaware.patch - BuildRequires: cmake make gcc-c++ BuildRequires: boost-devel log4cplus-devel numactl-devel libkperf-devel oeAware-manager-devel Requires: log4cplus boost libboundscheck oeAware-manager libkperf llvm-bolt @@ -40,6 +36,11 @@ install -D -m 0640 ./configs/dfot.ini ${RPM_BUILD_ROOT}/etc/dfot/ %attr(0440,root,root) %{_libdir}/oeAware-plugin/libdfot.so %changelog +* Tue Dec 10 2024 rfwang07 - v1.0.2-1 +- ID:NA +- SUG:NA +- DESC: fix pmudata processing bugs and add execution check + * Tue Dec 3 2024 rfwang07 - v1.0.1-2 - ID:NA - SUG:NA -- Gitee From 70845f2d9118faac0e7e0704a38b29350c9b4873 Mon Sep 17 00:00:00 2001 From: rfwang07 Date: Wed, 11 Dec 2024 09:07:47 +0800 Subject: [PATCH 3/4] filter so address pmudata --- 0001-filter-so-address-pmudata.patch | 127 +++++++++++++++++++++++++++ D-FOT.spec | 9 +- 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 0001-filter-so-address-pmudata.patch diff --git a/0001-filter-so-address-pmudata.patch b/0001-filter-so-address-pmudata.patch new file mode 100644 index 0000000..5f4ab93 --- /dev/null +++ b/0001-filter-so-address-pmudata.patch @@ -0,0 +1,127 @@ +From bfbec494a98f6b872b7449c4f641d2a94942d84b Mon Sep 17 00:00:00 2001 +From: rfwang07 +Date: Tue, 10 Dec 2024 16:06:31 +0800 +Subject: [PATCH] filter so address pmudata + +--- + include/records.h | 1 + + src/configs.cc | 4 +++- + src/oeaware_plugins/tuner_sysboost.cc | 1 + + src/records.cc | 1 + + src/startup_opt.cc | 28 +++++++++++++++++++++------ + 5 files changed, 28 insertions(+), 7 deletions(-) + +diff --git a/include/records.h b/include/records.h +index c86ce62..df7d39d 100644 +--- a/include/records.h ++++ b/include/records.h +@@ -23,6 +23,7 @@ typedef struct { + typedef struct { + uint64_t processed_samples; + std::map pids; ++ std::map modules; + } global_records; + + extern global_records records; +diff --git a/src/configs.cc b/src/configs.cc +index 9aa6d36..ab96d2a 100644 +--- a/src/configs.cc ++++ b/src/configs.cc +@@ -128,12 +128,14 @@ std::string get_app_collected_profile_path(AppConfig *app) + int parse_app(boost::property_tree::ptree pt, std::string app_name) + { + std::string full_path; ++ char rlpath[1024] = {0}; + try { + full_path = pt.get(app_name + ".FULL_PATH"); +- if (!boost::filesystem::exists(full_path)) { ++ if (!get_real_path(full_path.c_str(), rlpath)) { + ERROR("Error: File does not exist: " << full_path); + return DFOT_ERROR; + } ++ full_path = std::string(rlpath); + } catch (const boost::property_tree::ptree_bad_path &e) { + ERROR("FULL_PATH is needed."); + return DFOT_ERROR; +diff --git a/src/oeaware_plugins/tuner_sysboost.cc b/src/oeaware_plugins/tuner_sysboost.cc +index b471ccf..14025fd 100644 +--- a/src/oeaware_plugins/tuner_sysboost.cc ++++ b/src/oeaware_plugins/tuner_sysboost.cc +@@ -81,6 +81,7 @@ void SysboostTuner::UpdateData(const DataList &dataList) + processing = true; + + int64_t start_ts = get_current_timestamp(); ++ records.modules.clear(); + uint64_t total_samples = 0; + for (unsigned long long i = 0; i < dataList.len; i++) { + PmuSamplingData *data = (PmuSamplingData *)(dataList.data[i]); +diff --git a/src/records.cc b/src/records.cc +index 1f2cbe3..9b212a6 100644 +--- a/src/records.cc ++++ b/src/records.cc +@@ -8,6 +8,7 @@ void reset_records() + { + records.processed_samples = 0; + records.pids.clear(); ++ records.modules.clear(); + } + + void debug_print_records() +diff --git a/src/startup_opt.cc b/src/startup_opt.cc +index 14b4aa4..78cae70 100644 +--- a/src/startup_opt.cc ++++ b/src/startup_opt.cc +@@ -92,9 +92,25 @@ void update_app_profile_data(AppConfig *app, struct PmuData &data) + // {函数名func: {内存地址addr: 计数count, ...}, ...} + auto &funcs = app->profile.funcs; + ++ // 刷新modules记录,避免直接匹配modules字符串,此处的module是relapath路径 ++ auto symbol = data.stack->symbol; ++ if (records.modules.find(symbol->module) == records.modules.end()) { ++ records.modules[symbol->module] = false; ++ if (strcmp(symbol->module, app->full_path.c_str()) == 0) { ++ records.modules[symbol->module] = true; ++ } else if (strstr(symbol->module, ".rto") != nullptr && ++ strncmp(symbol->module, app->full_path.c_str(), strlen(app->full_path.c_str())) == 0) { ++ records.modules[symbol->module] = true; ++ } ++ } ++ ++ if (!records.modules[symbol->module]) { ++ return; ++ } ++ + // symbol->codeMapAddr symbol->offset + // 如果是BOLT优化过后的二进制的采样数据则只需记录地址和计数 +- unsigned long addr = data.stack->symbol->codeMapAddr; ++ unsigned long addr = symbol->codeMapAddr; + + if (records.pids[data.pid]->instance->version > 0) { + if (addrs.find(addr) != addrs.end()) { +@@ -108,18 +124,18 @@ void update_app_profile_data(AppConfig *app, struct PmuData &data) + // 原始二进制的采样数据,读取地址+符号+偏移 + if (addrs.find(addr) != addrs.end()) { + addrs[addr].count++; +- funcs[addrs[addr].name][data.stack->symbol->offset]++; ++ funcs[addrs[addr].name][symbol->offset]++; + } else { + addrs[addr] = AddrInfo(); +- if (data.stack->symbol->mangleName != nullptr) { +- addrs[addr].name = data.stack->symbol->mangleName; ++ if (symbol->mangleName != nullptr) { ++ addrs[addr].name = symbol->mangleName; + } else { + auto sym = SymResolverMapAddr(data.pid, addr); + addrs[addr].name = sym->mangleName; + } +- addrs[addr].offset = data.stack->symbol->offset; ++ addrs[addr].offset = symbol->offset; + addrs[addr].count = 1; +- funcs[addrs[addr].name][data.stack->symbol->offset] = 1; ++ funcs[addrs[addr].name][symbol->offset] = 1; + } + } + +-- +2.39.5 (Apple Git-154) + diff --git a/D-FOT.spec b/D-FOT.spec index cc9a8bb..eb1883c 100644 --- a/D-FOT.spec +++ b/D-FOT.spec @@ -1,12 +1,14 @@ Name: D-FOT Version: v1.0.2 -Release: 1 +Release: 2 Summary: %{name} is a dynamic feedback-directed optimization tool for openEuler. License: Mulan PSL v2 URL: https://gitee.com/openeuler/%{name} Source0: %{name}-%{version}.tar.gz +Patch1: 0001-filter-so-address-pmudata.patch + BuildRequires: cmake make gcc-c++ BuildRequires: boost-devel log4cplus-devel numactl-devel libkperf-devel oeAware-manager-devel Requires: log4cplus boost libboundscheck oeAware-manager libkperf llvm-bolt @@ -36,6 +38,11 @@ install -D -m 0640 ./configs/dfot.ini ${RPM_BUILD_ROOT}/etc/dfot/ %attr(0440,root,root) %{_libdir}/oeAware-plugin/libdfot.so %changelog +* Wed Dec 11 2024 rfwang07 - v1.0.2-2 +- ID:NA +- SUG:NA +- DESC: filter so address in pmudata + * Tue Dec 10 2024 rfwang07 - v1.0.2-1 - ID:NA - SUG:NA -- Gitee From 3ab7c393f79a1ffbae20f0989f10e60ebec807a4 Mon Sep 17 00:00:00 2001 From: rfwang07 Date: Wed, 26 Feb 2025 15:06:56 +0800 Subject: [PATCH 4/4] filter out default cmake options --- D-FOT.spec | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/D-FOT.spec b/D-FOT.spec index eb1883c..ad26db7 100644 --- a/D-FOT.spec +++ b/D-FOT.spec @@ -1,6 +1,6 @@ Name: D-FOT Version: v1.0.2 -Release: 2 +Release: 3 Summary: %{name} is a dynamic feedback-directed optimization tool for openEuler. License: Mulan PSL v2 URL: https://gitee.com/openeuler/%{name} @@ -23,7 +23,7 @@ ExclusiveArch: aarch64 %build mkdir build && cd build -%{cmake} .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_SKIP_RPATH=TRUE +cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_SKIP_RPATH=TRUE make %install @@ -38,6 +38,11 @@ install -D -m 0640 ./configs/dfot.ini ${RPM_BUILD_ROOT}/etc/dfot/ %attr(0440,root,root) %{_libdir}/oeAware-plugin/libdfot.so %changelog +* Wed Feb 26 2025 rfwang07 - v1.0.2-3 +- ID:NA +- SUG:NA +- DESC: filter out default cmake options + * Wed Dec 11 2024 rfwang07 - v1.0.2-2 - ID:NA - SUG:NA -- Gitee