mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-30 03:54:17 +01:00
Use per-thread scheduler condvars and clean up AS filters
Per-thread condvars previously caused issues due to an audren bug, now that's fixed they have a clear performance benefit.
This commit is contained in:
parent
2bbf526419
commit
7e7a792dc5
2
.idea/scopes/SkylineKotlin.xml
generated
2
.idea/scopes/SkylineKotlin.xml
generated
@ -1,3 +1,3 @@
|
|||||||
<component name="DependencyValidationManager">
|
<component name="DependencyValidationManager">
|
||||||
<scope name="SkylineKotlin" pattern="file[Skyline.app]:src/main/java//*.kt" />
|
<scope name="SkylineKotlin" pattern="file[skyline.app]:src/main/java//*.kt" />
|
||||||
</component>
|
</component>
|
2
.idea/scopes/SkylineLibraries.xml
generated
2
.idea/scopes/SkylineLibraries.xml
generated
@ -1,3 +1,3 @@
|
|||||||
<component name="DependencyValidationManager">
|
<component name="DependencyValidationManager">
|
||||||
<scope name="SkylineLibraries" pattern="file[app]:libraries//*" />
|
<scope name="SkylineLibraries" pattern="file[skyline.app]:libraries//*" />
|
||||||
</component>
|
</component>
|
2
.idea/scopes/SkylineNative.xml
generated
2
.idea/scopes/SkylineNative.xml
generated
@ -1,3 +1,3 @@
|
|||||||
<component name="DependencyValidationManager">
|
<component name="DependencyValidationManager">
|
||||||
<scope name="SkylineNative" pattern="file[Skyline.app]:src/main/cpp//*.cpp||file[Skyline.app]:src/main/cpp//*.h||file[Skyline.app]:src/main/cpp//*.S" />
|
<scope name="SkylineNative" pattern="file[skyline.app]:src/main/cpp//*.cpp||file[skyline.app]:src/main/cpp//*.h||file[skyline.app]:src/main/cpp//*.S" />
|
||||||
</component>
|
</component>
|
2
.idea/scopes/SkylineXml.xml
generated
2
.idea/scopes/SkylineXml.xml
generated
@ -1,3 +1,3 @@
|
|||||||
<component name="DependencyValidationManager">
|
<component name="DependencyValidationManager">
|
||||||
<scope name="SkylineXml" pattern="file[app]:src/main/res/layout/*||file[app]:src/main/res/menu/*||file[app]:src/main/res/values/*||file[app]:src/main/res/values-night/*||file[app]:src/main/res/xml/*" />
|
<scope name="SkylineXml" pattern="file[skyline.app]:src/main/res/layout/*||file[app]:src/main/res/menu/*||file[skyline.app]:src/main/res/values/*||file[skyline.app]:src/main/res/values-night/*||file[skyline.app]:src/main/res/xml/*" />
|
||||||
</component>
|
</component>
|
@ -113,7 +113,7 @@ namespace skyline::kernel {
|
|||||||
core.queue.push_front(thread);
|
core.queue.push_front(thread);
|
||||||
}
|
}
|
||||||
if (thread != state.thread)
|
if (thread != state.thread)
|
||||||
core.frontCondition.notify_all(); // We only want to trigger the conditional variable if the current thread isn't inserting itself
|
thread->wakeCondition.notify_one(); // We only want to trigger the conditional variable if the current thread isn't inserting itself
|
||||||
} else {
|
} else {
|
||||||
core.queue.insert(nextThread, thread);
|
core.queue.insert(nextThread, thread);
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ namespace skyline::kernel {
|
|||||||
std::unique_lock lock(core->mutex);
|
std::unique_lock lock(core->mutex);
|
||||||
if (loadBalance && thread->affinityMask.count() > 1) {
|
if (loadBalance && thread->affinityMask.count() > 1) {
|
||||||
std::chrono::milliseconds loadBalanceThreshold{PreemptiveTimeslice * 2}; //!< The amount of time that needs to pass unscheduled for a thread to attempt load balancing
|
std::chrono::milliseconds loadBalanceThreshold{PreemptiveTimeslice * 2}; //!< The amount of time that needs to pass unscheduled for a thread to attempt load balancing
|
||||||
while (!core->frontCondition.wait_for(lock, loadBalanceThreshold, [&]() { return !core->queue.empty() && core->queue.front() == thread; })) {
|
while (!thread->wakeCondition.wait_for(lock, loadBalanceThreshold, [&]() { return !core->queue.empty() && core->queue.front() == thread; })) {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
LoadBalance(state.thread);
|
LoadBalance(state.thread);
|
||||||
if (thread->coreId == core->id) {
|
if (thread->coreId == core->id) {
|
||||||
@ -139,7 +139,7 @@ namespace skyline::kernel {
|
|||||||
loadBalanceThreshold *= 2; // We double the duration required for future load balancing for this invocation to minimize pointless load balancing
|
loadBalanceThreshold *= 2; // We double the duration required for future load balancing for this invocation to minimize pointless load balancing
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
core->frontCondition.wait(lock, [&]() { return !core->queue.empty() && core->queue.front() == thread; });
|
thread->wakeCondition.wait(lock, [&]() { return !core->queue.empty() && core->queue.front() == thread; });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread->priority == core->preemptionPriority) {
|
if (thread->priority == core->preemptionPriority) {
|
||||||
@ -156,7 +156,7 @@ namespace skyline::kernel {
|
|||||||
auto *core{&cores.at(thread->coreId)};
|
auto *core{&cores.at(thread->coreId)};
|
||||||
|
|
||||||
std::unique_lock lock(core->mutex);
|
std::unique_lock lock(core->mutex);
|
||||||
if (core->frontCondition.wait_for(lock, timeout, [&]() { return !core->queue.empty() && core->queue.front() == thread; })) {
|
if (thread->wakeCondition.wait_for(lock, timeout, [&]() { return !core->queue.empty() && core->queue.front() == thread; })) {
|
||||||
if (thread->priority == core->preemptionPriority) {
|
if (thread->priority == core->preemptionPriority) {
|
||||||
struct itimerspec spec{.it_value = {.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(PreemptiveTimeslice).count()}};
|
struct itimerspec spec{.it_value = {.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(PreemptiveTimeslice).count()}};
|
||||||
timer_settime(thread->preemptionTimer, 0, &spec, nullptr);
|
timer_settime(thread->preemptionTimer, 0, &spec, nullptr);
|
||||||
@ -182,8 +182,9 @@ namespace skyline::kernel {
|
|||||||
// Splice the linked element from the beginning of the queue to where it's priority is present
|
// Splice the linked element from the beginning of the queue to where it's priority is present
|
||||||
core.queue.splice(std::upper_bound(core.queue.begin(), core.queue.end(), thread->priority.load(), type::KThread::IsHigherPriority), core.queue, core.queue.begin());
|
core.queue.splice(std::upper_bound(core.queue.begin(), core.queue.end(), thread->priority.load(), type::KThread::IsHigherPriority), core.queue, core.queue.begin());
|
||||||
|
|
||||||
if (core.queue.front() != thread)
|
auto& front{core.queue.front()};
|
||||||
core.frontCondition.notify_all(); // If we aren't at the front of the queue, only then should we wake the thread at the front up
|
if (front != thread)
|
||||||
|
front->wakeCondition.notify_one(); // If we aren't at the front of the queue, only then should we wake the thread at the front up
|
||||||
} else if (!thread->forceYield) { [[unlikely]]
|
} else if (!thread->forceYield) { [[unlikely]]
|
||||||
throw exception("T{} called Rotate while not being in C{}'s queue", thread->id, thread->coreId);
|
throw exception("T{} called Rotate while not being in C{}'s queue", thread->id, thread->coreId);
|
||||||
}
|
}
|
||||||
@ -267,7 +268,7 @@ namespace skyline::kernel {
|
|||||||
if (thread->coreId == constant::ParkedCoreId) {
|
if (thread->coreId == constant::ParkedCoreId) {
|
||||||
std::unique_lock lock(parkedMutex);
|
std::unique_lock lock(parkedMutex);
|
||||||
parkedQueue.insert(std::upper_bound(parkedQueue.begin(), parkedQueue.end(), thread->priority.load(), type::KThread::IsHigherPriority), thread);
|
parkedQueue.insert(std::upper_bound(parkedQueue.begin(), parkedQueue.end(), thread->priority.load(), type::KThread::IsHigherPriority), thread);
|
||||||
parkedFrontCondition.wait(lock, [&]() { return parkedQueue.front() == thread && thread->coreId != constant::ParkedCoreId; });
|
thread->wakeCondition.wait(lock, [&]() { return parkedQueue.front() == thread && thread->coreId != constant::ParkedCoreId; });
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertThread(thread);
|
InsertThread(thread);
|
||||||
@ -288,7 +289,7 @@ namespace skyline::kernel {
|
|||||||
if (parkedThread->priority < thread->priority || (parkedThread->priority == thread->priority && (!nextThread || parkedThread->timesliceStart < nextThread->timesliceStart))) {
|
if (parkedThread->priority < thread->priority || (parkedThread->priority == thread->priority && (!nextThread || parkedThread->timesliceStart < nextThread->timesliceStart))) {
|
||||||
parkedThread->coreId = thread->coreId;
|
parkedThread->coreId = thread->coreId;
|
||||||
parkedLock.unlock();
|
parkedLock.unlock();
|
||||||
parkedFrontCondition.notify_all();
|
parkedThread->wakeCondition.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +308,7 @@ namespace skyline::kernel {
|
|||||||
thread->averageTimeslice = (thread->averageTimeslice / 4) + (3 * (util::GetTimeTicks() - thread->timesliceStart / 4));
|
thread->averageTimeslice = (thread->averageTimeslice / 4) + (3 * (util::GetTimeTicks() - thread->timesliceStart / 4));
|
||||||
|
|
||||||
if (it != core.queue.end())
|
if (it != core.queue.end())
|
||||||
core.frontCondition.notify_all(); // We need to wake the thread at the front of the queue, if we were at the front previously
|
(*it)->wakeCondition.notify_one(); // We need to wake the thread at the front of the queue, if we were at the front previously
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,6 @@ namespace skyline {
|
|||||||
u8 id;
|
u8 id;
|
||||||
u8 preemptionPriority; //!< The priority at which this core becomes preemptive as opposed to cooperative
|
u8 preemptionPriority; //!< The priority at which this core becomes preemptive as opposed to cooperative
|
||||||
std::mutex mutex; //!< Synchronizes all operations on the queue
|
std::mutex mutex; //!< Synchronizes all operations on the queue
|
||||||
std::condition_variable frontCondition; //!< A conditional variable which is signalled when the front of the parked queue has changed
|
|
||||||
std::list<std::shared_ptr<type::KThread>> queue; //!< A queue of threads which are running or to be run on this core
|
std::list<std::shared_ptr<type::KThread>> queue; //!< A queue of threads which are running or to be run on this core
|
||||||
|
|
||||||
CoreContext(u8 id, u8 preemptionPriority);
|
CoreContext(u8 id, u8 preemptionPriority);
|
||||||
@ -56,7 +55,6 @@ namespace skyline {
|
|||||||
std::array<CoreContext, constant::CoreCount> cores{CoreContext(0, 59), CoreContext(1, 59), CoreContext(2, 59), CoreContext(3, 63)};
|
std::array<CoreContext, constant::CoreCount> cores{CoreContext(0, 59), CoreContext(1, 59), CoreContext(2, 59), CoreContext(3, 63)};
|
||||||
|
|
||||||
std::mutex parkedMutex; //!< Synchronizes all operations on the queue of parked threads
|
std::mutex parkedMutex; //!< Synchronizes all operations on the queue of parked threads
|
||||||
std::condition_variable parkedFrontCondition; //!< A conditional variable which is signalled when the front of the parked queue has changed
|
|
||||||
std::list<std::shared_ptr<type::KThread>> parkedQueue; //!< A queue of threads which are parked and waiting on core migration
|
std::list<std::shared_ptr<type::KThread>> parkedQueue; //!< A queue of threads which are parked and waiting on core migration
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -41,6 +41,7 @@ namespace skyline {
|
|||||||
u64 entryArgument;
|
u64 entryArgument;
|
||||||
void *stackTop;
|
void *stackTop;
|
||||||
|
|
||||||
|
std::condition_variable_any wakeCondition; //!< A conditional variable which is signalled to wake the current thread while it's sleeping
|
||||||
std::atomic<u8> basePriority; //!< The priority of the thread for the scheduler without any priority-inheritance
|
std::atomic<u8> basePriority; //!< The priority of the thread for the scheduler without any priority-inheritance
|
||||||
std::atomic<u8> priority; //!< The priority of the thread for the scheduler
|
std::atomic<u8> priority; //!< The priority of the thread for the scheduler
|
||||||
i8 idealCore; //!< The ideal CPU core for this thread to run on
|
i8 idealCore; //!< The ideal CPU core for this thread to run on
|
||||||
|
Loading…
Reference in New Issue
Block a user