diff --git a/bin/bolt.rs b/bin/bolt.rs index c20e95cc41b616d18a44b89d5c6e02480baa4bfb..0fd86f90f20fabff51309f058c739e10826710bf 100644 --- a/bin/bolt.rs +++ b/bin/bolt.rs @@ -149,7 +149,7 @@ pub fn bolt_optimize(conf: &RtoConfig) -> i32 { } } -fn gen_app_profile(name: &str, elf_path: &String) -> i32 { +fn gen_app_profile(name: &str, elf_path: &String, timeout: u32) -> i32 { // 抓取热点 // perf record -e cycles:u -j any,u -a -o mysqld.perf.data -- sleep 10 // 生成bolt profile文件 @@ -175,7 +175,7 @@ fn gen_app_profile(name: &str, elf_path: &String) -> i32 { args.push(perf_data_path.clone()); args.push("--".to_string()); args.push("sleep".to_string()); - args.push("10".to_string()); + args.push(timeout.to_string()); ret = run_child("perf", &args); if ret != 0 { return ret; @@ -194,15 +194,18 @@ fn gen_app_profile(name: &str, elf_path: &String) -> i32 { } // profile文件与ELF文件不配套的时候, 影响BOLT优化性能 -pub fn gen_profile(name: &str) -> i32 { +pub fn gen_profile(name: &str, timeout: u32) -> i32 { // 获得app路径 let conf_e = get_config(name); let conf = match conf_e { Some(conf) => conf, - None => return -1, + None => { + println!("get {} config fail", name); + return -1; + } }; - return gen_app_profile(name, &conf.elf_path); + return gen_app_profile(name, &conf.elf_path, timeout); } #[cfg(test)] diff --git a/bin/config.rs b/bin/config.rs index 21dec8f797117f582071599a8ecf4a757c557ffa..f90bff69e8b2f07bc8dddde4c4fc28098639a433 100644 --- a/bin/config.rs +++ b/bin/config.rs @@ -17,14 +17,18 @@ use std::fs; use std::path::PathBuf; use std::str::FromStr; +// 选型toml格式作为配置文件格式, toml格式可读性最佳 #[derive(Debug, Deserialize)] pub struct RtoConfig { + // 目标程序的全路径 pub elf_path: String, + // 优化模式 pub mode: String, - pub libs: Vec, - // Absolute path of the profile + // 依赖的动态库路径 + pub libs: Vec, // TODO: 修改为字符串, 列表形式影响可读性 + // profile文件路径 pub profile_path: Option, - + // 环境变量 #[serde(rename = "PATH")] pub path: Option, @@ -46,8 +50,8 @@ fn parse_config(contents: String) -> Option { let conf_e = contents.parse::(); match conf_e { Ok(ref c) => log::info!("parse config: {:?}", c), - Err(_) => { - log::error!("parse config fail"); + Err(e) => { + log::error!("parse config fail: {}", e); return None; } }; diff --git a/bin/main.rs b/bin/main.rs index a72033611b715db212dced24819a0db036968e53..e8b068251f5ff5bb08d35775951c71aeeddfe8b6 100644 --- a/bin/main.rs +++ b/bin/main.rs @@ -30,22 +30,38 @@ use std::env; use std::thread; const APP_NAME: &str = "sysboostd"; +const DEFAULT_TIMEOUT: u32 = 10; + +fn parameter_wrong_exit() { + println!("parameter is wrong"); + std::process::exit(-1); +} fn main() { let args: Vec = env::args().collect(); let mut is_debug = false; let mut is_daemon = false; + let mut is_gen_porfile = false; + let mut timeout = DEFAULT_TIMEOUT; + let mut name = ""; // 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)); + is_gen_porfile = true; + name = &args[i][index + 1..]; } else { - println!("parameter is wrong"); - std::process::exit(-1); + parameter_wrong_exit(); + } + continue; + } + if args[i].contains("--timeout=") { + if let Some(index) = args[i].find('=') { + let sub_str = &args[i][index + 1..]; + timeout = sub_str.parse().unwrap(); } + continue; } match args[i].as_str() { @@ -59,12 +75,16 @@ fn main() { std::process::exit(test_kmod()); } _ => { - println!("parameter is wrong"); - std::process::exit(-1); + parameter_wrong_exit(); } } } + if is_gen_porfile { + logger::init_log_to_console(APP_NAME, log::LevelFilter::Debug); + std::process::exit(gen_profile(name, timeout)); + } + if is_debug { logger::init_log_to_console(APP_NAME, log::LevelFilter::Debug); } else { diff --git a/tests/test_sysboostd.py b/tests/test_sysboostd.py index 3d12f031d92dfab19d62fe2227aaccfb28afe45a..73fd7b28966cbad8c90d5590a306329005a62208 100755 --- a/tests/test_sysboostd.py +++ b/tests/test_sysboostd.py @@ -44,23 +44,30 @@ class TestSysboostd(unittest.TestCase): 观察点: /usr/lib/sysboost.d/profile/mysqld.profile.now 是否正确生成 ''' def test_gen_profile(self): - # 测试环境需要安装perf - # yum install perf + # 测试环境需要安装perf, llvm-bolt + # yum install perf llvm-bolt - # 生成toml, 不是每个测试环境都有mysql, 用bash模拟测试 + run_cmd("mkdir -p /usr/lib/sysboost.d/profile") + # 不是每个测试环境都有mysql, 用小程序模拟测试, 目标程序需要有重定位信息 + run_cmd("mkdir -p /home/test_sysboost") + run_cmd("cp -f build/tests/test_simple/simple_app /home/test_sysboost/mysqld") + # 生成toml run_cmd("mkdir -p /etc/sysboost.d") run_cmd("rm -f /etc/sysboost.d/mysqld.toml") - s = '''elf_path = "/usr/bin/bash" + s = '''elf_path = "/home/test_sysboost/mysqld" mode = "bolt" +libs = [] ''' 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) + ret,output = run_cmd("sysboostd --gen-profile=mysqld --timeout=1") + # TODO: 目标程序需要被采集到, 否则perf2bolt会报错, 返回1 + self.assertEqual(ret, 1, msg=output) + #self.assertEqual(os.path.exists(file_path), True) + if __name__ == '__main__': unittest.main(verbosity=2)