除鏽壓力測試程式庫

本文說明如何使用信任壓力測試編寫「壓力測試」 資源庫。你可以在 //src/sys/lib/stress-test 找到程式庫。它會實作測試迴圈 執行這些測試所需的並行和同步基元。

撰寫壓力檢測

定義 GN 建構目標

定義 rustc_binaryfuchsia_componentfuchsia_test_package GN 建構目標 測試:

rustc_binary("filesystem-stressor-bin") {
    deps = [
        ...
        "//src/sys/lib/stress-test",
        ...
    ]
    sources = [
        ...
    ]
}

fuchsia_component("filesystem-stressor") {
    deps = [ ":filesystem-stressor-bin" ]
    manifest = "meta/filesystem-stressor.cml"
    testonly = true
}

fuchsia_test_package("filesystem-stress-tests") {
  test_components = [
    ":filesystem-stressor"
  ]
}

編寫演員

每位演員都必須實作 Actor 特徵。演員特徵是 perform() 的其中一種方法, 呼叫 ActorRunner。叫用時,執行者只能執行一項作業並傳回 傳送到執行元件的結果執行者必須儲存執行作業所需的所有連線。

pub trait Actor: Sync + Send + 'static {
    // ActorRunner invokes this function, instructing the actor
    // to perform exactly one operation and return result.
    async fn perform(&mut self) -> Result<(), ActorError>;
}

執行者可以透過傳回結果來指出下列內容:

  • Ok(()):作業成功,已新增至全域作業數量中。

  • Err(ActorError::DoNotCount):這項作業不會計入全域作業中 數量。

  • Err(ActorError::ResetEnvironment):必須重設環境,且不得執行作業 會計入全球作業數量。

執行者遇到未預期的錯誤時,應該會恐慌,進而停止測試。

由於發動者是在相同的環境下作業,因此他們的作業可能會 碰撞例如,進行檔案系統壓力測試時,發動者可能會對同一組檔案執行作業。 若可發現此類衝突,您必須設定發動者妥善處理這類衝突。 否則,行為人應恐慌,導致測試停止。

發動者可以刻意破壞系統底層測試,並要求重設環境。適用對象 例如,在檔案系統壓力測試中,執行者可以隨機 檔案系統和基礎區塊裝置在這個範例中,其他演員也應要求使用新的 使用 ActorError::ResetEnvironment 的環境,且環境會重新建立連線 讓所有演員都能獲益良多

pub struct FilesystemActor {
    /// Store a connection to the root of filesystem here
    pub root_directory: Directory
    ...
}

impl FilesystemActor {
    pub fn new(root_directory: Directory) -> Self {
        ...
    }
}

#[async_trait]
impl Actor for FilesystemActor {
    async pub fn perform(&mut self) -> Result<(), ActorError> {
        // Choose exactly one operation to do on the filesystem
        // using the root_directory
        self.root_directory.delete_all_files();
    }
}

寫入環境

環境提供壓力測試的基本設定,包括結束條件、 和重設方法

pub trait Environment: Send + Sync + Debug {
    /// Returns the target number of operations to complete before exiting
    fn target_operations(&self) -> Option<u64>;

    /// Returns the number of seconds to wait before exiting
    fn timeout_seconds(&self) -> Option<u64>;

    /// Return the runners for all the actors
    async fn actor_runners(&mut self) -> Vec<ActorRunner>;

    /// Reset the environment, when an actor requests one
    async fn reset(&mut self);
}

環境可以儲存測試的其他設定。我們可以提供這項設定 透過指令列加上 argh Crate。

執行者會由執行元件和環境共用,因此必須包裝為 Arc<Mutex<dyn Actor>>。跑者在執行作業時保持鎖頭。 這表示環境只能在作業之間取得執行者的鎖定。

行為人判定 系統下層測試已故障環境應會為 並鎖定發動者,以更新他們與新的執行個體之間的連線。

環境也必須實作 Debug 特徵。壓力測試會記錄環境 測試開始,以及測試是否恐慌時。一般做法是輸出 以便重現測試,例如使用的隨機種子。

#[derive(Debug)]
pub struct FilesystemEnvironment {
    fs_actor: Arc<Mutex<FilesystemActor>>,
    seed: u64,
    ...
}

impl Environment {
    pub fn new() -> Self {
        ...
    }
}

#[async_trait]
impl Environment for FilesystemEnvironment {
    fn target_operations(&self) -> Option<u64> {
        // By specifying None here, the test will run without an operation limit
        None
    }

    fn timeout_seconds(&self) -> Option<u64> {
        // By specifying None here, the test will run without a time limit
        None
    }

    async fn actor_runners(&mut self) -> Vec<ActorRunner> {
        vec![
            ActorRunner::new(
                "filesystem_actor",  // debug name
                60,  // delay (in seconds) between each operation (0 means no delay)
                self.fs_actor.clone()), // actor
            )
        ]
    }

    async fn reset(&mut self) {
        // If the actor is performing an operation, this will remain
        // locked until the operation is complete.
        let actor = self.fs_actor.lock().await;

        // Now the environment can update the actor before it is run again.
        actor.root_directory = ...;

        // Releasing the lock will resume the runner.
    }
}

編寫主函式

壓力測試的主要功能相當簡單,因為大部分的邏輯 環境和發動者。使用主要函式收集指令列 引數 (如有),初始化記錄並設定記錄嚴重性。

#[fuchsia::main]
async fn main() {
    // Create the environment
    let env = FilesystemEnvironment::new();

    // Run the test.
    // Depending on the exit criteria, this may never return.
    stress_test::run_test(env).await;
}

在本機執行壓力測試

由於壓力測試是 fuchsia_test_package 的一部分,因此執行壓力最簡單的方式之一 是執行 fx test 指令:

fx test filesystem-stress-tests

如要使用自訂指令列引數執行測試,請使用 fx shell run

fx shell run fuchsia-pkg://fuchsia.com/filesystem-stress-tests#meta/filesystem-stressor.cm <args>

對基礎架構執行壓力測試

壓力測試是由基礎架構所連接的 stress-tests 標記來識別 fuchsia_test_packagefuchsia_unittest_package GN 建構目標。

fuchsia_test_package("filesystem-stress-tests") {
  test_components = [
    ":filesystem-stressor"
  ]
  test_specs = {
    environments = [
      {
        dimensions = {
          device_type = "QEMU"
        }
        tags = [ "stress-tests" ]
      },
    ]
  }
}

專屬的 core.x64-stress 建構工具可識別這些測試,並在 最長可達 22 小時的套件

對壓力測試進行偵錯

這個架構使用信任 log Crate 記錄訊息。測試會記錄位於 看看是否會造成問題

--------------------- stressor is starting -----------------------
Environment {
    seed: 268479717856254664270968796173957499835,
    filesystem_actor: { ... }
    ...
}
------------------------------------------------------------------

如果已啟用偵錯記錄功能,系統也會記錄個別發動者作業和作業計數。

DEBUG: [0][filesystem_actor][389] Sleeping for 2 seconds
DEBUG: [0][filesystem_actor][389] Performing...
DEBUG: [0][filesystem_actor][389] Done!
DEBUG: Counters -> [total:403] {"filesystem_actor": 403}