added support for different sched strats + cfs

This commit is contained in:
Marcel Lütke Dreimann
2023-01-06 16:00:02 +01:00
parent 3b05673cfe
commit 9b15985a52
12 changed files with 328 additions and 114 deletions

View File

@@ -4,7 +4,8 @@
#include "../uos-intel-gpgpu/driver/gpgpu_driver.h"
#include "../virt/scheduler.h"
extern gpgpu_virt::Scheduler* _global_sched;
#include "../virt/strategies/rr.h"
extern gpgpu_virt::GPGPUScheduler* _global_sched;
namespace gpgpu
{

View File

@@ -2,6 +2,7 @@
#include "../virt/rpc.h"
#include "../virt/scheduler.h"
#include "../virt/strategies/rr.h"
#define GENODE // use genodes stdint header
#include "../uos-intel-gpgpu/driver/gpgpu_driver.h"
@@ -15,7 +16,7 @@
#endif // TEST
gpgpu::gpgpu_genode* _global_gpgpu_genode;
gpgpu_virt::Scheduler* _global_sched;
gpgpu_virt::GPGPUScheduler* _global_sched;
void Component::construct(Genode::Env& e)
{
@@ -25,7 +26,7 @@ void Component::construct(Genode::Env& e)
// init globals
static gpgpu::gpgpu_genode gg(e);
_global_gpgpu_genode = ≫
static gpgpu_virt::Scheduler sched;
static gpgpu_virt::GPGPUScheduler sched;
_global_sched = &sched;
#ifdef TEST

View File

@@ -1,7 +1,7 @@
TARGET = gpgpu
REQUIRES = x86_64
SRC_CC = main.cc gpgpu_genode.cc stubs.cc test.cc ../virt/rpc.cc ../virt/scheduler.cc
SRC_CC = main.cc gpgpu_genode.cc stubs.cc test.cc ../virt/rpc.cc ../virt/strategies/rr.cc ../virt/strategies/cfs.cc
LIBS = base
UOS_INTEL_GPGPU = uos-intel-gpgpu-link-cxx.o

View File

@@ -5,12 +5,13 @@
#include <gpgpu_virt/session.h>
#include "rpc.h"
#include "scheduler.h"
// genode instance
#include "../gpgpu/gpgpu_genode.h"
extern gpgpu::gpgpu_genode* _global_gpgpu_genode;
extern gpgpu_virt::Scheduler* _global_sched;
#include "scheduler.h"
#include "strategies/rr.h"
extern gpgpu_virt::GPGPUScheduler* _global_sched;
// driver
#define GENODE // use genodes stdint header

View File

@@ -1,92 +0,0 @@
#include "scheduler.h"
#include "kernel.h"
// genode instance
#include "../gpgpu/gpgpu_genode.h"
extern gpgpu::gpgpu_genode* _global_gpgpu_genode;
// driver
#define GENODE
#include "../uos-intel-gpgpu/driver/gpgpu_driver.h"
#include "../uos-intel-gpgpu/driver/ppgtt32.h"
namespace gpgpu_virt
{
void Scheduler::schedule_next()
{
VGpu* first = nullptr;
do
{
VGpu* next = nullptr;
_run_list.dequeue([&next](VGpu& vgpu){
next = &vgpu;
});
if(next != nullptr)
{
// set vgpu
_curr_vgpu = next;
// add vgpu back to end of list
_run_list.enqueue(*next);
// complete iteration?
if(first == next)
{
return;
}
// remember start of our search
if(first == nullptr)
{
first = next;
}
}
else
{
_curr_vgpu = nullptr;
}
}
while(_curr_vgpu != nullptr && !_curr_vgpu->has_kernel()); // continue search if we picked a vgpu without kernel
}
void Scheduler::handle_gpu_event()
{
// reduce frequency
GPGPU_Driver& gpgpudriver = GPGPU_Driver::getInstance();
gpgpudriver.setMinFreq();
/* Switch to next vGPU in the run list */
schedule_next();
// If no vGPU to schedule, this means that we don't have any clients with anymore.
if(_curr_vgpu == nullptr)
{
idle = true;
return;
}
Kernel* next = _curr_vgpu->take_kernel();
if(next == nullptr)
{
idle = true;
return;
}
idle = false;
// switch context
dispatch(*_curr_vgpu);
// set frequency
gpgpudriver.setMaxFreq();
// run gpgpu task
gpgpudriver.enqueueRun(*next->get_config());
// free kernel object
// kernel_config will not be freed, just the Queue object!
_global_gpgpu_genode->free(next);
}
}

View File

@@ -1,28 +1,35 @@
#ifndef SCHEDULER_H
#define SCHEDULER_H
#include <util/fifo.h>
#include "vgpu.h"
#include "kernel.h"
#include "strategies/rr.h"
// genode instance
#include "../gpgpu/gpgpu_genode.h"
extern gpgpu::gpgpu_genode* _global_gpgpu_genode;
// driver
#define GENODE
#include "../uos-intel-gpgpu/driver/gpgpu_driver.h"
namespace gpgpu_virt {
class Scheduler
template<typename S> class Scheduler
{
private:
S strat;
VGpu* _curr_vgpu;
Genode::Fifo<VGpu> _run_list;
bool idle;
Scheduler(const Scheduler &copy) = delete;
Scheduler(Scheduler&&) = delete;
Scheduler& operator=(const Scheduler&) = delete;
Scheduler& operator=(Scheduler&&) = delete;
public:
Scheduler() : _curr_vgpu(nullptr), _run_list(), idle(true) { }
/**
* @brief Select next vGPU from run list
* @details At the moment, round-robin is the only implemented strategy.
* TODO: Implement interface for strategies and strategies *
*/
void schedule_next();
Scheduler() : strat(), _curr_vgpu(nullptr), idle(true) { }
/**
* @brief Switch to new vGPU's context
@@ -41,7 +48,40 @@ namespace gpgpu_virt {
* executing kernels. It is the target for interrupts coming from the GPGPU driver, e.g. when
* a kernel has finished its execution.
*/
void handle_gpu_event();
void handle_gpu_event()
{
// reduce frequency
GPGPU_Driver& gpgpudriver = GPGPU_Driver::getInstance();
gpgpudriver.setMinFreq();
/* Switch to next vGPU in the run list */
_curr_vgpu = strat.nextVGPU();
// If no vGPU to schedule, this means that we don't have any clients with anymore.
if(_curr_vgpu == nullptr)
{
idle = true;
return;
}
idle = false;
Kernel* next = _curr_vgpu->take_kernel();
// switch context
dispatch(*_curr_vgpu);
// set frequency
gpgpudriver.setMaxFreq();
// run gpgpu task
gpgpudriver.enqueueRun(*next->get_config());
// free kernel object
// kernel_config will not be freed, just the Queue object!
_global_gpgpu_genode->free(next);
}
/**
* @brief
@@ -50,7 +90,7 @@ namespace gpgpu_virt {
*/
void add_vgpu(VGpu* vgpu)
{
_run_list.enqueue(*vgpu);
strat.addVGPU(vgpu);
}
/**
@@ -60,7 +100,7 @@ namespace gpgpu_virt {
*/
void remove_vgpu(VGpu* vgpu)
{
_run_list.remove(*vgpu);
strat.removeVGPU(vgpu);
}
/**
@@ -74,6 +114,8 @@ namespace gpgpu_virt {
return idle;
}
};
using GPGPUScheduler = Scheduler<gpgpu_virt::RoundRobin>;
}
#endif // SCHEDULER_H

View File

@@ -0,0 +1,40 @@
#ifndef STRATEGIE_H
#define STRATEGIE_H
#include "vgpu.h"
namespace gpgpu_virt {
class Strategie
{
private:
Strategie(const Strategie &copy) = delete;
public:
Strategie() {};
virtual ~Strategie() {};
/**
* @brief
*
* @param vgpu
*/
virtual void addVGPU(VGpu* vgpu) = 0;
/**
* @brief
*
* @param vgpu
*/
virtual void removeVGPU(VGpu* vgpu) = 0;
/**
* @brief
*
* @return VGpu*
*/
virtual VGpu* nextVGPU() = 0;
};
}
#endif // STRATEGIE_H

View File

@@ -0,0 +1,70 @@
#include "cfs.h"
// genode instance
#include "../../gpgpu/gpgpu_genode.h"
extern gpgpu::gpgpu_genode* _global_gpgpu_genode;
namespace gpgpu_virt
{
static unsigned long long int rdtsc()
{
unsigned long long int ret = 0;
unsigned int cycles_lo;
unsigned int cycles_hi;
__asm__ volatile ("RDTSC" : "=a" (cycles_lo), "=d" (cycles_hi));
ret = (unsigned long long int)cycles_hi << 32 | cycles_lo;
return ret;
}
void CompletlyFair::addVGPU(VGpu* vgpu)
{
cfs_entry* ce = new (_global_gpgpu_genode->getAlloc()) cfs_entry(vgpu);
_run_list.enqueue(*ce);
}
void CompletlyFair::removeVGPU(VGpu* vgpu)
{
_run_list.for_each([&vgpu, this](cfs_entry& ce){
if(ce.vgpu == vgpu)
{
_run_list.remove(ce);
}
});
}
VGpu* CompletlyFair::nextVGPU()
{
// update cfs entry
_curr->runtime += rdtsc() - _curr->ts;
// list empty?
if(_run_list.empty())
return nullptr;
cfs_entry* min = nullptr;
_run_list.head([&min](cfs_entry& ce){
min = &ce;
});
_run_list.for_each([&min](cfs_entry& ce){
if(ce.runtime < min->runtime && ce.vgpu->has_kernel())
{
min = &ce;
}
});
if(min->vgpu->has_kernel()) // in case this is still the head
{
_curr = min;
_curr->ts = rdtsc();
return min->vgpu;
}
// no vgpu with kernel found
return nullptr;
}
}

View File

@@ -0,0 +1,55 @@
#ifndef CFS_H
#define CFS_H
#include <util/fifo.h>
#include "../strategie.h"
namespace gpgpu_virt {
class CompletlyFair : Strategie
{
class cfs_entry : public Genode::Fifo<cfs_entry>::Element
{
public:
VGpu* vgpu;
unsigned long runtime;
unsigned long ts;
cfs_entry(VGpu* vg) : vgpu(vg), runtime(0), ts(0) {}
};
private:
Genode::Fifo<cfs_entry> _run_list; // TODO: Red Black Tree
cfs_entry* _curr;
CompletlyFair(const CompletlyFair &copy) = delete;
CompletlyFair(CompletlyFair&&) = delete;
CompletlyFair& operator=(const CompletlyFair&) = delete;
CompletlyFair& operator=(CompletlyFair&&) = delete;
public:
CompletlyFair() : _run_list(), _curr(nullptr) {};
/**
* @brief
*
* @param vgpu
*/
void addVGPU(VGpu* vgpu) override;
/**
* @brief
*
* @param vgpu
*/
void removeVGPU(VGpu* vgpu) override;
/**
* @brief
*
* @return VGpu*
*/
VGpu* nextVGPU() override;
};
}
#endif // CFS_H

View File

@@ -0,0 +1,57 @@
#include "rr.h"
namespace gpgpu_virt
{
void RoundRobin::addVGPU(VGpu* vgpu)
{
_run_list.enqueue(*vgpu);
}
void RoundRobin::removeVGPU(VGpu* vgpu)
{
_run_list.remove(*vgpu);
}
VGpu* RoundRobin::nextVGPU()
{
// list empty?
if(_run_list.empty())
return nullptr;
VGpu* first = nullptr;
VGpu* next = nullptr;
for(;;)
{
// get next vgpu
_run_list.dequeue([&next](VGpu& vgpu){
next = &vgpu;
});
// add vgpu back to end of list
_run_list.enqueue(*next);
// check if it has kernel?
if(next->has_kernel())
{
return next;
}
// complete iteration?
if(first == next)
{
break;
}
// set start of search
if(first == nullptr)
{
first = next;
}
}
// no vgpu with kernel found
return nullptr;
}
}

View File

@@ -0,0 +1,40 @@
#ifndef RR_H
#define RR_H
#include <util/fifo.h>
#include "../strategie.h"
namespace gpgpu_virt {
class RoundRobin : Strategie
{
private:
Genode::Fifo<VGpu> _run_list;
public:
RoundRobin() : _run_list() {};
/**
* @brief
*
* @param vgpu
*/
void addVGPU(VGpu* vgpu) override;
/**
* @brief
*
* @param vgpu
*/
void removeVGPU(VGpu* vgpu) override;
/**
* @brief
*
* @return VGpu*
*/
VGpu* nextVGPU() override;
};
}
#endif // RR_H

View File

@@ -36,7 +36,6 @@ namespace gpgpu_virt {
void add_kernel(Kernel* kernel) {
kernel->get_config()->ctx = ctx; // set context
ready_list.enqueue(*kernel);
}
/**