|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | use { | 
|  | anyhow::Error, | 
|  | blobfs_stress_test_lib::{state::BlobfsState, utils::init_blobfs}, | 
|  | fuchsia_async as fasync, | 
|  | log::{info, set_logger, set_max_level, LevelFilter}, | 
|  | rand::{rngs::SmallRng, FromEntropy, Rng, SeedableRng}, | 
|  | structopt::StructOpt, | 
|  | }; | 
|  |  | 
|  | #[derive(Clone, StructOpt, Debug)] | 
|  | #[structopt( | 
|  | name = "blobfs stress test (blobfs_stressor) tool", | 
|  | about = "Creates an instance of blobfs and performs stressful operations on it" | 
|  | )] | 
|  |  | 
|  | struct Opt { | 
|  | /// Seed to use for this stressor instance | 
|  | #[structopt(short = "s", long = "seed")] | 
|  | seed: Option<u128>, | 
|  |  | 
|  | /// Number of operations to complete before exiting. | 
|  | /// Otherwise stressor will run indefinitely. | 
|  | #[structopt(short = "ops", long = "num_operations")] | 
|  | num_operations: Option<u64>, | 
|  |  | 
|  | /// Filter logging by level (off, error, warn, info, debug, trace) | 
|  | #[structopt(short = "l", long = "log_filter", default_value = "info")] | 
|  | log_filter: LevelFilter, | 
|  | } | 
|  |  | 
|  | // A simple logger that logs to stdout | 
|  | struct SimpleLogger; | 
|  |  | 
|  | impl log::Log for SimpleLogger { | 
|  | fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool { | 
|  | true | 
|  | } | 
|  |  | 
|  | fn log(&self, record: &log::Record<'_>) { | 
|  | if self.enabled(record.metadata()) { | 
|  | if record.level() == log::Level::Info { | 
|  | println!("{}", record.args()); | 
|  | } else { | 
|  | println!("{}: {}", record.level(), record.args()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn flush(&self) {} | 
|  | } | 
|  |  | 
|  | #[fasync::run_singlethreaded] | 
|  | async fn main() -> Result<(), Error> { | 
|  | // Get arguments from command line | 
|  | let opt = Opt::from_args(); | 
|  |  | 
|  | // Initialize SimpleLogger (just prints to stdout) | 
|  | set_logger(&SimpleLogger).expect("Failed to set SimpleLogger as global logger"); | 
|  | set_max_level(opt.log_filter); | 
|  |  | 
|  | let seed = if let Some(seed_value) = opt.seed { | 
|  | seed_value | 
|  | } else { | 
|  | // Use entropy to generate a new seed | 
|  | let mut temp_rng = SmallRng::from_entropy(); | 
|  | temp_rng.gen() | 
|  | }; | 
|  |  | 
|  | info!("------------------ blobfs_stressor is starting -------------------"); | 
|  | info!("ARGUMENTS = {:#?}", opt); | 
|  | info!("SEED FOR THIS INVOCATION = {}", seed); | 
|  | info!("------------------------------------------------------------------"); | 
|  |  | 
|  | // Setup a panic handler that prints out details of this invocation | 
|  | let seed_clone = seed.clone(); | 
|  | let opt_clone = opt.clone(); | 
|  | let default_panic_hook = std::panic::take_hook(); | 
|  | std::panic::set_hook(Box::new(move |panic_info| { | 
|  | println!(""); | 
|  | println!("------------------ blobfs_stressor has crashed -------------------"); | 
|  | println!("ARGUMENTS = {:#?}", opt_clone); | 
|  | println!("SEED FOR THIS INVOCATION = {}", seed_clone); | 
|  | println!("------------------------------------------------------------------"); | 
|  | println!(""); | 
|  | default_panic_hook(panic_info); | 
|  | })); | 
|  |  | 
|  | // Setup blobfs and wait until it is ready | 
|  | let (_test, root_dir) = init_blobfs().await; | 
|  |  | 
|  | // Initialize blobfs in-memory state | 
|  | let rng = SmallRng::from_seed(seed.to_le_bytes()); | 
|  | let mut state = BlobfsState::new(root_dir, rng); | 
|  |  | 
|  | if let Some(num_operations) = opt.num_operations { | 
|  | info!("Performing {} operations...", num_operations); | 
|  | for _ in 0..num_operations { | 
|  | state.do_random_operation().await; | 
|  | } | 
|  | } else { | 
|  | info!("Running indefinitely..."); | 
|  | loop { | 
|  | state.do_random_operation().await; | 
|  | } | 
|  | } | 
|  |  | 
|  | info!("Run successful!"); | 
|  |  | 
|  | Ok(()) | 
|  | } |