1130803Smarcel/* 2130803Smarcel * Copyright 2013, Pawe�� Dziepak, pdziepak@quarnos.org. 3130803Smarcel * Distributed under the terms of the MIT License. 4130803Smarcel */ 5130803Smarcel 6130803Smarcel 7130803Smarcel#include <util/AutoLock.h> 8130803Smarcel 9130803Smarcel#include "scheduler_common.h" 10130803Smarcel#include "scheduler_cpu.h" 11130803Smarcel#include "scheduler_modes.h" 12130803Smarcel#include "scheduler_profiler.h" 13130803Smarcel#include "scheduler_thread.h" 14130803Smarcel 15130803Smarcel 16130803Smarcelusing namespace Scheduler; 17130803Smarcel 18130803Smarcel 19130803Smarcelconst bigtime_t kCacheExpire = 100000; 20130803Smarcel 21130803Smarcel 22130803Smarcelstatic void 23130803Smarcelswitch_to_mode() 24130803Smarcel{ 25130803Smarcel} 26130803Smarcel 27130803Smarcel 28130803Smarcelstatic void 29130803Smarcelset_cpu_enabled(int32 /* cpu */, bool /* enabled */) 30130803Smarcel{ 31130803Smarcel} 32130803Smarcel 33130803Smarcel 34130803Smarcelstatic bool 35130803Smarcelhas_cache_expired(const ThreadData* threadData) 36130803Smarcel{ 37130803Smarcel SCHEDULER_ENTER_FUNCTION(); 38130803Smarcel if (threadData->WentSleepActive() == 0) 39130803Smarcel return false; 40130803Smarcel CoreEntry* core = threadData->Core(); 41130803Smarcel bigtime_t activeTime = core->GetActiveTime(); 42130803Smarcel return activeTime - threadData->WentSleepActive() > kCacheExpire; 43130803Smarcel} 44130803Smarcel 45130803Smarcel 46130803Smarcelstatic CoreEntry* 47130803Smarcelchoose_core(const ThreadData* /* threadData */) 48130803Smarcel{ 49130803Smarcel SCHEDULER_ENTER_FUNCTION(); 50130803Smarcel 51130803Smarcel // wake new package 52130803Smarcel PackageEntry* package = gIdlePackageList.Last(); 53130803Smarcel if (package == NULL) { 54130803Smarcel // wake new core 55130803Smarcel package = PackageEntry::GetMostIdlePackage(); 56130803Smarcel } 57130803Smarcel 58130803Smarcel CoreEntry* core = NULL; 59130803Smarcel if (package != NULL) 60130803Smarcel core = package->GetIdleCore(); 61130803Smarcel 62130803Smarcel if (core == NULL) { 63130803Smarcel ReadSpinLocker coreLocker(gCoreHeapsLock); 64130803Smarcel // no idle cores, use least occupied core 65130803Smarcel core = gCoreLoadHeap.PeekMinimum(); 66130803Smarcel if (core == NULL) 67130803Smarcel core = gCoreHighLoadHeap.PeekMinimum(); 68130803Smarcel } 69130803Smarcel 70130803Smarcel ASSERT(core != NULL); 71130803Smarcel return core; 72130803Smarcel} 73130803Smarcel 74130803Smarcel 75130803Smarcelstatic CoreEntry* 76130803Smarcelrebalance(const ThreadData* threadData) 77130803Smarcel{ 78130803Smarcel SCHEDULER_ENTER_FUNCTION(); 79130803Smarcel 80130803Smarcel CoreEntry* core = threadData->Core(); 81130803Smarcel ASSERT(core != NULL); 82130803Smarcel 83130803Smarcel // Get the least loaded core. 84130803Smarcel ReadSpinLocker coreLocker(gCoreHeapsLock); 85130803Smarcel CoreEntry* other = gCoreLoadHeap.PeekMinimum(); 86130803Smarcel if (other == NULL) 87130803Smarcel other = gCoreHighLoadHeap.PeekMinimum(); 88130803Smarcel coreLocker.Unlock(); 89130803Smarcel ASSERT(other != NULL); 90130803Smarcel 91130803Smarcel // Check if the least loaded core is significantly less loaded than 92130803Smarcel // the current one. 93130803Smarcel int32 coreLoad = core->GetLoad(); 94130803Smarcel int32 otherLoad = other->GetLoad(); 95130803Smarcel if (other == core || otherLoad + kLoadDifference >= coreLoad) 96130803Smarcel return core; 97130803Smarcel 98130803Smarcel // Check whether migrating the current thread would result in both core 99130803Smarcel // loads become closer to the average. 100130803Smarcel int32 difference = coreLoad - otherLoad - kLoadDifference; 101130803Smarcel ASSERT(difference > 0); 102130803Smarcel 103130803Smarcel int32 threadLoad = threadData->GetLoad() / core->CPUCount(); 104130803Smarcel return difference >= threadLoad ? other : core; 105130803Smarcel} 106130803Smarcel 107130803Smarcel 108130803Smarcelstatic void 109130803Smarcelrebalance_irqs(bool idle) 110130803Smarcel{ 111130803Smarcel SCHEDULER_ENTER_FUNCTION(); 112130803Smarcel 113130803Smarcel if (idle) 114130803Smarcel return; 115130803Smarcel 116130803Smarcel cpu_ent* cpu = get_cpu_struct(); 117130803Smarcel SpinLocker locker(cpu->irqs_lock); 118130803Smarcel 119130803Smarcel irq_assignment* chosen = NULL; 120130803Smarcel irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs); 121130803Smarcel 122130803Smarcel int32 totalLoad = 0; 123130803Smarcel while (irq != NULL) { 124130803Smarcel if (chosen == NULL || chosen->load < irq->load) 125130803Smarcel chosen = irq; 126130803Smarcel totalLoad += irq->load; 127130803Smarcel irq = (irq_assignment*)list_get_next_item(&cpu->irqs, irq); 128130803Smarcel } 129130803Smarcel 130130803Smarcel locker.Unlock(); 131130803Smarcel 132130803Smarcel if (chosen == NULL || totalLoad < kLowLoad) 133130803Smarcel return; 134130803Smarcel 135130803Smarcel ReadSpinLocker coreLocker(gCoreHeapsLock); 136130803Smarcel CoreEntry* other = gCoreLoadHeap.PeekMinimum(); 137130803Smarcel if (other == NULL) 138130803Smarcel other = gCoreHighLoadHeap.PeekMinimum(); 139130803Smarcel coreLocker.Unlock(); 140130803Smarcel 141130803Smarcel int32 newCPU = other->CPUHeap()->PeekRoot()->ID(); 142130803Smarcel 143130803Smarcel ASSERT(other != NULL); 144130803Smarcel 145130803Smarcel CoreEntry* core = CoreEntry::GetCore(cpu->cpu_num); 146130803Smarcel if (other == core) 147130803Smarcel return; 148130803Smarcel if (other->GetLoad() + kLoadDifference >= core->GetLoad()) 149130803Smarcel return; 150130803Smarcel 151130803Smarcel assign_io_interrupt_to_cpu(chosen->irq, newCPU); 152130803Smarcel} 153130803Smarcel 154130803Smarcel 155130803Smarcelscheduler_mode_operations gSchedulerLowLatencyMode = { 156130803Smarcel "low latency", 157130803Smarcel 158130803Smarcel 1000, 159130803Smarcel 100, 160130803Smarcel { 2, 5 }, 161130803Smarcel 162130803Smarcel 5000, 163130803Smarcel 164130803Smarcel switch_to_mode, 165130803Smarcel set_cpu_enabled, 166130803Smarcel has_cache_expired, 167130803Smarcel choose_core, 168130803Smarcel rebalance, 169130803Smarcel rebalance_irqs, 170130803Smarcel}; 171130803Smarcel 172130803Smarcel