Repository: criteo/hwbench

Issue:
[FEATURE] Improve CPU pinning reporting
The current code reports the cpu pinning as a list of processors like

[full_cpu_load_0] stressng/cpu/matrixprod(M):  12 stressor pinned on CPU [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] for 15s

It would be interesting to get a synthetic with ranges, giving an output like : 
[full_cpu_load_0] stressng/cpu/matrixprod(M):  12 stressor pinned on CPU [0-11] for 15s

https://github.com/criteo/hwbench/blob/main/hwbench/config/test_parse.py#L83C35-L83C37 is already providing a test-suite for the expand, it would be nice to have one checking the opposite function and use it for the runtime reporting.

Discussion:
@ErwanAliasr1: @Arno500 if you want to take this one 

Solution patch:
diff --git a/hwbench/bench/benchmark.py b/hwbench/bench/benchmark.py
index fb7d27a..dbf06ce 100644
--- a/hwbench/bench/benchmark.py
+++ b/hwbench/bench/benchmark.py
@@ -124,7 +124,9 @@ def pre_run(self):
             if isinstance(p.get_pinned_cpu(), (int, str)):
                 cpu_location = " on CPU {:3d}".format(p.get_pinned_cpu())
             elif isinstance(p.get_pinned_cpu(), list):
-                cpu_location = " on CPU {}".format(str(p.get_pinned_cpu()))
+                cpu_location = " on CPU {}".format(
+                    h.cpu_list_to_range(p.get_pinned_cpu())
+                )
             else:
                 h.fatal(
                     "Unsupported get_pinned_cpu() format :{}".format(
diff --git a/hwbench/utils/helpers.py b/hwbench/utils/helpers.py
index b9dacd5..651d347 100644
--- a/hwbench/utils/helpers.py
+++ b/hwbench/utils/helpers.py
@@ -3,7 +3,7 @@
 import sys
 from datetime import timedelta
 from shutil import which
-from typing import NoReturn
+from typing import NoReturn, Optional
 
 
 def fatal(message) -> NoReturn:
@@ -30,3 +30,37 @@ def time_to_next_sync(safe_start=True):
 def is_binary_available(binary_name: str) -> bool:
     """A function to check if a binary is available"""
     return which(binary_name) is not None
+
+
+def cpu_list_to_range(cpu_list: list[int]) -> str:
+    """
+    This function takes a list of integers as input and will link them together in a nicely formatted string
+    - `[0, 1, 2, 3, 4, 5]` will give `"0-5"`
+    - `[0, 4, 2, 3, 7, 8, 9]` will give `"0, 2-4, 7-9"`
+
+    It was made specifically for formatting a CPU cores list
+    """
+    cpu_list.sort()
+    output: list[str] = []
+    previous_entry: Optional[int] = cpu_list[0]
+
+    for i in range(1, len(cpu_list)):
+        current_entry = cpu_list[i]
+        is_immediately_next = current_entry - 1 == cpu_list[i - 1]
+        needs_compression = cpu_list[i - 1] != previous_entry
+
+        if not is_immediately_next:
+            if needs_compression:
+                output.append(f"{previous_entry}-{cpu_list[i-1]}")
+            else:
+                output.append(str(previous_entry))
+            previous_entry = current_entry
+
+        # Specifically handle the last entry in the list
+        if i == len(cpu_list) - 1:
+            if cpu_list[i] != previous_entry:
+                output.append(f"{previous_entry}-{current_entry}")
+            else:
+                output.append(str(current_entry))
+
+    return ", ".join(output)


Test patch:
diff --git a/hwbench/utils/test_helpers.py b/hwbench/utils/test_helpers.py
new file mode 100644
index 0000000..52510eb
--- /dev/null
+++ b/hwbench/utils/test_helpers.py
@@ -0,0 +1,13 @@
+import unittest
+
+from .helpers import cpu_list_to_range
+
+
+class DisplayHelper(unittest.TestCase):
+    def test_deserialize_cpu_list_to_string(self):
+        "Make sure that the output matches the input even for invalid or weird cases"
+        assert cpu_list_to_range([0, 1, 2, 3, 4, 5]) == "0-5"
+        assert cpu_list_to_range([0, 1, 2, 3, 5]) == "0-3, 5"
+        assert cpu_list_to_range([0, 1, 3, 4, 5]) == "0-1, 3-5"
+        assert cpu_list_to_range([0, 4, 2, 7, 8, 9]) == "0, 2, 4, 7-9"
+        assert cpu_list_to_range([0, 4, 2, 3, 7, 8, 9]) == "0, 2-4, 7-9"