public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Fiona Ebner <f.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH proxmox-resource-scheduling 2/3] add pve_static module
Date: Thu, 10 Nov 2022 15:37:41 +0100	[thread overview]
Message-ID: <20221110143800.98047-3-f.ebner@proxmox.com> (raw)
In-Reply-To: <20221110143800.98047-1-f.ebner@proxmox.com>

Models usage of guests and nodes, and allows scoring nodes on which to
start a new service via TOPSIS. For this scoring, each node in turn is
considered as if the service was already running on it.

CPU and memory usage are used as criteria, with memory being weighted
much more, because it's a truly limited resource. For both, CPU and
memory, highest usage among nodes (weighted more, as ideally no node
should be overcommited) and average usage of all nodes (to still be
able to distinguish in case there already is a more highly commited
node) are considered.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
 Cargo.toml        |   2 +
 src/lib.rs        |   1 +
 src/pve_static.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+)
 create mode 100644 src/pve_static.rs

diff --git a/Cargo.toml b/Cargo.toml
index ec8e12f..85d0ec1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,3 +18,5 @@ path = "src/lib.rs"
 
 [dependencies]
 anyhow = "1.0"
+lazy_static = "1.4"
+serde = { version = "1.0", features = ["derive"] }
diff --git a/src/lib.rs b/src/lib.rs
index dda0563..c82bd40 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1 +1,2 @@
+pub mod pve_static;
 pub mod topsis;
