diff --git a/core/src/validator.rs b/core/src/validator.rs index 46dfb0423b..544a81f6fb 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -120,7 +120,6 @@ pub struct ValidatorConfig { pub max_genesis_archive_unpacked_size: u64, pub wal_recovery_mode: Option, pub poh_verify: bool, // Perform PoH verification during blockstore processing at boo - pub cuda: bool, pub require_tower: bool, pub tower_path: Option, pub debug_keys: Option>>, @@ -177,7 +176,6 @@ impl Default for ValidatorConfig { max_genesis_archive_unpacked_size: MAX_GENESIS_ARCHIVE_UNPACKED_SIZE, wal_recovery_mode: None, poh_verify: true, - cuda: false, require_tower: false, tower_path: None, debug_keys: None, @@ -302,8 +300,6 @@ impl Validator { } } - report_target_features(); - for cluster_entrypoint in &cluster_entrypoints { info!("entrypoint: {:?}", cluster_entrypoint); } @@ -1419,7 +1415,26 @@ fn wait_for_supermajority( Ok(true) } -fn report_target_features() { +fn is_rosetta_emulated() -> bool { + #[cfg(target_os = "macos")] + { + use std::str::FromStr; + std::process::Command::new("sysctl") + .args(&["-in", "sysctl.proc_translated"]) + .output() + .map_err(|_| ()) + .and_then(|output| String::from_utf8(output.stdout).map_err(|_| ())) + .and_then(|stdout| u8::from_str(stdout.trim()).map_err(|_| ())) + .map(|enabled| enabled == 1) + .unwrap_or(false) + } + #[cfg(not(target_os = "macos"))] + { + false + } +} + +pub fn report_target_features() { warn!( "CUDA is {}abled", if solana_perf::perf_libs::api().is_some() { @@ -1429,40 +1444,47 @@ fn report_target_features() { } ); - // We exclude Mac OS here to be compatible with computers that have Mac M1 chips. - // For these computers, one must install rust/cargo/brew etc. using Rosetta 2, - // which allows them to run software targeted for x86_64 on an aarch64. - // Hence the code below will run on these machines (target_arch="x86_64") - // if we don't exclude with target_os="macos". - // - // It's going to require more more work to get Solana building - // on Mac M1's without Rosetta, - // and when that happens we should remove this - // (the feature flag for code targeting that is target_arch="aarch64") - #[cfg(all( - any(target_arch = "x86", target_arch = "x86_64"), - not(target_os = "macos") - ))] - { + if !is_rosetta_emulated() { unsafe { check_avx() }; + unsafe { check_avx2() }; } } // Validator binaries built on a machine with AVX support will generate invalid opcodes // when run on machines without AVX causing a non-obvious process abort. Instead detect // the mismatch and error cleanly. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[target_feature(enable = "avx")] unsafe fn check_avx() { if is_x86_feature_detected!("avx") { info!("AVX detected"); } else { error!( - "Your machine does not have AVX support, please rebuild from source on your machine" + "Incompatible CPU detected: missing AVX support. Please build from source on the target" ); abort(); } } +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +unsafe fn check_avx() {} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[target_feature(enable = "avx2")] +unsafe fn check_avx2() { + if is_x86_feature_detected!("avx2") { + info!("AVX2 detected"); + } else { + error!( + "Incompatible CPU detected: missing AVX2 support. Please build from source on the target" + ); + abort(); + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +unsafe fn check_avx2() {} + // Get the activated stake percentage (based on the provided bank) that is visible in gossip fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: bool) -> u64 { let mut online_stake = 0; diff --git a/local-cluster/src/validator_configs.rs b/local-cluster/src/validator_configs.rs index e267008d33..424d9de25a 100644 --- a/local-cluster/src/validator_configs.rs +++ b/local-cluster/src/validator_configs.rs @@ -36,7 +36,6 @@ pub fn safe_clone_config(config: &ValidatorConfig) -> ValidatorConfig { max_genesis_archive_unpacked_size: config.max_genesis_archive_unpacked_size, wal_recovery_mode: config.wal_recovery_mode.clone(), poh_verify: config.poh_verify, - cuda: config.cuda, require_tower: config.require_tower, tower_path: config.tower_path.clone(), debug_keys: config.debug_keys.clone(), diff --git a/validator/src/bin/solana-test-validator.rs b/validator/src/bin/solana-test-validator.rs index 992eaec10b..0039ecc2c1 100644 --- a/validator/src/bin/solana-test-validator.rs +++ b/validator/src/bin/solana-test-validator.rs @@ -282,6 +282,112 @@ fn main() { ) .get_matches(); + let ledger_path = value_t_or_exit!(matches, "ledger_path", PathBuf); + let reset_ledger = matches.is_present("reset"); + let output = if matches.is_present("quiet") { + Output::None + } else if matches.is_present("log") { + Output::Log + } else { + Output::Dashboard + }; + let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap()); + let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| { + println!( + "Error: Unable to lock {} directory. Check if another validator is running", + ledger_path.display() + ); + exit(1); + }); + + if reset_ledger { + remove_directory_contents(&ledger_path).unwrap_or_else(|err| { + println!("Error: Unable to remove {}: {}", ledger_path.display(), err); + exit(1); + }) + } + solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&ledger_path); + + let validator_log_symlink = ledger_path.join("validator.log"); + let logfile = if output != Output::Log { + let validator_log_with_timestamp = format!( + "validator-{}.log", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + ); + + let _ = fs::remove_file(&validator_log_symlink); + symlink::symlink_file(&validator_log_with_timestamp, &validator_log_symlink).unwrap(); + + Some( + ledger_path + .join(validator_log_with_timestamp) + .into_os_string() + .into_string() + .unwrap(), + ) + } else { + None + }; + let _logger_thread = redirect_stderr_to_file(logfile); + + if !ledger_path.exists() { + fs::create_dir(&ledger_path).unwrap_or_else(|err| { + println!( + "Error: Unable to create directory {}: {}", + ledger_path.display(), + err + ); + exit(1); + }); + } + + let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap()); + let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| { + println!( + "Error: Unable to lock {} directory. Check if another validator is running", + ledger_path.display() + ); + exit(1); + }); + + if reset_ledger { + remove_directory_contents(&ledger_path).unwrap_or_else(|err| { + println!("Error: Unable to remove {}: {}", ledger_path.display(), err); + exit(1); + }) + } + solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&ledger_path); + + let validator_log_symlink = ledger_path.join("validator.log"); + let logfile = if output != Output::Log { + let validator_log_with_timestamp = format!( + "validator-{}.log", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + ); + + let _ = fs::remove_file(&validator_log_symlink); + symlink::symlink_file(&validator_log_with_timestamp, &validator_log_symlink).unwrap(); + + Some( + ledger_path + .join(validator_log_with_timestamp) + .into_os_string() + .into_string() + .unwrap(), + ) + } else { + None + }; + let _logger_thread = redirect_stderr_to_file(logfile); + + solana_core::validator::report_target_features(); + // TODO: Ideally test-validator should *only* allow private addresses. let socket_addr_space = SocketAddrSpace::new(/*allow_private_addr=*/ true); let cli_config = if let Some(config_file) = matches.value_of("config_file") { @@ -302,15 +408,6 @@ fn main() { .unwrap_or_else(|_| (Keypair::new().pubkey(), true)) }); - let ledger_path = value_t_or_exit!(matches, "ledger_path", PathBuf); - let reset_ledger = matches.is_present("reset"); - let output = if matches.is_present("quiet") { - Output::None - } else if matches.is_present("log") { - Output::Log - } else { - Output::Dashboard - }; let rpc_port = value_t_or_exit!(matches, "rpc_port", u16); let faucet_port = value_t_or_exit!(matches, "faucet_port", u16); let slots_per_epoch = value_t!(matches, "slots_per_epoch", Slot).ok(); @@ -394,59 +491,6 @@ fn main() { None }; - if !ledger_path.exists() { - fs::create_dir(&ledger_path).unwrap_or_else(|err| { - println!( - "Error: Unable to create directory {}: {}", - ledger_path.display(), - err - ); - exit(1); - }); - } - - let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap()); - let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| { - println!( - "Error: Unable to lock {} directory. Check if another validator is running", - ledger_path.display() - ); - exit(1); - }); - - if reset_ledger { - remove_directory_contents(&ledger_path).unwrap_or_else(|err| { - println!("Error: Unable to remove {}: {}", ledger_path.display(), err); - exit(1); - }) - } - solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&ledger_path); - - let validator_log_symlink = ledger_path.join("validator.log"); - let logfile = if output != Output::Log { - let validator_log_with_timestamp = format!( - "validator-{}.log", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_millis() - ); - - let _ = fs::remove_file(&validator_log_symlink); - symlink::symlink_file(&validator_log_with_timestamp, &validator_log_symlink).unwrap(); - - Some( - ledger_path - .join(validator_log_with_timestamp) - .into_os_string() - .into_string() - .unwrap(), - ) - } else { - None - }; - let _logger_thread = redirect_stderr_to_file(logfile); - let faucet_lamports = sol_to_lamports(value_of(&matches, "faucet_sol").unwrap()); let faucet_keypair_file = ledger_path.join("faucet-keypair.json"); if !faucet_keypair_file.exists() { diff --git a/validator/src/main.rs b/validator/src/main.rs index c14a0c9ed8..b3213f8042 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -2076,6 +2076,33 @@ pub fn main() { .exit(); })); + let logfile = { + let logfile = matches + .value_of("logfile") + .map(|s| s.into()) + .unwrap_or_else(|| format!("solana-validator-{}.log", identity_keypair.pubkey())); + + if logfile == "-" { + None + } else { + println!("log file: {}", logfile); + Some(logfile) + } + }; + let use_progress_bar = logfile.is_none(); + let _logger_thread = redirect_stderr_to_file(logfile); + + info!("{} {}", crate_name!(), solana_version::version!()); + info!("Starting validator with: {:#?}", std::env::args_os()); + + let cuda = matches.is_present("cuda"); + if cuda { + solana_perf::perf_libs::init_cuda(); + enable_recycler_warming(); + } + + solana_core::validator::report_target_features(); + let authorized_voter_keypairs = keypairs_of(&matches, "authorized_voter_keypairs") .map(|keypairs| keypairs.into_iter().map(Arc::new).collect()) .unwrap_or_else(|| vec![identity_keypair.clone()]); @@ -2197,7 +2224,6 @@ pub fn main() { require_tower: matches.is_present("require_tower"), tower_path: value_t!(matches, "tower", PathBuf).ok(), dev_halt_at_slot: value_t!(matches, "dev_halt_at_slot", Slot).ok(), - cuda: matches.is_present("cuda"), expected_genesis_hash: matches .value_of("expected_genesis_hash") .map(|s| Hash::from_str(s).unwrap()), @@ -2471,25 +2497,6 @@ pub fn main() { exit(1); }); - let logfile = { - let logfile = matches - .value_of("logfile") - .map(|s| s.into()) - .unwrap_or_else(|| format!("solana-validator-{}.log", identity_keypair.pubkey())); - - if logfile == "-" { - None - } else { - println!("log file: {}", logfile); - Some(logfile) - } - }; - let use_progress_bar = logfile.is_none(); - let _logger_thread = redirect_stderr_to_file(logfile); - - info!("{} {}", crate_name!(), solana_version::version!()); - info!("Starting validator with: {:#?}", std::env::args_os()); - let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default())); admin_rpc_service::run( &ledger_path, @@ -2594,10 +2601,6 @@ pub fn main() { solana_metrics::set_host_id(identity_keypair.pubkey().to_string()); solana_metrics::set_panic_hook("validator"); - if validator_config.cuda { - solana_perf::perf_libs::init_cuda(); - enable_recycler_warming(); - } solana_ledger::entry::init_poh(); solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&snapshot_output_dir);