1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
// Copyright (c) Facebook, Inc. and its affiliates.
use anyhow::Result;
use chrono::prelude::*;
use serde::{Deserialize, Serialize};
use std::time::SystemTime;

use rd_util::*;

pub const BENCH_FILENAME: &str = "bench.json";

const BENCH_DOC: &str = "\
//
// rd-agent benchmark results
//
//  timestamp: When this report was generated
//  hashd_seq: Current rd-hashd bench result sequence, see cmd.json
//  iocost_seq: Current iocost bench result sequence, see cmd.json
//  hashd[].hash_size: Mean hash size which determines CPU usage
//  hashd[].rps_max: Maximum RPS
//  hashd[].mem_size: Memory size base
//  hashd[].mem_frac: Memory size is mem_size * mem_frac, tune this if needed
//  hashd[].chunk_pages: Memory access chunk size in pages
//  hashd[].fake_cpu_load: Bench was run with --bench-fake-cpu-load
//  iocost.devnr: Storage device devnr
//  iocost.model: Model parameters
//  iocost.qos: QoS parameters
//
";

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct HashdKnobs {
    pub hash_size: usize,
    pub rps_max: u32,
    pub mem_size: u64,
    pub mem_frac: f64,
    pub chunk_pages: usize,
    pub fake_cpu_load: bool,
}

impl std::fmt::Display for HashdKnobs {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "hash_size={} rps_max={} mem_actual={} chunk_pages={}{}",
            format_size(self.hash_size),
            self.rps_max,
            format_size(self.actual_mem_size()),
            self.chunk_pages,
            if self.fake_cpu_load {
                " fake_cpu_load"
            } else {
                ""
            }
        )
    }
}

impl HashdKnobs {
    pub fn actual_mem_size(&self) -> u64 {
        (self.mem_size as f64 * self.mem_frac).ceil() as u64
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
pub struct IoCostKnobs {
    pub devnr: String,
    pub model: IoCostModelParams,
    pub qos: IoCostQoSParams,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BenchKnobs {
    pub timestamp: DateTime<Local>,
    pub hashd_seq: u64,
    pub iocost_seq: u64,
    pub hashd: HashdKnobs,
    pub iocost: IoCostKnobs,
    pub iocost_dev_model: String,
    pub iocost_dev_fwrev: String,
    pub iocost_dev_size: u64,
}

impl Default for BenchKnobs {
    fn default() -> Self {
        Self {
            timestamp: DateTime::from(SystemTime::now()),
            hashd_seq: 0,
            iocost_seq: 0,
            hashd: Default::default(),
            iocost: Default::default(),
            iocost_dev_model: String::new(),
            iocost_dev_fwrev: String::new(),
            iocost_dev_size: 0,
        }
    }
}

impl JsonLoad for BenchKnobs {
    fn loaded(&mut self, _prev: Option<&mut Self>) -> Result<()> {
        self.iocost.qos.sanitize();
        Ok(())
    }
}

impl JsonSave for BenchKnobs {
    fn preamble() -> Option<String> {
        Some(BENCH_DOC.to_string())
    }
}