From cf863a50401af89883ea314ccf54e16badd9439e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 16 Oct 2013 18:39:25 +0200 Subject: [PATCH] kernel: Decide whether to use simple or affine scheduler Simple scheduler is used when we do not have to worry about cache affinity (i.e. single core with or without SMT, multicore with all cache levels shared). When we replace gSchedulerLock with more fine grained locking affine scheduler should also be chosen when logical CPU count is high (regardless of cache). --- headers/private/kernel/cpu.h | 1 + src/system/kernel/arch/x86/arch_cpu.cpp | 13 ++++----- src/system/kernel/cpu.cpp | 1 + src/system/kernel/scheduler/scheduler.cpp | 35 +++++++++++++++++------ 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h index 2432cce524..e8fe6bc490 100644 --- a/headers/private/kernel/cpu.h +++ b/headers/private/kernel/cpu.h @@ -76,6 +76,7 @@ typedef struct cpu_ent { //extern cpu_ent gCPU[MAX_BOOT_CPUS]; extern cpu_ent gCPU[]; +extern uint32 gCPUCacheLevelCount; #ifdef __cplusplus diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index 7ea90bf672..91cc6bf31a 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -131,7 +131,6 @@ static uint32 sHierarchyShift[CPU_TOPOLOGY_LEVELS]; /* Cache topology information */ static uint32 sCacheSharingMask[CPU_MAX_CACHE_LEVEL]; -static uint32 sCacheLevelCount; static status_t @@ -611,7 +610,7 @@ detect_amd_cache_topology(uint32 maxExtendedLeaf) for (int i = 0; i < maxCacheLevel; i++) sCacheSharingMask[i] = ~uint32(hierarchyLevels[i] - 1); - sCacheLevelCount = maxCacheLevel; + gCPUCacheLevelCount = maxCacheLevel; } @@ -725,7 +724,7 @@ detect_intel_cache_topology(uint32 maxBasicLeaf) for (int i = 0; i < maxCacheLevel; i++) sCacheSharingMask[i] = ~uint32(hierarchyLevels[i] - 1); - sCacheLevelCount = maxCacheLevel; + gCPUCacheLevelCount = maxCacheLevel; } @@ -789,7 +788,7 @@ detect_cpu_topology(int currentCPU, cpu_ent* cpu, uint32 maxBasicLeaf, = get_topology_level_id(topologyID, CPU_TOPOLOGY_PACKAGE); unsigned int i; - for (i = 0; i < sCacheLevelCount; i++) + for (i = 0; i < gCPUCacheLevelCount; i++) cpu->cache_id[i] = topologyID & sCacheSharingMask[i]; for (; i < CPU_MAX_CACHE_LEVEL; i++) cpu->cache_id[i] = -1; @@ -800,14 +799,14 @@ detect_cpu_topology(int currentCPU, cpu_ent* cpu, uint32 maxBasicLeaf, cpu->topology_id[CPU_TOPOLOGY_CORE], cpu->topology_id[CPU_TOPOLOGY_SMT]); - if (sCacheLevelCount > 0) { + if (gCPUCacheLevelCount > 0) { char cacheLevels[256]; unsigned int offset = 0; - for (i = 0; i < sCacheLevelCount; i++) { + for (i = 0; i < gCPUCacheLevelCount; i++) { offset += snprintf(cacheLevels + offset, sizeof(cacheLevels) - offset, " L%d id %d%s", i + 1, cpu->cache_id[i], - i < sCacheLevelCount - 1 ? "," : ""); + i < gCPUCacheLevelCount - 1 ? "," : ""); if (offset >= sizeof(cacheLevels)) break; diff --git a/src/system/kernel/cpu.cpp b/src/system/kernel/cpu.cpp index 44bff7e25d..1dfbc4dcc1 100644 --- a/src/system/kernel/cpu.cpp +++ b/src/system/kernel/cpu.cpp @@ -21,6 +21,7 @@ /* global per-cpu structure */ cpu_ent gCPU[MAX_BOOT_CPUS]; +uint32 gCPUCacheLevelCount; static spinlock sSetCpuLock; diff --git a/src/system/kernel/scheduler/scheduler.cpp b/src/system/kernel/scheduler/scheduler.cpp index ba6a00825f..fd843119c3 100644 --- a/src/system/kernel/scheduler/scheduler.cpp +++ b/src/system/kernel/scheduler/scheduler.cpp @@ -59,20 +59,39 @@ scheduler_remove_listener(struct SchedulerListener* listener) } +static bool +should_use_affine_scheduler(int32 cpuCount) +{ + if (cpuCount < 2) + return false; + + for (int32 i = 1; i < cpuCount; i++) { + for (int32 j = 0; j < gCPUCacheLevelCount; j++) { + if (gCPU[i].cache_id[j] != gCPU[i - 1].cache_id[j]) + return true; + } + } + + return false; +} + + void scheduler_init(void) { int32 cpuCount = smp_get_num_cpus(); - dprintf("scheduler_init: found %" B_PRId32 " logical cpu%s\n", cpuCount, - cpuCount != 1 ? "s" : ""); + dprintf("scheduler_init: found %" B_PRId32 " logical cpu%s and %" B_PRId32 + " cache level%s\n", cpuCount, cpuCount != 1 ? "s" : "", + gCPUCacheLevelCount, gCPUCacheLevelCount != 1 ? "s" : ""); status_t result; -#if 0 - dprintf("scheduler_init: using affine scheduler\n"); - result = scheduler_affine_init(); -#endif - dprintf("scheduler_init: using simple scheduler\n"); - result = scheduler_simple_init(); + if (should_use_affine_scheduler(cpuCount)) { + dprintf("scheduler_init: using affine scheduler\n"); + result = scheduler_affine_init(); + } else { + dprintf("scheduler_init: using simple scheduler\n"); + result = scheduler_simple_init(); + } if (result != B_OK) panic("scheduler_init: failed to initialize scheduler\n");