diff --git a/Makefile b/Makefile index a44990fa5f65d14ae8dc9abbcedcdd3f33355deb..75c9107b48773a6f49165f90d55312241463e0d8 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ install: test: sysboostd install clear - cargo test + ./tests/test_sysboostd.py -test-debug: +unittest: cargo test -- --nocapture diff --git a/bin/bolt.rs b/bin/bolt.rs index 5410f5116c8fc3b4c61d3736c222c51e896d010e..c20e95cc41b616d18a44b89d5c6e02480baa4bfb 100644 --- a/bin/bolt.rs +++ b/bin/bolt.rs @@ -10,12 +10,14 @@ // Create: 2023-8-28 use crate::common::set_thp; -use crate::common::ARCH; +use crate::common::is_arch_x86_64; use crate::config::RtoConfig; use crate::lib::process_ext::run_child; +use crate::config::get_config; use std::fs; use std::path::Path; +use std::env::consts::ARCH; // 因为sysboost限制最多只有10个APP可以做优化, 因此假设app名称不会冲突 // 为了避免不同架构profile误用, 因此名称中带arch信息 @@ -147,10 +149,66 @@ pub fn bolt_optimize(conf: &RtoConfig) -> i32 { } } +fn gen_app_profile(name: &str, elf_path: &String) -> i32 { + // 抓取热点 + // perf record -e cycles:u -j any,u -a -o mysqld.perf.data -- sleep 10 + // 生成bolt profile文件 + // perf2bolt -p=mysqld.perf.data -o mysqld.profile xxx + + // ARM不支持-j参数 + // perf record -e cycles:u -a -o mysqld.perf.data -- sleep 10 + // 没有-j参数收集的分支跳转信息, 则-nl关闭分支预测 + // perf2bolt -nl -p=mysqld.perf.data -o mysqld.profile xxx + + let mut args: Vec = Vec::new(); + let mut ret; + let perf_data_path = format!("{}{}.perf.data", SYSBOOST_BOLT_PROFILE, name); + args.push("record".to_string()); + args.push("-e".to_string()); + args.push("cycles:u".to_string()); + if is_arch_x86_64() { + args.push("-j".to_string()); + args.push("any,u".to_string()); + } + args.push("-a".to_string()); + args.push("-o".to_string()); + args.push(perf_data_path.clone()); + args.push("--".to_string()); + args.push("sleep".to_string()); + args.push("10".to_string()); + ret = run_child("perf", &args); + if ret != 0 { + return ret; + } + + args = Vec::new(); + if is_arch_x86_64() == false { + args.push("-nl".to_string()); + } + args.push(format!("-p={}", perf_data_path)); + args.push("-o".to_string()); + args.push(format!("{}{}.profile.now", SYSBOOST_BOLT_PROFILE, name)); + args.push(elf_path.to_string()); + ret = run_child("perf2bolt", &args); + return ret; +} + +// profile文件与ELF文件不配套的时候, 影响BOLT优化性能 +pub fn gen_profile(name: &str) -> i32 { + // 获得app路径 + let conf_e = get_config(name); + let conf = match conf_e { + Some(conf) => conf, + None => return -1, + }; + + return gen_app_profile(name, &conf.elf_path); +} + #[cfg(test)] mod tests { use super::*; - use crate::common::ARCH; + use std::env::consts::ARCH; // cargo test -- tests::test_get_profile_path --nocapture // 测试profile路径是否正确 diff --git a/bin/common.rs b/bin/common.rs index 12eae142d2978e830d13392fcf98018d72363149..59b28ec7f5d5b3b188538bb8a5e4f3ac35736950 100644 --- a/bin/common.rs +++ b/bin/common.rs @@ -12,12 +12,7 @@ use crate::lib::process_ext::run_child; pub const SYSBOOST_PATH: &str = "/usr/bin/sysboost"; - -#[cfg(target_arch = "x86_64")] -pub const ARCH: &str = "x86_64"; - -#[cfg(target_arch = "aarch64")] -pub const ARCH: &str = "aarch64"; +pub const SYSBOOST_CONFIG_PATH: &str = "/etc/sysboost.d"; // echo always > /sys/kernel/mm/transparent_hugepage/enabled pub fn set_thp() -> i32 { @@ -25,3 +20,10 @@ pub fn set_thp() -> i32 { let ret = run_child("echo always > /sys/kernel/mm/transparent_hugepage/enabled", &args); return ret; } + +pub fn is_arch_x86_64() -> bool { + if std::env::consts::ARCH == "x86_64" { + return true; + } + return false; +} diff --git a/bin/config.rs b/bin/config.rs index f5a4a7aa8bf4ae167972491290a3580bdc61414d..21dec8f797117f582071599a8ecf4a757c557ffa 100644 --- a/bin/config.rs +++ b/bin/config.rs @@ -10,6 +10,7 @@ // Create: 2023-8-28 use crate::common::SYSBOOST_PATH; +use crate::common::SYSBOOST_CONFIG_PATH; use serde::Deserialize; use std::fs; @@ -78,3 +79,8 @@ pub fn read_config(path: &PathBuf) -> Option { }; return parse_config(contents); } + +pub fn get_config(name: &str) -> Option { + let conf_path = format!("{}/{}.toml", SYSBOOST_CONFIG_PATH, name); + return read_config(&PathBuf::from(conf_path)); +} diff --git a/bin/daemon.rs b/bin/daemon.rs index d5a525417f22df881c721a3e276f5dcdc00b097a..8d63f48693d740c9f77ceed956f2af48cc82dd62 100644 --- a/bin/daemon.rs +++ b/bin/daemon.rs @@ -436,7 +436,7 @@ mod tests { } #[test] - #[cfg(target_arch = "x86")] + #[cfg(target_arch = "x86_64")] fn test_process_config_x86() { // Create a temporary directory for testing let temp_dir = tempfile::tempdir().unwrap(); diff --git a/bin/main.rs b/bin/main.rs index 8f4ead7ab8d5195b69f96a8ad989e63886b0af51..a72033611b715db212dced24819a0db036968e53 100644 --- a/bin/main.rs +++ b/bin/main.rs @@ -21,6 +21,7 @@ mod lib; use crate::coredump_monitor::coredump_monitor_loop; use crate::daemon::daemon_loop; use crate::kmod_util::test_kmod; +use crate::bolt::gen_profile; use basic::logger::{self}; use daemonize::Daemonize; @@ -37,6 +38,16 @@ fn main() { // arg0 is program name, parameter is from arg1 for i in 1..args.len() { + if args[i].contains("--gen-profile=") { + if let Some(index) = args[i].find('=') { + let sub_str = &args[i][index + 1..]; + std::process::exit(gen_profile(sub_str)); + } else { + println!("parameter is wrong"); + std::process::exit(-1); + } + } + match args[i].as_str() { "--debug" => { is_debug = true; diff --git a/tests/test_sysboostd.py b/tests/test_sysboostd.py new file mode 100755 index 0000000000000000000000000000000000000000..3d12f031d92dfab19d62fe2227aaccfb28afe45a --- /dev/null +++ b/tests/test_sysboostd.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +# Copyright (c) 2023 Huawei Technologies Co., Ltd. +# sysboost is licensed under the 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. +# Create: 2023-9-25 + +import unittest +import subprocess +import os + + +''' +cmd 是字符串列表 ['xxx', 'xx']; cmd是命令行的时候, 需要带shell=True +subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, encoding=None, errors=None, env=None, universal_newlines=None) +`stdin` 参数用于指定标准输入,`input` 参数用于指定输入内容,`stdout` 和 `stderr` 参数用于指定标准输出和标准错误输出,`shell` 参数用于指定是否使用 shell 执行命令,`timeout` 参数用于指定超时时间,`check` 参数用于指定是否检查返回值,`encoding` 和 `errors` 参数用于指定编码和错误处理方式,`env` 参数用于指定环境变量,`universal_newlines` 参数用于指定是否将输入输出转换为字符串。 +`subprocess.run()` 的返回值是一个 `CompletedProcess` 对象,其中包含了执行结果的各种信息,例如返回值、标准输出、标准错误输出等。可以通过 `result.returncode` 获取返回值,通过 `result.stdout` 和 `result.stderr` 获取标准输出和标准错误输出。 +''' +def run_cmd(cmd): + try: + result = subprocess.run(cmd, shell=True, check=False, capture_output=True, text=True) + except Exception as e: + print(e) + return (-1, None) + return (result.returncode, result.stdout) + + +def write_file(file_path, s): + file = open(file_path, "w") + file.write(s) + file.close() + + +class TestSysboostd(unittest.TestCase): + ''' 测试在线生成profile文件 + sysboostd --gen-profile=mysqld + 观察点: /usr/lib/sysboost.d/profile/mysqld.profile.now 是否正确生成 + ''' + def test_gen_profile(self): + # 测试环境需要安装perf + # yum install perf + + # 生成toml, 不是每个测试环境都有mysql, 用bash模拟测试 + run_cmd("mkdir -p /etc/sysboost.d") + run_cmd("rm -f /etc/sysboost.d/mysqld.toml") + s = '''elf_path = "/usr/bin/bash" +mode = "bolt" +''' + write_file("/etc/sysboost.d/mysqld.toml", s) + + # 测试 + file_path = "/usr/lib/sysboost.d/profile/mysqld.profile.now" + run_cmd("rm -f {}".format(file_path)) + ret,_ = run_cmd("sysboostd --gen-profile=mysqld") + self.assertEqual(ret, 0) + self.assertEqual(os.path.exists(file_path), True) + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/tests/test_sysboostd.rs b/tests/test_sysboostd.rs index a138224d184129ce2cecec3687d957de85c5dd58..cb59fc76786a301d2a2d12f58994e5823279f460 100644 --- a/tests/test_sysboostd.rs +++ b/tests/test_sysboostd.rs @@ -9,6 +9,7 @@ // See the Mulan PSL v2 for more details. // Create: 2023-5-17 +// TODO: rust开发测试用例效率太低, 用Python开发测试用例, 该文件代码逐渐废弃 // test all sysboostd modes and features #[cfg(test)] mod tests {