added 2 changesets to branch 'refs/remotes/pdziepak-github/scheduler' old head: d897a478d7c01054aad29b23f7f545073c797530 new head: e2ff9a2865beeabed2dbe7cc2b975b377cd12087 overview: https://github.com/pdziepak/Haiku/compare/d897a47...e2ff9a2 ---------------------------------------------------------------------------- f14e456: kernel: Use CPU topology to distribute IRQs e2ff9a2: scheduler: Rebalance IRQs on overloaded cores [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 2 files changed, 71 insertions(+), 3 deletions(-) src/system/kernel/int.cpp | 21 ++++++++++- src/system/kernel/scheduler/scheduler.cpp | 53 ++++++++++++++++++++++++++- ############################################################################ Commit: f14e4567e81270bf6ddf1a3abfef662885763e3d Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Nov 18 04:32:51 2013 UTC kernel: Use CPU topology to distribute IRQs ---------------------------------------------------------------------------- diff --git a/src/system/kernel/int.cpp b/src/system/kernel/int.cpp index cfea6fe..baed8fd 100644 --- a/src/system/kernel/int.cpp +++ b/src/system/kernel/int.cpp @@ -67,7 +67,8 @@ struct io_vector { #endif }; -static uint32 sLastCPU; +static int32 sLastCPU; + static struct io_vector sVectors[NUM_IO_VECTORS]; static bool sAllocatedIOInterruptVectors[NUM_IO_VECTORS]; static mutex sIOInterruptVectorAllocationLock @@ -387,6 +388,22 @@ restore_interrupts(cpu_status status) } +static +uint32 assign_cpu(void) +{ + int32 nextID = atomic_add(&sLastCPU, 1); + cpu_topology_node* node = get_cpu_topology(); + + while (node->level != CPU_TOPOLOGY_SMT) { + int levelSize = node->children_count; + node = node->children[nextID % levelSize]; + nextID /= levelSize; + } + + return node->id; +} + + /*! Install a handler to be called when an interrupt is triggered for the given interrupt number with \a data as the argument. */ @@ -426,7 +443,7 @@ install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, if (sVectors[vector].type == INTERRUPT_TYPE_IRQ && sVectors[vector].handler_list == NULL) { - int32 cpuID = atomic_add(&sLastCPU, 1) % smp_get_num_cpus(); + int32 cpuID = assign_cpu(); arch_int_assign_to_cpu(vector, cpuID); ASSERT(sVectors[vector].assigned_cpu.cpu == -1); ############################################################################ Commit: e2ff9a2865beeabed2dbe7cc2b975b377cd12087 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Mon Nov 18 06:05:35 2013 UTC scheduler: Rebalance IRQs on overloaded cores ---------------------------------------------------------------------------- diff --git a/src/system/kernel/scheduler/scheduler.cpp b/src/system/kernel/scheduler/scheduler.cpp index 86760d5..e8cbffb 100644 --- a/src/system/kernel/scheduler/scheduler.cpp +++ b/src/system/kernel/scheduler/scheduler.cpp @@ -64,7 +64,9 @@ const bigtime_t kCacheExpire = 100000; const int kTargetLoad = kMaxLoad * 55 / 100; const int kHighLoad = kMaxLoad * 70 / 100; +const int kVeryHighLoad = (kMaxLoad + kHighLoad) / 2; const int kLoadDifference = kMaxLoad * 20 / 100; +const int kLowLoad = kLoadDifference / 2; static bigtime_t sDisableSmallTaskPacking; static int32 sSmallTaskCore; @@ -76,6 +78,7 @@ static rw_spinlock sSchedulerModeLock = B_RW_SPINLOCK_INITIALIZER; static int32 (*sChooseCore)(Thread* thread); static bool (*sShouldRebalance)(Thread* thread); +static void (*sRebalanceIRQs)(void); // Heaps in sCPUPriorityHeaps are used for load balancing on a core the logical @@ -893,7 +896,7 @@ should_rebalance_power_saving(Thread* thread) if (coreEntry->fLoad > kHighLoad) { if (!is_task_small(thread)) return true; - } else if (coreEntry->fLoad > (kHighLoad + kMaxLoad) / 2) + } else if (coreEntry->fLoad > kVeryHighLoad) disable_small_task_packing(); } @@ -924,6 +927,48 @@ should_rebalance(Thread* thread) } +static void +rebalance_irqs_low_latency(void) +{ + cpu_ent* cpu = get_cpu_struct(); + SpinLocker locker(cpu->irqs_lock); + + irq_assignment* chosen = NULL; + irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs); + + int32 totalLoad = 0; + while (irq != NULL) { + if (chosen == NULL || chosen->load < irq->load) + chosen = irq; + totalLoad += irq->load; + irq = (irq_assignment*)list_get_next_item(&cpu->irqs, irq); + } + + locker.Unlock(); + + if (chosen == NULL || totalLoad < kLowLoad) + return; + + SpinLocker coreLocker(sCoreHeapsLock); + CoreEntry* other = sCoreLoadHeap->PeekMinimum(); + if (other == NULL) + other = sCoreHighLoadHeap->PeekMinimum(); + coreLocker.Unlock(); + + ASSERT(other != NULL); + + int32 thisCore = sCPUToCore[smp_get_current_cpu()]; + if (other->fCoreID == thisCore) + return; + + if (other->fLoad + kLoadDifference >= sCoreEntries[thisCore].fLoad) + return; + + int32 newCPU = choose_cpu(other->fCoreID); + assign_io_interrupt_to_cpu(chosen->irq, newCPU); +} + + static inline void compute_cpu_load(int32 cpu) { @@ -934,6 +979,9 @@ compute_cpu_load(int32 cpu) if (oldLoad < 0) return; + if (sCPUEntries[cpu].fLoad > kVeryHighLoad) + sRebalanceIRQs(); + if (oldLoad != sCPUEntries[cpu].fLoad) { int32 core = sCPUToCore[cpu]; @@ -1625,13 +1673,16 @@ scheduler_set_operation_mode(scheduler_mode mode) case SCHEDULER_MODE_LOW_LATENCY: sDisableSmallTaskPacking = -1; sSmallTaskCore = -1; + sChooseCore = choose_core_low_latency; sShouldRebalance = should_rebalance_low_latency; + sRebalanceIRQs = rebalance_irqs_low_latency; break; case SCHEDULER_MODE_POWER_SAVING: sDisableSmallTaskPacking = 0; sSmallTaskCore = -1; + sChooseCore = choose_core_power_saving; sShouldRebalance = should_rebalance_power_saving; break;