forked from Bananymous/banan-os
Kernel: Use min heap for scheduler block list
This makes insertion to block list O(log n) instead of O(n) when blocking with wake time. This is more heavy and currently slower than the previous implementation, but that is just because we don't really have too many threads running at any given time. This will be more scalable in the future and even allows implementing priorities if I ever wish so
This commit is contained in:
@@ -22,7 +22,7 @@ namespace Kernel
|
||||
class GDT;
|
||||
class IDT;
|
||||
class Scheduler;
|
||||
class SchedulerQueueNode;
|
||||
class SchedulerThreadNode;
|
||||
class Thread;
|
||||
|
||||
#if ARCH(x86_64) || ARCH(i686)
|
||||
@@ -54,8 +54,8 @@ namespace Kernel
|
||||
union
|
||||
{
|
||||
TLBEntry flush_tlb;
|
||||
SchedulerQueueNode* new_thread;
|
||||
SchedulerQueueNode* unblock_thread;
|
||||
SchedulerThreadNode* new_thread;
|
||||
SchedulerThreadNode* unblock_thread;
|
||||
bool dummy;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/ProcessorID.h>
|
||||
#include <kernel/SchedulerThreadNode.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -14,29 +15,6 @@ namespace Kernel
|
||||
class BaseMutex;
|
||||
class Thread;
|
||||
class ThreadBlocker;
|
||||
struct SchedulerQueueNode;
|
||||
|
||||
class SchedulerQueue
|
||||
{
|
||||
public:
|
||||
using Node = SchedulerQueueNode;
|
||||
|
||||
public:
|
||||
void add_thread_to_back(Node*);
|
||||
bool add_thread_with_wake_time(Node*); // return true if node was inserted as the first element
|
||||
template<typename F>
|
||||
Node* remove_with_condition(F callback);
|
||||
void remove_node(Node*);
|
||||
Node* front();
|
||||
Node* pop_front();
|
||||
|
||||
bool empty() const { return m_head == nullptr; }
|
||||
|
||||
private:
|
||||
Node* m_head { nullptr };
|
||||
Node* m_tail { nullptr };
|
||||
};
|
||||
|
||||
class Scheduler
|
||||
{
|
||||
BAN_NON_COPYABLE(Scheduler);
|
||||
@@ -45,12 +23,12 @@ namespace Kernel
|
||||
public:
|
||||
struct NewThreadRequest
|
||||
{
|
||||
SchedulerQueue::Node* node;
|
||||
SchedulerThreadNode* node;
|
||||
};
|
||||
|
||||
struct UnblockRequest
|
||||
{
|
||||
SchedulerQueue::Node* node;
|
||||
SchedulerThreadNode* node;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -79,9 +57,9 @@ namespace Kernel
|
||||
private:
|
||||
Scheduler() = default;
|
||||
|
||||
void add_current_to_most_loaded(SchedulerQueue* target_queue);
|
||||
void update_most_loaded_node_queue(SchedulerQueue::Node*, SchedulerQueue* target_queue);
|
||||
void remove_node_from_most_loaded(SchedulerQueue::Node*);
|
||||
void add_current_to_most_loaded(void* target_list);
|
||||
void update_most_loaded_node_list(SchedulerThreadNode*, void* target_list);
|
||||
void remove_node_from_most_loaded(SchedulerThreadNode*);
|
||||
|
||||
void update_wake_up_deadline();
|
||||
void wake_up_sleeping_threads();
|
||||
@@ -90,13 +68,13 @@ namespace Kernel
|
||||
|
||||
class ProcessorID find_least_loaded_processor() const;
|
||||
|
||||
void add_thread(SchedulerQueue::Node*);
|
||||
void unblock_thread(SchedulerQueue::Node*);
|
||||
void add_thread(SchedulerThreadNode*);
|
||||
void unblock_thread(SchedulerThreadNode*);
|
||||
|
||||
private:
|
||||
SchedulerQueue m_run_queue;
|
||||
SchedulerQueue m_block_queue;
|
||||
SchedulerQueue::Node* m_current { nullptr };
|
||||
SchedulerQueue m_run_list;
|
||||
SchedulerHeap m_block_list;
|
||||
SchedulerThreadNode* m_current { nullptr };
|
||||
|
||||
uint32_t m_thread_count { 0 };
|
||||
|
||||
@@ -108,8 +86,8 @@ namespace Kernel
|
||||
|
||||
struct ThreadInfo
|
||||
{
|
||||
SchedulerQueue* queue { nullptr };
|
||||
SchedulerQueue::Node* node { nullptr };
|
||||
void* list { nullptr };
|
||||
SchedulerThreadNode* node { nullptr };
|
||||
};
|
||||
BAN::Array<ThreadInfo, 10> m_most_loaded_threads;
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <kernel/ProcessorID.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Thread;
|
||||
class ThreadBlocker;
|
||||
|
||||
struct SchedulerQueueNode
|
||||
{
|
||||
SchedulerQueueNode(Thread* thread)
|
||||
: thread(thread)
|
||||
{}
|
||||
|
||||
Thread* const thread;
|
||||
|
||||
SchedulerQueueNode* next { nullptr };
|
||||
SchedulerQueueNode* prev { nullptr };
|
||||
|
||||
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
||||
|
||||
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
|
||||
SchedulerQueueNode* block_chain_prev { nullptr };
|
||||
SchedulerQueueNode* block_chain_next { nullptr };
|
||||
|
||||
ProcessorID processor_id { PROCESSOR_NONE };
|
||||
bool blocked { false };
|
||||
|
||||
uint64_t last_start_ns { 0 };
|
||||
uint64_t time_used_ns { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <kernel/ProcessorID.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Thread;
|
||||
class ThreadBlocker;
|
||||
|
||||
struct SchedulerThreadNode
|
||||
{
|
||||
SchedulerThreadNode(Thread* thread)
|
||||
: thread(thread)
|
||||
, heap({ nullptr, nullptr, nullptr })
|
||||
{}
|
||||
|
||||
Thread* const thread;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
SchedulerThreadNode* next;
|
||||
SchedulerThreadNode* prev;
|
||||
} queue;
|
||||
struct
|
||||
{
|
||||
SchedulerThreadNode* parent;
|
||||
SchedulerThreadNode* lchild;
|
||||
SchedulerThreadNode* rchild;
|
||||
} heap;
|
||||
};
|
||||
|
||||
uint64_t wake_time_ns { static_cast<uint64_t>(-1) };
|
||||
|
||||
BAN::Atomic<ThreadBlocker*> blocker { nullptr };
|
||||
SchedulerThreadNode* block_chain_prev { nullptr };
|
||||
SchedulerThreadNode* block_chain_next { nullptr };
|
||||
|
||||
ProcessorID processor_id { PROCESSOR_NONE };
|
||||
bool blocked { false };
|
||||
|
||||
uint64_t last_start_ns { 0 };
|
||||
uint64_t time_used_ns { 0 };
|
||||
};
|
||||
|
||||
class SchedulerQueue
|
||||
{
|
||||
BAN_NON_COPYABLE(SchedulerQueue);
|
||||
BAN_NON_MOVABLE(SchedulerQueue);
|
||||
public:
|
||||
SchedulerQueue() = default;
|
||||
|
||||
SchedulerThreadNode* front();
|
||||
SchedulerThreadNode* pop_front();
|
||||
|
||||
void push(SchedulerThreadNode*);
|
||||
void pop(SchedulerThreadNode*);
|
||||
|
||||
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
|
||||
bool empty() const { return m_head == nullptr; }
|
||||
|
||||
private:
|
||||
SchedulerThreadNode* m_head { nullptr };
|
||||
SchedulerThreadNode* m_tail { nullptr };
|
||||
};
|
||||
|
||||
class SchedulerHeap
|
||||
{
|
||||
BAN_NON_COPYABLE(SchedulerHeap);
|
||||
BAN_NON_MOVABLE(SchedulerHeap);
|
||||
public:
|
||||
SchedulerHeap() = default;
|
||||
|
||||
SchedulerThreadNode* front();
|
||||
SchedulerThreadNode* pop_front();
|
||||
|
||||
void push(SchedulerThreadNode*);
|
||||
void pop(SchedulerThreadNode*);
|
||||
|
||||
void walk(void (*)(const SchedulerThreadNode*, void*), void*) const;
|
||||
bool empty() const { return m_root == nullptr; }
|
||||
|
||||
private:
|
||||
void walk_impl(void (*)(const SchedulerThreadNode*, void*), void*, const SchedulerThreadNode*) const;
|
||||
void swap_nodes(SchedulerThreadNode*, SchedulerThreadNode*);
|
||||
|
||||
private:
|
||||
SchedulerThreadNode* m_root { nullptr };
|
||||
SchedulerThreadNode* m_last { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
@@ -192,7 +192,7 @@ namespace Kernel
|
||||
vaddr_t m_fsbase { 0 };
|
||||
vaddr_t m_gsbase { 0 };
|
||||
|
||||
SchedulerQueueNode* m_scheduler_node { nullptr };
|
||||
SchedulerThreadNode* m_scheduler_node { nullptr };
|
||||
|
||||
YieldRegisters m_yield_registers { };
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class SchedulerQueueNode;
|
||||
class SchedulerThreadNode;
|
||||
|
||||
class ThreadBlocker
|
||||
{
|
||||
@@ -29,11 +29,11 @@ namespace Kernel
|
||||
}
|
||||
|
||||
private:
|
||||
void add_thread_to_block_queue(SchedulerQueueNode*);
|
||||
void remove_thread_from_block_queue(SchedulerQueueNode*);
|
||||
void add_thread_to_block_queue(SchedulerThreadNode*);
|
||||
void remove_thread_from_block_queue(SchedulerThreadNode*);
|
||||
|
||||
private:
|
||||
SchedulerQueueNode* m_block_chain { nullptr };
|
||||
SchedulerThreadNode* m_block_chain { nullptr };
|
||||
SpinLock m_lock;
|
||||
|
||||
friend class Scheduler;
|
||||
|
||||
Reference in New Issue
Block a user