xref: /haiku/src/system/kernel/scheduler/low_latency.cpp (revision 04171cfc5c10c98b9ba3c7233a271f6165cdd36f)
1 /*
2  * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <util/AutoLock.h>
8 
9 #include "scheduler_common.h"
10 #include "scheduler_cpu.h"
11 #include "scheduler_modes.h"
12 #include "scheduler_profiler.h"
13 #include "scheduler_thread.h"
14 
15 
16 using namespace Scheduler;
17 
18 
19 const bigtime_t kCacheExpire = 100000;
20 
21 
22 static void
23 switch_to_mode()
24 {
25 }
26 
27 
28 static void
29 set_cpu_enabled(int32 /* cpu */, bool /* enabled */)
30 {
31 }
32 
33 
34 static bool
35 has_cache_expired(const ThreadData* threadData)
36 {
37 	SCHEDULER_ENTER_FUNCTION();
38 	if (threadData->WentSleepActive() == 0)
39 		return false;
40 	CoreEntry* core = threadData->Core();
41 	bigtime_t activeTime = core->GetActiveTime();
42 	return activeTime - threadData->WentSleepActive() > kCacheExpire;
43 }
44 
45 
46 static CoreEntry*
47 choose_core(const ThreadData* /* threadData */)
48 {
49 	SCHEDULER_ENTER_FUNCTION();
50 
51 	// wake new package
52 	PackageEntry* package = gIdlePackageList.Last();
53 	if (package == NULL) {
54 		// wake new core
55 		package = PackageEntry::GetMostIdlePackage();
56 	}
57 
58 	CoreEntry* core = NULL;
59 	if (package != NULL)
60 		core = package->GetIdleCore();
61 
62 	if (core == NULL) {
63 		ReadSpinLocker coreLocker(gCoreHeapsLock);
64 		// no idle cores, use least occupied core
65 		core = gCoreLoadHeap.PeekMinimum();
66 		if (core == NULL)
67 			core = gCoreHighLoadHeap.PeekMinimum();
68 	}
69 
70 	ASSERT(core != NULL);
71 	return core;
72 }
73 
74 
75 static CoreEntry*
76 rebalance(const ThreadData* threadData)
77 {
78 	SCHEDULER_ENTER_FUNCTION();
79 
80 	CoreEntry* core = threadData->Core();
81 	ASSERT(core != NULL);
82 
83 	// Get the least loaded core.
84 	ReadSpinLocker coreLocker(gCoreHeapsLock);
85 	CoreEntry* other = gCoreLoadHeap.PeekMinimum();
86 	if (other == NULL)
87 		other = gCoreHighLoadHeap.PeekMinimum();
88 	coreLocker.Unlock();
89 	ASSERT(other != NULL);
90 
91 	// Check if the least loaded core is significantly less loaded than
92 	// the current one.
93 	int32 coreLoad = core->GetLoad();
94 	int32 otherLoad = other->GetLoad();
95 	if (other == core || otherLoad + kLoadDifference >= coreLoad)
96 		return core;
97 
98 	// Check whether migrating the current thread would result in both core
99 	// loads become closer to the average.
100 	int32 difference = coreLoad - otherLoad - kLoadDifference;
101 	ASSERT(difference > 0);
102 
103 	int32 threadLoad = threadData->GetLoad() / core->CPUCount();
104 	return difference >= threadLoad ? other : core;
105 }
106 
107 
108 static void
109 rebalance_irqs(bool idle)
110 {
111 	SCHEDULER_ENTER_FUNCTION();
112 
113 	if (idle)
114 		return;
115 
116 	cpu_ent* cpu = get_cpu_struct();
117 	SpinLocker locker(cpu->irqs_lock);
118 
119 	irq_assignment* chosen = NULL;
120 	irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs);
121 
122 	int32 totalLoad = 0;
123 	while (irq != NULL) {
124 		if (chosen == NULL || chosen->load < irq->load)
125 			chosen = irq;
126 		totalLoad += irq->load;
127 		irq = (irq_assignment*)list_get_next_item(&cpu->irqs, irq);
128 	}
129 
130 	locker.Unlock();
131 
132 	if (chosen == NULL || totalLoad < kLowLoad)
133 		return;
134 
135 	ReadSpinLocker coreLocker(gCoreHeapsLock);
136 	CoreEntry* other = gCoreLoadHeap.PeekMinimum();
137 	if (other == NULL)
138 		other = gCoreHighLoadHeap.PeekMinimum();
139 	coreLocker.Unlock();
140 
141 	int32 newCPU = other->CPUHeap()->PeekRoot()->ID();
142 
143 	ASSERT(other != NULL);
144 
145 	CoreEntry* core = CoreEntry::GetCore(cpu->cpu_num);
146 	if (other == core)
147 		return;
148 	if (other->GetLoad() + kLoadDifference >= core->GetLoad())
149 		return;
150 
151 	assign_io_interrupt_to_cpu(chosen->irq, newCPU);
152 }
153 
154 
155 scheduler_mode_operations gSchedulerLowLatencyMode = {
156 	"low latency",
157 
158 	1000,
159 	100,
160 	{ 2, 5 },
161 
162 	5000,
163 
164 	switch_to_mode,
165 	set_cpu_enabled,
166 	has_cache_expired,
167 	choose_core,
168 	rebalance,
169 	rebalance_irqs,
170 };
171 
172