diff --git a/src/sysboostd/coredump_monitor.rs b/src/sysboostd/coredump_monitor.rs index c96bda7bf317684feb0bc600db1c23f9ed34c19a..011a3f3296789e4f5c0a66a2330a8ec6992b1048 100644 --- a/src/sysboostd/coredump_monitor.rs +++ b/src/sysboostd/coredump_monitor.rs @@ -37,10 +37,10 @@ lazy_static! { } // 设置SYSBOOST_LOG_PATH的权限仅root可写 -fn set_mode() { +pub fn set_mode(path: &str) { let mut set_mod: Vec = Vec::new(); set_mod.push("644".to_string()); - set_mod.push(SYSBOOST_LOG_PATH.to_string()); + set_mod.push(path.to_string()); let _ = run_child("/usr/bin/chmod", &set_mod); } @@ -82,7 +82,7 @@ fn record_crashed_path(path: String) { let exist = Path::new(&SYSBOOST_LOG_PATH).exists(); if !exist { let _ = std::fs::File::create(SYSBOOST_LOG_PATH.to_string()); - set_mode(); + set_mode(SYSBOOST_LOG_PATH); } let file_name = Path::new(&SYSBOOST_LOG_PATH); let mut file = match OpenOptions::new().append(true).open(file_name) { @@ -116,10 +116,7 @@ fn do_rollback(path: &String) -> i32 { } // remove link let link_path = format!("{}{}.link", SYSBOOST_DB_PATH, binary_name); - let exist = Path::new(&link_path).exists(); - if exist { - daemon::db_remove_link(&link_path); - } + daemon::db_remove_link(&link_path); // remove bash.rto let exist = Path::new(&rto_path).exists(); diff --git a/src/sysboostd/daemon.rs b/src/sysboostd/daemon.rs index 06a138b3f73815e1229185a36710536008dabcbf..966431b8d532877d0d95589327339b1bde609164 100644 --- a/src/sysboostd/daemon.rs +++ b/src/sysboostd/daemon.rs @@ -26,7 +26,7 @@ use inotify::{EventMask, Inotify, WatchMask}; use log::{self}; use std::fs; use std::os::unix::fs as UnixFs; -use std::path::{Path}; +use std::path::Path; use std::thread; use std::time::Duration; diff --git a/src/sysboostd/interface.rs b/src/sysboostd/interface.rs new file mode 100644 index 0000000000000000000000000000000000000000..23392ca8494a6316d9353b220fbfef494f4776cc --- /dev/null +++ b/src/sysboostd/interface.rs @@ -0,0 +1,156 @@ +use std::fs; +use std::path::Path; +use std::os::unix::fs as UnixFs; +use std::fs::OpenOptions; +use std::io::{Write, Read}; +use std::io::BufRead; + +use crate::aot::{set_rto_link_flag, set_app_link_flag}; +use crate::coredump_monitor::set_mode; +use crate::lib::process_ext::run_child; +use crate::daemon::{SYSBOOST_DB_PATH, self}; + +pub const OPTIMIZED_ELF_LOG: &str = "/etc/sysboost.d/.optimized.log"; + +pub fn write_back_config(name: &str) -> i32 { + let exist = Path::new(&OPTIMIZED_ELF_LOG).exists(); + if !exist { + let _ = std::fs::File::create(OPTIMIZED_ELF_LOG.to_string()); + set_mode(OPTIMIZED_ELF_LOG); + } + let file_name = Path::new(&OPTIMIZED_ELF_LOG); + let mut file = match OpenOptions::new().append(true).open(file_name) { + Ok(f) => {f} + Err(e) => { + log::error!("open {} failed: {}", OPTIMIZED_ELF_LOG, e); + return -1; + } + }; + let content = format!("{}\n", name); + match file.write_all(content.as_bytes()) { + Ok(_) => {return 0;} + Err(e) => { + log::error!("write {} failed: {}", OPTIMIZED_ELF_LOG, e); + return -1; + } + } +} +pub fn delete_one_record(name: &str) -> i32 { + let exist = Path::new(&OPTIMIZED_ELF_LOG).exists(); + if !exist { + return -1; + } + let file_name = Path::new(&OPTIMIZED_ELF_LOG); + let rfile = match OpenOptions::new().read(true).open(file_name) { + Ok(f) => {f} + Err(e) => { + log::error!("open {} failed: {}", OPTIMIZED_ELF_LOG, e); + return -1; + } + }; + let mut buf = String::new(); + let reader = std::io::BufReader::new(&rfile); + for line in reader.lines() { + if line.as_ref().unwrap().contains(name){ + continue; + } + buf.push_str(line.as_ref().unwrap()); + buf.push_str("\n") + } + let mut wfile = match OpenOptions::new().truncate(true).write(true).open(file_name) { + Ok(f) => {f} + Err(e) => { + log::error!("open {} failed: {}", OPTIMIZED_ELF_LOG, e); + return -1; + } + }; + match wfile.write_all(buf.as_bytes()) { + Ok(_) => {return 0;} + Err(e) => { + log::error!("write {} failed: {}", OPTIMIZED_ELF_LOG, e); + return -1; + } + } + +} +pub fn bolt_add_link(file_name: &str) -> i32 { + // symlink app.link to app, different modes correspond to different directories + let names: Vec<&str> = file_name.split("/").collect(); + let binary_name = names[names.len() - 1]; + let link_path = format!("{}{}.link", SYSBOOST_DB_PATH, binary_name); + let ret_e = UnixFs::symlink(&binary_name, &link_path); + match ret_e { + Ok(_) => log::info!("symlink sucess {}", link_path), + Err(_) => { + log::error!("symlink fail {}", link_path); + return -1; + } + }; + 0 +} + +pub fn gen_bolt_optimize_bin(name: &str, bolt_option: &str, profile_path: &str) -> i32 { + let mut args: Vec = Vec::new(); + if bolt_option.is_empty() { + args.push("-reorder-blocks=ext-tsp".to_string()); + args.push("-reorder-functions=hfsort".to_string()); + args.push("-split-functions".to_string()); + args.push("-split-all-cold".to_string()); + args.push("-split-eh".to_string()); + args.push("-dyno-stats".to_string()); + } else { + let options: Vec<&str> = bolt_option.split(" ").collect(); + for option in options{ + args.push(option.to_string()); + } + } + let elf_path = Path::new(name); + let elf_path = match fs::canonicalize(elf_path) { + Ok(p) => p, + Err(e) => { + log::error!("bolt_optimize_bin: get realpath failed: {}", e); + return -1; + } + }; + let rto_path = elf_path.with_extension("rto"); + args.push(name.to_string()); + args.push("-o".to_string()); + args.push(rto_path.to_str().unwrap().to_string()); + args.push(format!("-data={}", profile_path)); + let mut ret = run_child("/usr/bin/llvm-bolt", &args); + if ret != 0 { + return ret; + } + ret = set_rto_link_flag(&rto_path.to_str().unwrap().to_string(), true); + ret = set_app_link_flag(&name.to_string(), true); + ret = bolt_add_link(name); + return ret; + +} + +pub fn stop_one_elf(path: &str) -> i32 { + let names: Vec<&str> = path.split("/").collect(); + let binary_name = names[names.len() - 1]; + let rto_path = format!("{}.rto", path); + // unset flag + let ret = set_app_link_flag(&path.to_string(), false); + if ret != 0 { + log::error!("Failed to unset link flag for {}", path); + return ret; + } + // remove link + let link_path = format!("{}{}.link", SYSBOOST_DB_PATH, binary_name); + daemon::db_remove_link(&link_path); + + // remove xx.rto + let exist = Path::new(&rto_path).exists(); + if exist { + match fs::remove_file(&rto_path) { + Ok(_) => {} + Err(e) => { + log::error!("remove file failed: {}", e); + } + } + } + 0 +} \ No newline at end of file diff --git a/src/sysboostd/main.rs b/src/sysboostd/main.rs index 91fbdb8d789ce6617fb9239b62648e489d9e3196..d33c0abedd4bc3e1a6756009c1e5b9bfd57dc578 100644 --- a/src/sysboostd/main.rs +++ b/src/sysboostd/main.rs @@ -18,11 +18,16 @@ mod daemon; mod kmod_util; mod lib; mod netlink_client; +mod interface; use crate::config::parse_sysinit_config; use crate::coredump_monitor::coredump_monitor_loop; use crate::coredump_monitor::parse_crashed_log; use crate::daemon::daemon_loop; +use crate::interface::delete_one_record; +use crate::interface::gen_bolt_optimize_bin; +use crate::interface::stop_one_elf; +use crate::interface::write_back_config; use crate::kmod_util::test_kmod; use crate::bolt::gen_profile; use crate::config::INIT_CONF; @@ -35,6 +40,7 @@ use std::thread; const APP_NAME: &str = "sysboostd"; const DEFAULT_TIMEOUT: u32 = 10; +const PROFILE_PATH_DEFAULT: &str = "/usr/lib/sysboost.d/profile/mysqld.profile"; fn parameter_wrong_exit() { println!("parameter is wrong"); @@ -49,6 +55,13 @@ fn main() { let mut timeout = DEFAULT_TIMEOUT; let mut name = ""; + let mut is_bolt = false; + let mut bolt_option = ""; + let mut profile_path = ""; + let mut bolt_elf_name = ""; + + let mut is_stop = false; + let mut stop_elf_name = ""; // arg0 is program name, parameter is from arg1 for i in 1..args.len() { if args[i].contains("--gen-profile=") { @@ -67,7 +80,35 @@ fn main() { } continue; } - + if args[i].contains("--gen-bolt=") { + if let Some(index) = args[i].find('=') { + is_bolt = true; + bolt_elf_name = &args[i][index + 1..]; + } + continue; + } + if args[i].contains("--bolt-option=") { + if let Some(index) = args[i].find('=') { + bolt_option = &args[i][index + 1..]; + } + continue; + } + if args[i].contains("--profile-path=") { + if let Some(index) = args[i].find('=') { + profile_path = &args[i][index + 1..]; + } + continue; + } + if args[i].contains("--stop=") { + if let Some(index) = args[i].find('=') { + is_stop = true; + stop_elf_name = &args[i][index + 1..]; + } + if stop_elf_name.is_empty() { + parameter_wrong_exit(); + } + continue; + } match args[i].as_str() { "--debug" => { is_debug = true; @@ -93,6 +134,26 @@ fn main() { // 配置文件解析 parse_sysinit_config(); parse_crashed_log(); + //sysboostd --gen-bolt="/path/to/mysqld" --bolt-option="xxx" --profile-path="/path/to/mysqld.profile" + if is_bolt { + if profile_path.is_empty() { + profile_path = PROFILE_PATH_DEFAULT; + } + let ret = gen_bolt_optimize_bin(bolt_elf_name, bolt_option, profile_path); + if ret < 0 { + std::process::exit(-1); + } + std::process::exit(write_back_config(bolt_elf_name)); + } + //sysboostd --stop=/path/to/mysqld + if is_stop { + logger::init_log_to_console(APP_NAME, log::LevelFilter::Debug); + let ret = stop_one_elf(stop_elf_name); + if ret < 0 { + std::process::exit(-1); + } + std::process::exit(delete_one_record(stop_elf_name)); + } if is_gen_porfile { logger::init_log_to_console(APP_NAME, log::LevelFilter::Debug); std::process::exit(gen_profile(name, timeout));