diff --git a/src/pve_static.rs b/src/pve_static.rs
new file mode 100644
index 0000000..cb8a823
--- /dev/null
+++ b/src/pve_static.rs
@@ -0,0 +1,143 @@
+use anyhow::Error;
+use lazy_static::lazy_static;
+use serde::{Deserialize, Serialize};
+
+use crate::topsis::{TopsisCriteria, TopsisCriterion, TopsisMatrix};
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Static usage information of a node.
+pub struct StaticNodeUsage {
+    /// Hostname of the node.
+    pub name: String,
+    /// CPU utilization. Can be more than `maxcpu` if overcommited.
+    pub cpu: f64,
+    /// Total number of CPUs.
+    pub maxcpu: usize,
+    /// Used memory in bytes. Can be more than `maxmem` if overcommited.
+    pub mem: usize,
+    /// Total memory in bytes.
+    pub maxmem: usize,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// Static usage information of an HA resource.
+pub struct StaticServiceUsage {
+    /// Number of assigned CPUs or CPU limit.
+    pub maxcpu: f64,
+    /// Maximum assigned memory in bytes.
+    pub maxmem: usize,
+}
+
+/// Calculate new CPU usage in percent.
+/// `add` being `0.0` means "unlimited" and results in `max` being added.
+fn add_cpu_usage(old: f64, max: f64, add: f64) -> f64 {
+    if add == 0.0 {
+        old + max
+    } else {
+        old + add
+    }
+}
+
+impl StaticNodeUsage {
+    /// Add usage of `service` to the node's usage.
+    pub fn add_service_usage(&mut self, service: &StaticServiceUsage) {
+        self.cpu = add_cpu_usage(self.cpu, self.maxcpu as f64, service.maxcpu);
+        self.mem += service.maxmem;
+    }
+}
+
+/// A given alternative.
+struct PveTopsisAlternative {
+    average_cpu: f64,
+    highest_cpu: f64,
+    average_memory: f64,
+    highest_memory: f64,
+}
+
+const N_CRITERIA: usize = 4;
+
+// NOTE It is essenital that the order of the criteria definition and the order in the
+// From<PveTopsisAlternative> implementation match up.
+
+lazy_static! {
+    static ref PVE_HA_TOPSIS_CRITERIA: TopsisCriteria<N_CRITERIA> = TopsisCriteria::new([
+        TopsisCriterion::new("average CPU".to_string(), -1.0),
+        TopsisCriterion::new("highest CPU".to_string(), -2.0),
+        TopsisCriterion::new("average memory".to_string(), -5.0),
+        TopsisCriterion::new("highest memory".to_string(), -10.0),
+    ])
+    .unwrap();
+}
+
+impl From<PveTopsisAlternative> for [f64; N_CRITERIA] {
+    fn from(alternative: PveTopsisAlternative) -> Self {
+        [
+            alternative.average_cpu,
+            alternative.highest_cpu,
+            alternative.average_memory,
+            alternative.highest_memory,
+        ]
+    }
+}
+
+/// Scores candidate `nodes` to start a `service` on. Scoring is done according to the static memory
+/// and CPU usages of the nodes as if the service would already be running on each.
+///
+/// Returns a vector of (nodename, score) pairs. Scores are between 0.0 and 1.0 and a higher score
+/// is better.
+pub fn score_nodes_to_start_service(
+    nodes: &[&StaticNodeUsage],
+    service: &StaticServiceUsage,
+) -> Result<Vec<(String, f64)>, Error> {
+    let len = nodes.len();
+
+    let matrix = nodes
+        .iter()
+        .enumerate()
+        .map(|(target_index, _)| {
+            // all of these are as percentages to be comparable across nodes
+            let mut highest_cpu = 0.0;
+            let mut sum_cpu = 0.0;
+            let mut highest_mem = 0.0;
+            let mut sum_mem = 0.0;
+
+            for (index, node) in nodes.iter().enumerate() {
+                let new_cpu = if index == target_index {
+                    add_cpu_usage(node.cpu, node.maxcpu as f64, service.maxcpu)
+                } else {
+                    node.cpu
+                } / (node.maxcpu as f64);
+                highest_cpu = f64::max(highest_cpu, new_cpu);
+                sum_cpu += new_cpu;
+
+                let new_mem = if index == target_index {
+                    node.mem + service.maxmem
+                } else {
+                    node.mem
+                } as f64
+                    / node.maxmem as f64;
+                highest_mem = f64::max(highest_mem, new_mem);
+                sum_mem += new_mem;
+            }
+
+            PveTopsisAlternative {
+                average_cpu: sum_cpu / len as f64,
+                highest_cpu,
+                average_memory: sum_mem / len as f64,
+                highest_memory: highest_mem,
+            }
+            .into()
+        })
+        .collect::<Vec<_>>();
+
+    let scores =
+        crate::topsis::score_alternatives(&TopsisMatrix::new(matrix)?, &PVE_HA_TOPSIS_CRITERIA)?;
+
+    Ok(scores
+        .into_iter()
+        .enumerate()
+        .map(|(n, score)| (nodes[n].name.clone(), score))
+        .collect())
+}
-- 
2.30.2





  parent reply	other threads:[~2022-11-10 14:38 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-10 14:37 [pve-devel] [PATCH-SERIES proxmox-resource-scheduling/pve-ha-manager/etc] add static usage scheduler for HA manager Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH proxmox-resource-scheduling 1/3] initial commit Fiona Ebner
2022-11-15 10:15   ` [pve-devel] applied: " Wolfgang Bumiller
2022-11-15 15:39   ` [pve-devel] " DERUMIER, Alexandre
2022-11-16  9:09     ` Fiona Ebner
2022-11-10 14:37 ` Fiona Ebner [this message]
2022-11-16  9:18   ` [pve-devel] [PATCH proxmox-resource-scheduling 2/3] add pve_static module Thomas Lamprecht
2022-11-10 14:37 ` [pve-devel] [PATCH proxmox-resource-scheduling 3/3] add Debian packaging Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH proxmox-perl-rs 1/2] pve-rs: add resource scheduling module Fiona Ebner
2022-11-15 10:16   ` [pve-devel] applied-series: " Wolfgang Bumiller
2022-11-10 14:37 ` [pve-devel] [PATCH proxmox-perl-rs 2/2] add basic test for resource scheduling Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH manager 1/3] pvestatd: broadcast static node information Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH v3 manager 2/3] cluster resources: add cgroup-mode to node properties Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH v2 manager 3/3] ui: lxc/qemu: cpu edit: make cpuunits depend on node's cgroup version Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH cluster 1/1] datacenter config: add cluster resource scheduling (crs) options Fiona Ebner
2022-11-17 11:52   ` [pve-devel] applied: " Thomas Lamprecht
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 01/11] env: add get_static_node_stats() method Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 02/11] resources: add get_static_stats() method Fiona Ebner
2022-11-15 13:28   ` Thomas Lamprecht
2022-11-16  8:46     ` Fiona Ebner
2022-11-16  8:59       ` Thomas Lamprecht
2022-11-16 12:38       ` DERUMIER, Alexandre
2022-11-16 12:52         ` Thomas Lamprecht
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 03/11] add Usage base plugin and Usage::Basic plugin Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 04/11] manager: select service node: add $sid to parameters Fiona Ebner
2022-11-16  7:17   ` Thomas Lamprecht
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 05/11] manager: online node usage: switch to Usage::Basic plugin Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 06/11] usage: add Usage::Static plugin Fiona Ebner
2022-11-15 15:55   ` DERUMIER, Alexandre
2022-11-16  9:10     ` Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 07/11] env: add get_crs_settings() method Fiona Ebner
2022-11-16  7:05   ` Thomas Lamprecht
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 08/11] manager: set resource scheduler mode upon init Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 09/11] manager: use static resource scheduler when configured Fiona Ebner
2022-11-11  9:28   ` Fiona Ebner
2022-11-16  7:14     ` Thomas Lamprecht
2022-11-16  9:37       ` Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 10/11] manager: avoid scoring nodes if maintenance fallback node is valid Fiona Ebner
2022-11-10 14:37 ` [pve-devel] [PATCH ha-manager 11/11] manager: avoid scoring nodes when not trying next and current " Fiona Ebner
2022-11-10 14:38 ` [pve-devel] [PATCH docs 1/1] ha: add section about scheduler modes Fiona Ebner
2022-11-15 13:12 ` [pve-devel] partially-applied: [PATCH-SERIES proxmox-resource-scheduling/pve-ha-manager/etc] add static usage scheduler for HA manager Thomas Lamprecht

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221110143800.98047-3-f.ebner@proxmox.com \
    --to=f.ebner@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal