64 thread(self_type& aOwner) :
async_task{
"neolib::ecs::system::thread" },
async_thread{ *
this,
"neolib::ecs::system::thread" }, iOwner{ aOwner }
78 if (iOwner.can_apply())
79 didWork = iOwner.apply() || didWork;
81 if (iOwner.paused() && !iOwner.waiting())
89 struct performance_metrics
91 std::vector<std::chrono::microseconds> updateTimes;
92 std::size_t updateCounter = 0;
93 std::chrono::high_resolution_clock::time_point updateStartTime;
96 struct no_thread : std::logic_error {
no_thread() : std::logic_error{
"neolib::ecs::system::no_thread" } {} };
99 iEcs{ aEcs }, iComponents{
ComponentData::meta::
id()... }, iPaused{ 0u }
104 iEcs{ aOther.iEcs }, iComponents{ aOther.iComponents }, iPaused{ 0u }
109 iEcs{ aOther.iEcs }, iComponents{
std::move(aOther.iComponents) }, iPaused{ 0u }
113 template <
typename ComponentIdIter>
114 system(
i_ecs& aEcs, ComponentIdIter aFirstComponent, ComponentIdIter aLastComponent) :
115 iEcs{ aEcs }, iComponents{ aFirstComponent, aLastComponent }, iPaused{ 0u }
154 return iPaused != 0u;
162 if (--iPaused == 0 &&
waiting())
181 std::unique_lock<std::mutex> lock{ iMutex };
183 iCondVar.wait(lock, [&]() {
return !iWaiting; });
193 std::unique_lock<std::mutex> lock{ iMutex };
195 iCondVar.wait_for(lock, std::chrono::duration<double>(aDuration), [&](){
return !iWaiting; });
203 std::unique_lock<std::mutex> lock{ iMutex };
211 iCondVar.notify_one();
216 if (
ecs().run_threaded(
id()))
221 iThread = std::make_unique<thread>(*
this);
230 if (iDebug != aDebug)
233 iPerformanceMetrics.clear();
236 std::chrono::microseconds
update_time(std::size_t aMetricsIndex = 0)
const override
238 if (iPerformanceMetrics.size() <= aMetricsIndex || iPerformanceMetrics[aMetricsIndex].updateTimes.empty())
239 return std::chrono::microseconds{ 0 };
240 return std::accumulate(iPerformanceMetrics[aMetricsIndex].updateTimes.begin(), iPerformanceMetrics[aMetricsIndex].updateTimes.end(), std::chrono::microseconds{}) / iPerformanceMetrics[aMetricsIndex].updateTimes.size();
245 return iThread !=
nullptr;
255 if (service<neolib::i_power>().green_mode_active() || aSleep)
268 if (iPerformanceMetrics.size() <= aMetricsIndex)
269 iPerformanceMetrics.resize(aMetricsIndex + 1);
270 iPerformanceMetrics[aMetricsIndex].updateStartTime = std::chrono::high_resolution_clock::now();
277 if (iPerformanceMetrics.size() > aMetricsIndex)
279 std::size_t
const updateQueueSize = 100;
280 auto const time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - iPerformanceMetrics[aMetricsIndex].updateStartTime);
281 if (iPerformanceMetrics[aMetricsIndex].updateTimes.size() < updateQueueSize)
282 iPerformanceMetrics[aMetricsIndex].updateTimes.push_back(
time);
285 iPerformanceMetrics[aMetricsIndex].updateTimes[iPerformanceMetrics[aMetricsIndex].updateCounter++] =
time;
286 iPerformanceMetrics[aMetricsIndex].updateCounter %= updateQueueSize;
293 component_list iComponents;
294 std::atomic<uint32_t> iPaused = 0u;
296 std::condition_variable iCondVar;
297 std::atomic<bool> iWaiting =
false;
298 std::atomic<bool> iDebug =
false;
299 std::vector<performance_metrics> iPerformanceMetrics;
300 std::unique_ptr<thread> iThread;
void set_destroying() override
i_thread & thread() const override
bool do_work(yield_type aYieldType=yield_type::NoYield) override
virtual const i_component & component(component_id aComponentId) const =0
virtual bool all_systems_paused() const =0
virtual const system_id & id() const =0
bool paused() const override
void start_update(std::size_t aMetricsIndex=0)
void wait_for(scalar aDuration) override
void start_thread_if() override
void terminate() override
void yield(bool aSleep=false)
system(i_ecs &aEcs, ComponentIdIter aFirstComponent, ComponentIdIter aLastComponent)
i_ecs & ecs() const override
bool can_apply() const override
std::chrono::microseconds update_time(std::size_t aMetricsIndex=0) const override
bool debug() const override
const i_set< component_id > & components() const override
void set_debug(bool aDebug) override
i_set< component_id > & components() override
i_component & component(component_id aComponentId) override
thread & get_thread() const
bool waiting() const override
system(const system &aOther)
const i_component & component(component_id aComponentId) const override
std::mutex & waiting_mutex()
void end_update(std::size_t aMetricsIndex=0)
void start_thread() override
static void sleep(const std::chrono::duration< double, std::milli > &aDuration)
bool is_alive(Object &aObject)
boost::fast_pool_allocator< T, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex, NextSize > fast_pool_allocator