Projects
Eulaceura:Factory
A-FOT
_service:obs_scm:0003-PGO-kernel-Add-PGO-kernel...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:obs_scm:0003-PGO-kernel-Add-PGO-kernel-mode.patch of Package A-FOT
From 2beb891a3e87e0fa61509d3746f0e216374f6f23 Mon Sep 17 00:00:00 2001 From: xiongzhou4 <xiongzhou4@huawei.com> Date: Mon, 29 May 2023 17:14:22 +0800 Subject: [PATCH] [PGO kernel] Add PGO kernel mode. --- GcovSummaryAddTool.cpp | 176 +++++++++++++++++++++++ a-fot | 129 ++++++++++++++--- a-fot.ini | 45 ++++-- auto_kernel_pgo.sh | 310 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 630 insertions(+), 30 deletions(-) create mode 100644 GcovSummaryAddTool.cpp create mode 100644 auto_kernel_pgo.sh diff --git a/GcovSummaryAddTool.cpp b/GcovSummaryAddTool.cpp new file mode 100644 index 0000000..656f3d5 --- /dev/null +++ b/GcovSummaryAddTool.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * This tool is used to add GCC 9 and GCC 10 summary info into gcov file. + */ + +#include <cstdio> +#include <string> +#include <vector> +#include <cassert> + +using namespace std; + +constexpr long long GCOV_DATA_MAGIC = 0x67636461u; +constexpr long long GCOV_TAG_FUNCTION = 0x01000000u; +constexpr long long GCOV_TAG_COUNTER_BASE = 0x01a10000u; +constexpr long long GCOV_TAG_OBJECT_SUMMARY = 0xa1000000u; + +/* value profile counter */ +constexpr long long GCOV_TAG_COUNTER_INTERVAL = 0x01a30000u; +constexpr long long GCOV_TAG_COUNTER_POW2 = 0x01a50000u; +constexpr long long GCOV_TAG_COUNTER_TOPN = 0x01a70000u; +constexpr long long GCOV_TAG_COUNTER_IC = 0x01a90000u; // indirect call profiler +constexpr long long GCOV_TAG_COUNTER_AVERAGE = 0x01ab0000u; +constexpr long long GCOV_TAG_COUNTER_IOR = 0x01ad0000u; +constexpr long long GCOV_TAG_COUNTER_TP = 0x01af0000u; // time profiler + +static int ReadFile(const string filename, vector<char>& out) +{ + FILE* fp = fopen(filename.c_str(), "rb"); + if (!fp) { + fprintf(stderr, "[!] Fail to read: %s\n", filename.c_str()); + return 1; + } + constexpr int bufSize = 4096; + char buf[bufSize]; + size_t sz; + while (sz = fread(buf, 1, bufSize, fp)) { + out.insert(out.end(), buf, buf + sz); + } + fclose(fp); + return 0; +} + +static void SplitLines(const vector<char>& in, vector<string>& out) +{ + size_t pos = 0; + for (size_t i = 0; i < in.size(); ++i) { + if (in[i] != '\r' && in[i] != '\n') { + continue; + } + out.push_back(string(in.begin() + pos, in.begin() + i)); + if (in[i] == '\r' && i + 1 < in.size() && in[i + 1] == '\n') { + i++; + } + pos = i + 1; + } + if (pos < in.size()) { + out.push_back(string(in.begin() + pos, in.end())); + } +} + +static int WriteFile(string fileName, const vector<char> in, unsigned int valMax) +{ + if (in.size() < 12) { + fprintf(stderr, "[!] Not enough size to write\n"); + return 1; + } + FILE* fp = fopen(fileName.c_str(), "wb"); + if (!fp) { + fprintf(stderr, "[!] Fail to write: %s \n", fileName.c_str()); + return 1; + } + fwrite(in.data(), 1, 12, fp); + unsigned int title[4] = { + GCOV_TAG_OBJECT_SUMMARY, + 2, + 1, + valMax + }; + fwrite(title, 1, 16, fp); + fwrite(in.data() + 12, 1, in.size() - 12, fp); + fclose(fp); + return 0; +} + +static int ProcessFile(const string fileName) +{ + vector<char> source; + if (ReadFile(fileName, source)) { + fprintf(stderr, "[!] Fail to read file: %s \n", fileName.c_str()); + return 1; + } + int state = 1; + unsigned int valMax = 0; + unsigned int count = 0; + unsigned int n = source.size() / 4; + auto vData = (const unsigned int*) source.data(); + for (int i = 0; i < n; ++i) { + unsigned int val = vData[i]; + switch (state) { + case 1: + if (val != GCOV_DATA_MAGIC) { + fprintf(stderr, "[!] GCOV_DATA_MAGIC mismatches: 0x%x\n", val); + return 1; + } + i += 2; + state = 2; + break; + case 2: + if (i == n - 1 && val) { + fprintf(stderr, "[!] Single last tag: 0x%x\n", val); + return 1; + } + if (val == GCOV_TAG_FUNCTION) { + i += 1 + vData[i + 1]; + } else if (val == GCOV_TAG_COUNTER_BASE) { + if (vData[i + 1] % 2) { + fprintf(stderr, "[!] Invalid length: %d\n", vData[i + 1]); + return 1; + } + count = vData[++i]; + if (count) { + state = 3; + } + } else if (val) { + switch (val) { + case GCOV_TAG_COUNTER_INTERVAL: + case GCOV_TAG_COUNTER_POW2: + case GCOV_TAG_COUNTER_TOPN: + case GCOV_TAG_COUNTER_IC: + case GCOV_TAG_COUNTER_AVERAGE: + case GCOV_TAG_COUNTER_IOR: + case GCOV_TAG_COUNTER_TP: + i += 1 + vData[i + 1]; + break; + default: + fprintf(stderr, "[!] Unknown tag: 0x%x\n", val); + return 1; + } + } + break; + case 3: + valMax = valMax < val ? val : valMax; + if (--count == 0) { + state = 2; + } + break; + default: + break; + } + } + if (WriteFile(fileName, source, valMax)) { + return 1; + } + return 0; +} + +int main(int argc, char** argv) +{ + vector<char> fileNameList; + if (argc != 2 || ReadFile(argv[1], fileNameList)) { + fprintf(stderr, "USAGE:\n %s <Input File List>\n", argv[0]); + return 1; + } + vector<string> fileNames; + SplitLines(fileNameList, fileNames); + for (size_t i = 0; i < fileNames.size(); ++i) { + string fileName = fileNames[i]; + fprintf(stderr, "[.] Processing %s \n", fileName.c_str()); + if (ProcessFile(fileName)) { + return 1; + } + } + fprintf(stderr, "[.] File procesed: %d \n", (int) fileNames.size()); + return 0; +} diff --git a/a-fot b/a-fot index c633098..1e7d08e 100755 --- a/a-fot +++ b/a-fot @@ -1,11 +1,13 @@ #!/bin/bash -current_path=$(cd "$(dirname "$0")";pwd) -config_file=${current_path}/a-fot.ini +afot_path=$(cd "$(dirname "$0")";pwd) +config_file=${afot_path}/a-fot.ini # Profile名字 profile_name="profile.data" # gcov名字 gcov_name="profile.gcov" +# 内核编译选项 +kernel_configs=() # 解析配置文件配置项 function parse_config() { @@ -13,21 +15,21 @@ function parse_config() { echo "[ERROR] Could not load config file at: ${config_file}, please check!" exit 1 fi - while read line; do - if [[ ! ${line} =~ "#" ]]; then + while read line || [[ -n ${line} ]]; do + if [[ ! ${line} =~ "#" ]] && [[ ${line} != "" ]]; then key=$(echo ${line} | awk -F "=" '{print $1}') value=$(echo ${line} | awk -F "=" '{print $2}') - eval "${key}=${value}" + if [[ ${key} =~ "CONFIG_" ]]; then + kernel_configs+="${key}=${value}" + else + eval "${key}=${value}" + fi fi done <${config_file} } # 解析输入的参数 function parse_input_params() { - if [[ $# == 1 ]]; then - suggest_info - exit 1 - fi while [ $# -ge 2 ]; do case $1 in --opt_mode) @@ -78,12 +80,71 @@ function parse_input_params() { build_mode=$2 shift 2 ;; + --pgo_mode) + pgo_mode=$2 + shift 2 + ;; + --pgo_phase) + pgo_phase=$2 + shift 2 + ;; + --kernel_src) + kernel_src=$2 + shift 2 + ;; + --kernel_name) + kernel_name=$2 + shift 2 + ;; + --run_time) + run_time=$2 + shift 2 + ;; + --CONFIG_*) + kernel_configs+="${1:2}=$2" + shift 2 + ;; + --last_time) + last_time=$2 + shift 2 + ;; + -s) + silent=1 + shift + ;; + -n) + disable_compilation=1 + shift + ;; + --makefile) + makefile=$2 + shift 2 + ;; + --kernel_config) + kernel_config=$2 + shift 2 + ;; + --data_dir) + data_dir=$2 + shift 2 + ;; *) suggest_info exit 1 ;; esac done + + if [[ $# == 1 ]]; then + if [[ $1 == "-s" ]]; then + silent=1 + elif [[ $1 == "-n" ]]; then + disable_compilation=1 + else + suggest_info + exit 1 + fi + fi } function check_config_item() { @@ -138,6 +199,7 @@ function suggest_info() { echo """ Usage: a-fot [OPTION1 ARG1] [OPTION2 ARG2] [...] +For perf mode: --config_file Path of configuration file --opt_mode Optimization modes (AutoFDO/AutoPrefetch/AutoBOLT) --perf_time Perf sampling duration (unit: seconds) @@ -146,10 +208,28 @@ Usage: a-fot [OPTION1 ARG1] [OPTION2 ARG2] [...] --bin_file Executable binary file path --build_script Application build script path --work_path Script working directory (used to compile the application and store the profile) ---run_script Script path for run application +--run_script Script path for running application --max_waiting_time Maximum binary startup time (unit: seconds) --check_success Check optimization result ---build_mode Execute build scrip mode (Wrapper/Bear) +--build_mode Execute build script mode (Wrapper/Bear) + +For kernel PGO mode: +--config_file Path of configuration file +--opt_mode Optimization mode (Auto_kernel_PGO) +--pgo_mode PGO mode (arc/all) +--pgo_phase Phase of kernel PGO (1/2) +--kernel_src Kernel source directory +--kernel_name Kernel local version name (will be appended with "-pgoing" or "-pgoed") +--work_path Script working directory (used to store the profile and the log) +--run_script Script path for running application +--gcc_path Compiler gcc path +--CONFIG_... Kernel building +--last_time Last time directory before rebooting (used to put log infos together) +-s Silent mode (reboot automatically after kernel installation) +-n Do not compile kernel automatically +--makefile Makefile path of kernel +--kernel_config Config file path of kernel +--data_dir Profile path generated by kernel """ } @@ -157,13 +237,13 @@ Usage: a-fot [OPTION1 ARG1] [OPTION2 ARG2] [...] function load_script() { case ${opt_mode} in "AutoFDO") - source ${current_path}/auto_fdo.sh + source ${afot_path}/auto_fdo.sh ;; "AutoPrefetch") - source ${current_path}/auto_prefetch.sh + source ${afot_path}/auto_prefetch.sh ;; "AutoBOLT") - source ${current_path}/auto_bolt.sh + source ${afot_path}/auto_bolt.sh ;; *) echo "[ERROR] Optimization mode ${opt_mode} is not supported, Check the configuration item: opt_mode" @@ -193,7 +273,7 @@ function check_common_dependency() { # 拆分编译数据库 function split_option() { if [ "$bear_prefix" ];then - python3 $current_path/split_json.py -i $PWD/compile_commands.json + python3 $afot_path/split_json.py -i $PWD/compile_commands.json mv $PWD/compile_commands.json $PWD/compile_commands_$1.json mv $PWD/compile_commands.fail.json $PWD/compile_commands.fail_$1.json fi @@ -289,7 +369,7 @@ function second_compilation() { # 判断上一步执行是否成功 function is_success() { pre_result=$1 - if [[ ${pre_result} -eq 1 ]]; then + if [[ ${pre_result} -ne 0 ]]; then echo "[ERROR] Execution failed, please check the log: ${log_file}" exit 1 fi @@ -342,11 +422,10 @@ function is_opt_success() { exit 0 } -#执行入口,部分函数为加载不同优化脚本中得到 -function main() { - parse_input_params "$@" - parse_config - parse_input_params "$@" +function do_optimization() { + if [[ ${opt_mode} == Auto_kernel_PGO ]]; then + source ${afot_path}/auto_kernel_pgo.sh + fi check_config_item init_profile_and_log load_script @@ -361,6 +440,14 @@ function main() { prepare_new_env second_compilation is_opt_success +} + +#执行入口,部分函数为加载不同优化脚本中得到 +function main() { + parse_input_params "$@" + parse_config + parse_input_params "$@" + do_optimization exit "$?" } diff --git a/a-fot.ini b/a-fot.ini index b395504..c5da1b0 100644 --- a/a-fot.ini +++ b/a-fot.ini @@ -1,23 +1,50 @@ +# 文件和目录请使用绝对路径 + +# 优化模式(AutoFDO、AutoPrefetch、AutoBOLT、Auto_kernel_PGO) +opt_mode=Auto_kernel_PGO +# 脚本工作目录(用来编译应用程序/存放profile、日志) +work_path=/opt +# 应用运行脚本路径 +run_script=/root/run.sh +# GCC路径(bin、lib的父目录) +gcc_path=/usr + +# AutoFDO、AutoPrefetch、AutoBOLT +# 针对应用的三种优化模式,请填写此部分配置 + # 应用进程名 application_name=test # 二进制安装后可执行文件 bin_file=/tmp/test -# 脚本工作目录(用来编译应用程序/存放profile) -work_path=/tmp/ # 应用构建脚本路径 build_script=/root/build.sh -# Benhmark路径及运行命令 -run_script=/root/benchmark.sh # 最大二进制启动时间(单位:秒) max_waiting_time=600 -# 优化模式(AutoFDO、AutoPrefetch、AutoBOLT) -opt_mode=AutoPrefetch # Perf采样时长(单位:秒) perf_time=100 -# gcc路径 -gcc_path=/usr/ # 检测是否优化成功(1=启用,0=禁用) check_success=0 # 构建模式 (Bear、Wrapper) build_mode=Bear -# 结束行勿删 \ No newline at end of file + +# auto_kernel_PGO +# 针对内核的优化模式,请填写此部分配置 + +# 内核PGO模式(arc=只启用arc profile,all=启用完整的PGO优化) +pgo_mode=all +# 执行阶段(1=编译插桩内核阶段,2=编译优化内核阶段) +pgo_phase=1 +# 内核源码目录(不指定则自动下载) +kernel_src=/opt/kernel +# 内核构建的本地名(将根据阶段添加"-pgoing"或"-pgoed"后缀) +kernel_name=kernel +# 内核编译选项(请确保选项修改正确合法,不会造成内核编译失败) +#CONFIG_...=y +# 重启前的时间目录(用于将同一套流程的日志存放在一起) +last_time= +# 内核源码的Makefile地址(用于不自动编译内核的场景) +makefile= +# 内核配置文件路径(用于不自动编译内核的场景) +kernel_config= +# 内核生成的原始profile目录(用于不自动编译内核的场景) +data_dir= \ No newline at end of file diff --git a/auto_kernel_pgo.sh b/auto_kernel_pgo.sh new file mode 100644 index 0000000..0b62220 --- /dev/null +++ b/auto_kernel_pgo.sh @@ -0,0 +1,310 @@ +#!/bin/bash + +parallel=$(cat /proc/cpuinfo | grep "processor" | wc -l) + +# 检查某个配置项是否存在 +function check_item() { + if [[ -z $1 ]]; then + echo "[ERROR] The configuration item '$2' is missing, please check!" + exit 1 + fi +} + +# 检查所有配置项 +function check_config_items() { + check_item ${pgo_phase} pgo_phase + if [[ ${pgo_phase} -ne 1 ]] && [[ ${pgo_phase} -ne 2 ]]; then + echo "[ERROR] The value of configuration item 'pgo_phase' is invalid, please check!" + exit 1 + fi + if [[ ${pgo_phase} -eq 1 ]]; then + check_item ${pgo_mode} pgo_mode + if [[ ${pgo_mode} != "arc" ]] && [[ ${pgo_mode} != "all" ]]; then + echo "[ERROR] The value of configuration item 'pgo_mode' is invalid, please check!" + exit 1 + fi + fi + + check_item ${kernel_name} kernel_name + check_item ${work_path} work_path + if [[ ${work_path} =~ "/tmp" ]]; then + echo "[ERROR] Do not put work path under /tmp, or it will be cleaned after rebooting." + fi + check_item ${run_script} run_script + check_item ${gcc_path} gcc_path + + if [[ -n ${disable_compilation} ]]; then + check_item ${makefile} makefile + is_file_exist ${makefile} "makefile" + if [[ ${pgo_phase} -eq 1 ]]; then + check_item ${kernel_config} kernel_config + is_file_exist ${kernel_config} "kernel_config" + fi + if [[ ${pgo_phase} -eq 2 ]]; then + check_item ${data_dir} data_dir + if [[ ! -d ${data_dir} ]]; then + echo "[ERROR] GCOV data directory ${data_dir} does not exist." + exit 1 + fi + fi + fi +} + +# 初始化文件和目录 +function init() { + if [[ -z ${last_time} ]]; then + now_time=$(date '+%Y%m%d-%H%M%S') + else + now_time=${last_time} + fi + time_dir=${work_path}/${now_time} + log_file=${time_dir}/log + + if [[ -d ${time_dir} ]]; then + echo "[INFO] Use last time directory: ${time_dir}" + else + mkdir -p ${time_dir} + echo "[INFO] Create time directory: ${time_dir}" + fi + + if [[ -f ${log_file} ]]; then + echo "[INFO] Use last log: ${log_file}" + else + touch ${log_file} + echo "[INFO] Init log file: ${log_file}" + fi +} + +# 检测环境 +function check_dependency() { + sed -i '/a-fot/d' /etc/rc.d/rc.local + + get_arch=$(arch) + if [[ ${get_arch} =~ "x86_64" || ${get_arch} =~ "aarch64" ]]; then + echo "[INFO] Current arch: ${get_arch}" + else + echo "[ERROR] Unsupport arch: ${get_arch}" + exit 1 + fi + is_file_exist ${run_script} "run_script" + is_file_exist "${gcc_path}/bin/gcc" "gcc_path" + + export CC=${gcc_path}/bin/gcc + export PATH=${gcc_path}/bin:${PATH} + export LD_LIBRARY_PATH=${gcc_path}/lib64:${LD_LIBRARY_PATH} + + if [[ ${pgo_phase} -eq 1 ]] && [[ ${pgo_mode} == "all" ]] && [[ -z ${disable_compilation} ]]; then + if echo 'int main() { return 0; }' | gcc -x c - -o /dev/null -Werror -fkernel-pgo >/dev/null 2>&1; then + echo "[INFO] Current GCC supports kernel PGO in runtime, use -fkernel-pgo option." + option="-fkernel-pgo" + elif gcc -v 2>&1 | grep -- "--disable-tls" >/dev/null; then + echo "[INFO] Current GCC is recompiled with --disable-tls, does support kernel PGO in runtime." + else + echo "[ERROR] Current GCC does not support kernel PGO, you may use openeuler GCC or recompile GCC with --disable-tls --disable-libsanitizer." + fi + fi +} + +# 修改内核配置文件 +function modify_kernel_config() { + if [[ ${pgo_mode} == "all" ]]; then + if ! grep "PGO" $1 >/dev/null; then + echo "[ERROR] Current version of kernel does not support PGO, please use newer ones or choose arc mode." + exit 1 + fi + sed -i 's/.*CONFIG_PGO_KERNEL.*/CONFIG_PGO_KERNEL=y/' $1 + fi + for config in ${kernel_configs[@]}; do + sed -i "s/.*${config%%=*}.*/${config}/" $1 + done + sed -i "s/CONFIG_LOCALVERSION=\"\"/CONFIG_LOCALVERSION=\"-${kernel_name}-pgoing\"/" $1 + sed -i 's/.*CONFIG_GCOV_KERNEL.*/CONFIG_GCOV_KERNEL=y/' $1 + sed -i '/CONFIG_ARCH_HAS_GCOV_PROFILE_ALL/ a\CONFIG_GCOV_PROFILE_ALL=y' $1 + sed -i '/CONFIG_CC_HAS_ASM_INLINE/ a\CONFIG_CONSTRUCTORS=y' $1 + sed -i '/CONFIG_TRACE_EVAL_MAP_FILE/ a\# CONFIG_GCOV_PROFILE_FTRACE is not set' $1 +} + +# 编译插桩版本的内核 +function first_compilation() { + if [[ -n ${disable_compilation} ]]; then + modify_kernel_config ${kernel_config} + echo "[INFO] Kernel configuration has been generated, the path is: ${kernel_config}" + if [[ -z ${option} ]]; then + sed -i "/KBUILD_CFLAGS += \$(KCFLAGS)/ a\KBUILD_CFLAGS += fkernel-pgo" ${makefile} + fi + echo "[INFO] Kernel makefile has been generated, the path is: ${makefile}" + exit 0 + fi + + if [[ -z ${kernel_src} ]]; then + echo "[WARNING] ${kernel_src} is not specified, A-FOT will download and build kernel source code automatically in 10 seconds." + sleep 10 + oe_version=$(grep 'openeulerversion' /etc/openEuler-latest | cut -d '=' -f 2) + echo "[INFO] Current openEuler version: ${oe_version}" + url="https://repo.huaweicloud.com/openeuler/${oe_version}/source/Packages/" + echo "[INFO] Download the kernel source rpm package from ${url}" + cd ${work_path} + wget --no-parent --no-directories -r -A 'kernel-[0-9]*.rpm' ${url} --no-check-certificate >>${log_file} 2>&1 + is_success $? + srpm=$(ls -t kernel-[0-9]*.rpm 2>/dev/null | head -n 1) + echo "[INFO] Successfully downloaded kernel source rpm package: ${srpm}" + echo "[INFO] Build kernel source code." + rpm -ivh ${srpm} >>${log_file} 2>&1 + cd - >/dev/null + rpmbuild -bp ~/rpmbuild/SPECS/kernel.spec >>${log_file} 2>&1 + is_success $? + src_dir=$(ls -td ~/rpmbuild/BUILD/kernel-*/*-source/ | head -n 1) + cp -r ${src_dir} ${work_path}/kernel + kernel_src=${work_path}/kernel + echo "[INFO] Successfully builded kernel source code: ${kernel_src}" + else + echo "[INFO] Build kernel in an existing source directory." + fi + + if [[ ! -d ${kernel_src} ]]; then + echo "[ERROR] Kernel source directory ${kernel_src} does not exist." + exit 1 + fi + + cd ${kernel_src} + make openeuler_defconfig + modify_kernel_config .config + echo "[INFO] Start PGO kernel compilation." + Arch=$(arch | sed -e s/x86_64/x86/ -e s/aarch64.*/arm64/) + (make clean -j ${parallel} && make KCFLAGS="${option}" ARCH=${Arch} -j ${parallel} && make modules_install ARCH=${Arch} -j ${parallel} && make install ARCH=${Arch} -j ${parallel}) 2>&1 | tee -a ${log_file} + is_success ${PIPESTATUS[0]} + cd - >/dev/null +} + +# 第一次重启操作 +function first_reboot() { + grub2-set-default 0 + next_cmd="${afot_path}/a-fot --opt_mode Auto_kernel_PGO --pgo_phase 2 --kernel_src ${kernel_src} --kernel_name ${kernel_name} --work_path ${work_path} --run_script ${run_script} --gcc_path ${gcc_path} --last_time ${now_time} -s" + if [[ -z ${silent} ]]; then + read -p $'PGO kernel has been successfully installed. Reboot now to use?\nPress [y] to reboot now, [n] to reboot yourself later: ' reboot_p + if [[ ${reboot_p} == "y" ]]; then + echo "[WARNING] System will be rebooted in 10 seconds!!!" + echo -e "[INFO] Please run this command to continue after rebooting:\n${next_cmd}" + sleep 10 + reboot + else + echo -e "[INFO] Please run this command to continue after rebooting:\n${next_cmd}" + fi + else + echo ${next_cmd} >>/etc/rc.d/rc.local + chmod u+x /etc/rc.d/rc.local + echo "[WARNING] System will be rebooted in 10 seconds!!!" + sleep 10 + reboot + fi + exit 0 +} + +# 执行应用程序执行脚本 +function execute_run_script() { + echo "[INFO] Start to execute the run_script: ${run_script}" + /bin/bash ${run_script} >>${log_file} 2>&1 + is_success $? +} + +# 收集和处理profile文件 +function process_profiles() { + if [[ -z ${disable_compilation} ]]; then + data_dir=/sys/kernel/debug/gcov + fi + if [[ ! -d ${data_dir} ]]; then + echo "[ERROR] GCOV data directory ${data_dir} does not exist." + exit 1 + fi + + temp_dir=$(mktemp -d) + cd ${work_path} + echo "[INFO] Start collecting the profiles." + find ${data_dir} -type d -exec mkdir -p ${temp_dir}/\{\} \; + find ${data_dir} -name '*.gcda' -exec sh -c 'cat < $0 > '${temp_dir}'/$0' {} \; + find ${data_dir} -name '*.gcno' -exec sh -c 'cp -d $0 '${temp_dir}'/$0' {} \; + + echo "[INFO] Start post-processing the profiles." + find ${temp_dir} -name '*.gcda' >list.txt + /usr/bin/g++ ${afot_path}/GcovSummaryAddTool.cpp -o calcsum + ./calcsum list.txt + rm -f list.txt + + profile_dir=${time_dir}/gcovdata + rm -rf ${profile_dir} + mkdir ${profile_dir} + for file in $(find ${temp_dir} -name '*.gcda'); do + hash_path=$(echo ${file//\//\#}) + name=$(echo ${hash_path#*gcov}) + mv $file ${profile_dir}/$name + done + rm -rf ${temp_dir} + cd - >/dev/null + echo "[INFO] Profiles have been successfully processed, the path is: ${profile_dir}" +} + +# 使用profile编译优化的内核 +function second_compilation() { + if [[ -n ${disable_compilation} ]]; then + sed -i "/KBUILD_CFLAGS += \$(KCFLAGS)/ a\KBUILD_CFLAGS += -fprofile-use -fprofile-correction -Wno-error=coverage-mismatch -fprofile-dir=${profile_dir}" ${makefile} + echo "[INFO] Kernel makefile has been generated, the path is: ${makefile}" + exit 0 + fi + + if [[ -z ${kernel_src} ]]; then + kernel_src=${work_path}/kernel + fi + if [[ ! -d ${kernel_src} ]]; then + echo "[ERROR] Kernel source directory ${kernel_src} does not exist." + exit 1 + fi + + cd ${kernel_src} + make openeuler_defconfig + for config in ${kernel_configs[@]}; do + sed -i 's/.*${config%%=*}.*/${config}/' .config + done + sed -i "s/CONFIG_LOCALVERSION=\"\"/CONFIG_LOCALVERSION=\"-${kernel_name}-pgoed\"/" .config + echo "[INFO] Start optimized kernel compilation." + Arch=$(arch | sed -e s/x86_64/x86/ -e s/aarch64.*/arm64/) + (make clean -j ${parallel} && make KCFLAGS="-fprofile-use -fprofile-correction -Wno-error=coverage-mismatch -fprofile-dir=${profile_dir}" -j ${parallel} && make modules_install ARCH=${Arch} -j ${parallel} && make install ARCH=${Arch} -j ${parallel}) 2>&1 | tee -a ${log_file} + is_success ${PIPESTATUS[0]} + cd - >/dev/null +} + +# 第二次重启操作 +function second_reboot() { + grub2-set-default 0 + if [[ -z ${silent} ]]; then + read -p $'Optimized kernel has been successfully installed. Reboot now to use?\nPress [y] to reboot now, [n] to reboot yourself later: ' reboot_p + fi + if [[ -n ${silent} ]] || [[ ${reboot_p} == "y" ]]; then + echo "[WARNING] System will be rebooted in 10 seconds!!!" + sleep 10 + reboot + exit 0 + fi +} + +# 执行入口 +function main() { + check_config_items + if [[ ${pgo_phase} -eq 1 ]]; then + check_dependency + init + first_compilation + first_reboot + fi + if [[ ${pgo_phase} -eq 2 ]]; then + check_dependency + init + execute_run_script + process_profiles + second_compilation + second_reboot + fi + exit "$?" +} + +main +exit "$?" -- 2.33.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2