Optimize scheduler

This commit is contained in:
Maurice Heumann 2021-04-08 08:55:11 +02:00
parent f3d7d2c786
commit c96af6d3ad
3 changed files with 74 additions and 172 deletions

View File

@ -2,9 +2,9 @@
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "game/game.hpp"
#include <utils/concurrent_list.hpp>
#include <utils/hook.hpp>
#include <utils/thread.hpp>
#include <utils/concurrency.hpp>
namespace scheduler
{
@ -12,39 +12,82 @@ namespace scheduler
{
struct task
{
pipeline type;
std::function<bool()> handler;
std::function<bool()> handler{};
std::chrono::milliseconds interval{};
std::chrono::high_resolution_clock::time_point last_call{};
};
using task_list = std::vector<task>;
class task_pipeline
{
public:
void add(task&& task)
{
new_callbacks.access([&task](task_list& tasks)
{
tasks.emplace_back(std::move(task));
});
}
void execute()
{
callbacks.access([&](task_list& tasks)
{
this->merge_callbacks();
for (auto i = tasks.begin(); i != tasks.end();)
{
const auto now = std::chrono::high_resolution_clock::now();
const auto diff = now - i->last_call;
if (diff < i->interval)
{
++i;
continue;
}
i->last_call = now;
const auto res = i->handler();
if (res == cond_end)
{
i = tasks.erase(i);
}
else
{
++i;
}
}
});
}
private:
utils::concurrency::container<task_list> new_callbacks;
utils::concurrency::container<task_list, std::recursive_mutex> callbacks;
void merge_callbacks()
{
callbacks.access([&](task_list& tasks)
{
new_callbacks.access([&](task_list& new_tasks)
{
tasks.insert(tasks.end(), std::move_iterator<task_list::iterator>(new_tasks.begin()), std::move_iterator<task_list::iterator>(new_tasks.end()));
new_tasks = {};
});
});
}
};
volatile bool kill = false;
std::thread thread;
utils::concurrent_list<task> callbacks;
task_pipeline pipelines[pipeline::count];
utils::hook::detour r_end_frame_hook;
void execute(const pipeline type)
{
for (auto callback : callbacks)
{
if (callback->type != type)
{
continue;
}
const auto now = std::chrono::high_resolution_clock::now();
const auto diff = now - callback->last_call;
if (diff < callback->interval) continue;
callback->last_call = now;
const auto res = callback->handler();
if (res == cond_end)
{
callbacks.remove(callback);
}
}
assert(type >= 0 && type < pipeline::count);
pipelines[type].execute();
}
void r_end_frame_stub()
@ -69,13 +112,14 @@ namespace scheduler
void schedule(const std::function<bool()>& callback, const pipeline type,
const std::chrono::milliseconds delay)
{
assert(type >= 0 && type < pipeline::count);
task task;
task.type = type;
task.handler = callback;
task.interval = delay;
task.last_call = std::chrono::high_resolution_clock::now();
callbacks.add(task);
pipelines[type].add(std::move(task));
}
void loop(const std::function<void()>& callback, const pipeline type,

View File

@ -2,10 +2,10 @@
namespace scheduler
{
enum class pipeline
enum pipeline
{
// Asynchronuous pipeline, disconnected from the game
async,
async = 0,
// The game's rendering pipeline
renderer,
@ -15,6 +15,8 @@ namespace scheduler
// The game's main thread
main,
count,
};
static const bool cond_continue = false;

View File

@ -1,144 +0,0 @@
#pragma once
#include <mutex>
#include <memory>
// This class is trash. Need to get rid of it.
namespace utils
{
template <typename T>
class concurrent_list final
{
public:
class element final
{
public:
explicit element(std::recursive_mutex* mutex, std::shared_ptr<T> entry = {},
std::shared_ptr<element> next = {}) :
mutex_(mutex),
entry_(std::move(entry)),
next_(std::move(next))
{
}
void remove(const std::shared_ptr<T>& element)
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
if (!this->next_) return;
if (this->next_->entry_.get() == element.get())
{
this->next_ = this->next_->next_;
}
else
{
this->next_->remove(element);
}
}
[[nodiscard]] std::shared_ptr<element> get_next() const
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
return this->next_;
}
std::shared_ptr<T> operator*() const
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
return this->entry_;
}
element& operator++()
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
*this = this->next_ ? *this->next_ : element(this->mutex_);
return *this;
}
element operator++(int)
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
auto result = *this;
this->operator++();
return result;
}
bool operator==(const element& other)
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
return this->entry_.get() == other.entry_.get();
}
bool operator!=(const element& other)
{
std::lock_guard<std::recursive_mutex> _(*this->mutex_);
return !(*this == other);
}
private:
std::recursive_mutex* mutex_;
std::shared_ptr<T> entry_;
std::shared_ptr<element> next_;
};
element begin()
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
return this->entry_ ? *this->entry_ : this->end();
}
element end()
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
return element(&this->mutex_);
}
void remove(const element& entry)
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
this->remove(*entry);
}
void remove(const std::shared_ptr<T>& element)
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
if (!this->entry_) return;
if ((**this->entry_).get() == element.get())
{
this->entry_ = this->entry_->get_next();
}
else
{
this->entry_->remove(element);
}
}
void add(const T& object)
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
const auto object_ptr = std::make_shared<T>(object);
this->entry_ = std::make_shared<element>(&this->mutex_, object_ptr, this->entry_);
}
void add(T&& object)
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
const auto object_ptr = std::make_shared<T>(std::move(object));
this->entry_ = std::make_shared<element>(&this->mutex_, object_ptr, this->entry_);
}
void clear()
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
this->entry_ = {};
}
private:
std::recursive_mutex mutex_;
std::shared_ptr<element> entry_;
};
}