From: Jan Kiszka <[email protected]>

Currently, the for_each_cpu iterators scan the whole given CPU set
bitwise. Since we use static CPU set sizes, we scan even more bits
needlessly for most workloads. This is particularly relevant for sending
IPIs that go out to a set of CPUs.

But the common case of having a small and non-sparse bitmap can easily
be optimized by scanning the lower and upper boundaries once during
setup of the CPU set and then using those limits in for_each_cpu*.

At this chance, reduce the type of the boundaries to unsigned int
because we do not support 4 billion CPUs anyway.

Signed-off-by: Jan Kiszka <[email protected]>
---
 hypervisor/control.c                   | 26 +++++++++++++++++++++++---
 hypervisor/include/jailhouse/control.h |  4 ++--
 hypervisor/include/jailhouse/types.h   |  6 ++++--
 3 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/hypervisor/control.c b/hypervisor/control.c
index 8eaaa46a..7a5304a0 100644
--- a/hypervisor/control.c
+++ b/hypervisor/control.c
@@ -58,6 +58,25 @@ unsigned int next_cpu(unsigned int cpu, struct cpu_set 
*cpu_set,
        return cpu;
 }
 
+/**
+ * Update CPU set min/max boundaries.
+ * @param cpu_set      CPU set to update.
+ *
+ * @note For internal use only. CPU set must not be empty.
+ */
+static void cpu_set_update(struct cpu_set *cpu_set)
+{
+       unsigned int cpu, max_cpu = 0;
+
+       cpu_set->min_cpu_id = 0;
+       cpu_set->max_cpu_id = sizeof(cpu_set->bitmap) * 8 - 1;
+
+       cpu_set->min_cpu_id = first_cpu(cpu_set);
+       for_each_cpu(cpu, cpu_set)
+               max_cpu = cpu;
+       cpu_set->max_cpu_id = max_cpu;
+}
+
 /**
  * Suspend a remote CPU.
  * @param cpu_id       ID of the target CPU.
@@ -226,12 +245,10 @@ int cell_init(struct cell *cell)
 {
        const struct jailhouse_cpu *cell_cpu =
                jailhouse_cell_cpus(cell->config);
-       unsigned long cpu_set_size = (cell->config->num_cpus + 7) / 8;
        unsigned int cpu_idx, result;
 
-       if (cpu_set_size > sizeof(cell->cpu_set.bitmap))
+       if (cell->config->num_cpus > sizeof(cell->cpu_set.bitmap) * 8)
                return trace_error(-EINVAL);
-       cell->cpu_set.max_cpu_id = cpu_set_size * 8 - 1;
 
        for (cpu_idx = 0; cpu_idx < cell->config->num_cpus; cpu_idx++) {
                result = cpu_by_phys_processor_id(cell_cpu[cpu_idx].phys_id);
@@ -240,6 +257,7 @@ int cell_init(struct cell *cell)
 
                set_bit(result, cell->cpu_set.bitmap);
        }
+       cpu_set_update(&cell->cpu_set);
 
        return mmio_cell_init(cell);
 }
@@ -358,6 +376,7 @@ static void cell_destroy_internal(struct cell *cell)
                memset(public_per_cpu(cpu)->stats, 0,
                       sizeof(public_per_cpu(cpu)->stats));
        }
+       cpu_set_update(&root_cell.cpu_set);
 
        for_each_mem_region(mem, cell->config, n) {
                if (!JAILHOUSE_MEMORY_IS_SUBPAGE(mem))
@@ -493,6 +512,7 @@ static int cell_create(struct per_cpu *cpu_data, unsigned 
long config_address)
                memset(public_per_cpu(cpu)->stats, 0,
                       sizeof(public_per_cpu(cpu)->stats));
        }
+       cpu_set_update(&root_cell.cpu_set);
 
        /*
         * Unmap the cell's memory regions from the root cell and map them to
diff --git a/hypervisor/include/jailhouse/control.h 
b/hypervisor/include/jailhouse/control.h
index f01af617..2e2446f0 100644
--- a/hypervisor/include/jailhouse/control.h
+++ b/hypervisor/include/jailhouse/control.h
@@ -44,7 +44,7 @@ unsigned int next_cpu(unsigned int cpu, struct cpu_set 
*cpu_set,
  *
  * @return First CPU in set, or max_cpu_id + 1 if the set is empty.
  */
-#define first_cpu(set)         next_cpu(INVALID_CPU_ID, (set), INVALID_CPU_ID)
+#define first_cpu(set) next_cpu((set)->min_cpu_id - 1, (set), INVALID_CPU_ID)
 
 /**
  * Loop-generating macro for iterating over all CPUs in a set.
@@ -67,7 +67,7 @@ unsigned int next_cpu(unsigned int cpu, struct cpu_set 
*cpu_set,
  * @see for_each_cpu
  */
 #define for_each_cpu_except(cpu, set, exception)               \
-       for ((cpu) = -1;                                        \
+       for ((cpu) = (set)->min_cpu_id - 1;                     \
             (cpu) = next_cpu((cpu), (set), (exception)),       \
             (cpu) <= (set)->max_cpu_id;                        \
            )
diff --git a/hypervisor/include/jailhouse/types.h 
b/hypervisor/include/jailhouse/types.h
index 5ca81034..f8580f2f 100644
--- a/hypervisor/include/jailhouse/types.h
+++ b/hypervisor/include/jailhouse/types.h
@@ -23,8 +23,10 @@ typedef enum { true = 1, false = 0 } bool;
 
 /** Describes a CPU set. */
 struct cpu_set {
-       /** Maximum CPU ID expressible with this set. */
-       unsigned long max_cpu_id;
+       /** Smallest CPU ID in the set. */
+       unsigned int min_cpu_id;
+       /** Largest CPU ID in the set. */
+       unsigned int max_cpu_id;
        /** Bitmap of CPUs in the set. */
        unsigned long bitmap[(MAX_CPUS + BITS_PER_LONG - 1) / BITS_PER_LONG];
 };
-- 
2.36.1

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/20220627131329.3659-20-ralf.ramsauer%40oth-regensburg.de.

Reply via email to