diff --git a/repos/dde_uos-intel-gpgpu/src/gpgpu/gpgpu_genode.cc b/repos/dde_uos-intel-gpgpu/src/gpgpu/gpgpu_genode.cc index 2363805778..3b0ec70090 100644 --- a/repos/dde_uos-intel-gpgpu/src/gpgpu/gpgpu_genode.cc +++ b/repos/dde_uos-intel-gpgpu/src/gpgpu/gpgpu_genode.cc @@ -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 { diff --git a/repos/dde_uos-intel-gpgpu/src/gpgpu/main.cc b/repos/dde_uos-intel-gpgpu/src/gpgpu/main.cc index fd9a6c0659..d3477d9f05 100644 --- a/repos/dde_uos-intel-gpgpu/src/gpgpu/main.cc +++ b/repos/dde_uos-intel-gpgpu/src/gpgpu/main.cc @@ -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 diff --git a/repos/dde_uos-intel-gpgpu/src/gpgpu/target.mk b/repos/dde_uos-intel-gpgpu/src/gpgpu/target.mk index f128664f08..11d8619622 100644 --- a/repos/dde_uos-intel-gpgpu/src/gpgpu/target.mk +++ b/repos/dde_uos-intel-gpgpu/src/gpgpu/target.mk @@ -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 diff --git a/repos/dde_uos-intel-gpgpu/src/virt/rpc.cc b/repos/dde_uos-intel-gpgpu/src/virt/rpc.cc index 9eee559243..ec8684fe30 100644 --- a/repos/dde_uos-intel-gpgpu/src/virt/rpc.cc +++ b/repos/dde_uos-intel-gpgpu/src/virt/rpc.cc @@ -5,12 +5,13 @@ #include #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 diff --git a/repos/dde_uos-intel-gpgpu/src/virt/scheduler.cc b/repos/dde_uos-intel-gpgpu/src/virt/scheduler.cc deleted file mode 100644 index 67e853d609..0000000000 --- a/repos/dde_uos-intel-gpgpu/src/virt/scheduler.cc +++ /dev/null @@ -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); -} - -} diff --git a/repos/dde_uos-intel-gpgpu/src/virt/scheduler.h b/repos/dde_uos-intel-gpgpu/src/virt/scheduler.h index b8815332c6..c56e1776dc 100644 --- a/repos/dde_uos-intel-gpgpu/src/virt/scheduler.h +++ b/repos/dde_uos-intel-gpgpu/src/virt/scheduler.h @@ -1,28 +1,35 @@ #ifndef SCHEDULER_H #define SCHEDULER_H -#include #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 class Scheduler { private: + S strat; VGpu* _curr_vgpu; - Genode::Fifo _run_list; bool idle; + + Scheduler(const Scheduler ©) = 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; } #endif // SCHEDULER_H diff --git a/repos/dde_uos-intel-gpgpu/src/virt/strategie.h b/repos/dde_uos-intel-gpgpu/src/virt/strategie.h new file mode 100644 index 0000000000..4633bc8b6a --- /dev/null +++ b/repos/dde_uos-intel-gpgpu/src/virt/strategie.h @@ -0,0 +1,40 @@ +#ifndef STRATEGIE_H +#define STRATEGIE_H + +#include "vgpu.h" + +namespace gpgpu_virt { + + class Strategie + { + private: + Strategie(const Strategie ©) = 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 diff --git a/repos/dde_uos-intel-gpgpu/src/virt/strategies/cfs.cc b/repos/dde_uos-intel-gpgpu/src/virt/strategies/cfs.cc new file mode 100644 index 0000000000..22cda75dfd --- /dev/null +++ b/repos/dde_uos-intel-gpgpu/src/virt/strategies/cfs.cc @@ -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; +} + +} diff --git a/repos/dde_uos-intel-gpgpu/src/virt/strategies/cfs.h b/repos/dde_uos-intel-gpgpu/src/virt/strategies/cfs.h new file mode 100644 index 0000000000..34accc1694 --- /dev/null +++ b/repos/dde_uos-intel-gpgpu/src/virt/strategies/cfs.h @@ -0,0 +1,55 @@ +#ifndef CFS_H +#define CFS_H + +#include +#include "../strategie.h" + +namespace gpgpu_virt { + + class CompletlyFair : Strategie + { + class cfs_entry : public Genode::Fifo::Element + { + public: + VGpu* vgpu; + unsigned long runtime; + unsigned long ts; + cfs_entry(VGpu* vg) : vgpu(vg), runtime(0), ts(0) {} + }; + + private: + Genode::Fifo _run_list; // TODO: Red Black Tree + cfs_entry* _curr; + + CompletlyFair(const CompletlyFair ©) = 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 diff --git a/repos/dde_uos-intel-gpgpu/src/virt/strategies/rr.cc b/repos/dde_uos-intel-gpgpu/src/virt/strategies/rr.cc new file mode 100644 index 0000000000..c3905b1606 --- /dev/null +++ b/repos/dde_uos-intel-gpgpu/src/virt/strategies/rr.cc @@ -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; +} + +} diff --git a/repos/dde_uos-intel-gpgpu/src/virt/strategies/rr.h b/repos/dde_uos-intel-gpgpu/src/virt/strategies/rr.h new file mode 100644 index 0000000000..a80ae0ecf2 --- /dev/null +++ b/repos/dde_uos-intel-gpgpu/src/virt/strategies/rr.h @@ -0,0 +1,40 @@ +#ifndef RR_H +#define RR_H + +#include +#include "../strategie.h" + +namespace gpgpu_virt { + + class RoundRobin : Strategie + { + private: + Genode::Fifo _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 diff --git a/repos/dde_uos-intel-gpgpu/src/virt/vgpu.h b/repos/dde_uos-intel-gpgpu/src/virt/vgpu.h index 267ccf0942..74ec851327 100644 --- a/repos/dde_uos-intel-gpgpu/src/virt/vgpu.h +++ b/repos/dde_uos-intel-gpgpu/src/virt/vgpu.h @@ -36,7 +36,6 @@ namespace gpgpu_virt { void add_kernel(Kernel* kernel) { kernel->get_config()->ctx = ctx; // set context ready_list.enqueue(*kernel); - } /**