Commit 940ba052 authored by Philipp Schäfer's avatar Philipp Schäfer
Browse files

OutdoorAcoustics

- internal due to moving outdoor worker out of ART
parent bc237086
#ifndef INCLUDE_WATCHER_ITA_SIMULATION_SCHEDULER_OUTDOOR_ACOUSTICS_ART_WORKER_THREAD
#define INCLUDE_WATCHER_ITA_SIMULATION_SCHEDULER_OUTDOOR_ACOUSTICS_ART_WORKER_THREAD
#ifndef INCLUDE_WATCHER_ITA_SIMULATION_SCHEDULER_OUTDOOR_ACOUSTICS_WORKER_THREAD
#define INCLUDE_WATCHER_ITA_SIMULATION_SCHEDULER_OUTDOOR_ACOUSTICS_WORKER_THREAD
// std include
#include <string>
......@@ -28,125 +28,122 @@ namespace ITA
{
namespace OutdoorAcoustics
{
namespace ART
//struct CARonfig;
//! \brief Outdoor simulation worker utilizing a thread to run the actual simulation.
class ITA_SIMULATION_SCHEDULER_API CWorkerThread : public IWorkerInterface, VistaThreadLoop
{
//struct CARonfig;
public:
//! \brief ART worker utilizing a thread to run the actual simulation.
class ITA_SIMULATION_SCHEDULER_API CWorkerThread : public IWorkerInterface, VistaThreadLoop
//! \brief Configuration class for a raven thread worker.
struct ITA_SIMULATION_SCHEDULER_API WorkerThreadConfig : public IWorkerInterface::WorkerConfig
{
public:
//! \brief Configuration class for a raven thread worker.
struct ITA_SIMULATION_SCHEDULER_API WorkerThreadConfig : public IWorkerInterface::WorkerConfig
{
explicit WorkerThreadConfig ( );
explicit WorkerThreadConfig(const std::string& sType);
VistaPropertyList Store ( ) const override;
void Load ( const VistaPropertyList& oProperties ) override;
const std::string& sSimulatorType;
private:
std::string m_sSimulatorType;
};
//! \brief Constructor for CWorkerThread.
//! \param oConfig the WorkerConfig used to configure the CWorkerThread.
//! \param pParent the parent scheduler of the worker.
CWorkerThread ( const WorkerThreadConfig& oConfig, ISchedulerInterface* pParent );
//! \brief Destructor of CWorkerThread.
/**
* This waits till the simulation is finished and stops the thread loop gently.
*/
~CWorkerThread ( );
//! \brief Checks if the worker is busy.
inline bool IsBusy() override
{
return m_bBusy;
};
//! \brief Push a new update to the worker.
//!
//! After a new Update is pushed to a worker, the update gets simulated immediately.
//! \note This method takes ownership of the update.
//! \param pUpdateMessage the new update for the scheduler.
void PushUpdate ( std::unique_ptr<CUpdateScene> pUpdate ) override;
//! \brief Reset the worker.
//! \detail Also resets the simulator
void Reset ( ) override;
//! \brief Shutdown the worker safely.
void Shutdown() override;
//! \brief Factory function for CWorkerThread.
//! \param pConfig the WorkerConfig used to configure the CWorkerThread.
//! \param pParent the parent scheduler of the worker.
static std::unique_ptr<IWorkerInterface> CreateWorker ( const std::shared_ptr<IWorkerInterface::WorkerConfig>& pConfig, ISchedulerInterface* pParent );
//! \brief Return a unique type identifying string.
//! \return a unique type identifying string.
inline static std::string GetType() { return "OutdoorAcousticsWorkerThread"; };
protected:
//! \brief Loop body for the CWorkerThread.
/** The following steps are done in the loop:
* - Check if the scene is loaded, and load it if not.
* - Simulate the Task.
* - Forward the result to the scheduler.
* \return true if VistaThreadLoop::ThreadBody() shall call VistaThread::YieldThread() before the next loop, false else
*/
virtual bool LoopBody ( ) override;
//! \brief Pre loop function.
/**
* This function is called once before the thread starts.
* \note This is primarily used to set the thread name while profiling.
*/
void PreLoop ( ) override;
//! \brief Set the simulator of the worker.
/**
* \param pSimulator the new simulator.
* \note This function is primarily for testing.
* However, it could also be useful in the long run.
*/
//void SetSimulator ( std::unique_ptr<ISimulatorInterface> pSimulator );
private:
//! \brief Pointer to simulator interface for outdoor scenarios
std::unique_ptr<ISimulatorInterface> m_oSimulator;
//! \brief If busy, this holds a pointer to the scene update to be simulated
std::unique_ptr<CUpdateScene> m_pUpdate = nullptr;
explicit WorkerThreadConfig();
explicit WorkerThreadConfig(const std::string& sType);
//! \brief Trigger for starting a thread loop.
VistaThreadEvent m_evTriggerLoop;
VistaPropertyList Store() const override;
void Load(const VistaPropertyList& oProperties) override;
//! Indicates whether worker is busy or not
ITAAtomicBool m_bBusy = false;
const std::string& sSimulatorType;
private:
std::string m_sSimulatorType;
};
///
/// \{
/// \brief Bools for handling the stop of the loop.
///
/// As these will be accessed by two threads, they have to be atomic.
///
ITAAtomicBool m_bStopIndicated = false;
//! \brief Constructor for CWorkerThread.
//! \param oConfig the WorkerConfig used to configure the CWorkerThread.
//! \param pParent the parent scheduler of the worker.
CWorkerThread(const WorkerThreadConfig& oConfig, ISchedulerInterface* pParent);
ITAAtomicBool m_bResetIndicated = false;
/// \}
//! \brief Destructor of CWorkerThread.
/**
* This waits till the simulation is finished and stops the thread loop gently.
*/
~CWorkerThread();
#ifdef WITH_PROFILER
static std::size_t iWorkerMaxID;
#endif
//! \brief Checks if the worker is busy.
inline bool IsBusy() override
{
return m_bBusy;
};
} // namespace ART
//! \brief Push a new update to the worker.
//!
//! After a new Update is pushed to a worker, the update gets simulated immediately.
//! \note This method takes ownership of the update.
//! \param pUpdateMessage the new update for the scheduler.
void PushUpdate(std::unique_ptr<CUpdateScene> pUpdate) override;
//! \brief Reset the worker.
//! \detail Also resets the simulator
void Reset() override;
//! \brief Shutdown the worker safely.
void Shutdown() override;
//! \brief Factory function for CWorkerThread.
//! \param pConfig the WorkerConfig used to configure the CWorkerThread.
//! \param pParent the parent scheduler of the worker.
static std::unique_ptr<IWorkerInterface> CreateWorker(const std::shared_ptr<IWorkerInterface::WorkerConfig>& pConfig, ISchedulerInterface* pParent);
//! \brief Return a unique type identifying string.
//! \return a unique type identifying string.
inline static std::string GetType() { return "OutdoorAcousticsWorkerThread"; };
protected:
//! \brief Loop body for the CWorkerThread.
/** The following steps are done in the loop:
* - Check if the scene is loaded, and load it if not.
* - Simulate the Task.
* - Forward the result to the scheduler.
* \return true if VistaThreadLoop::ThreadBody() shall call VistaThread::YieldThread() before the next loop, false else
*/
virtual bool LoopBody() override;
//! \brief Pre loop function.
/**
* This function is called once before the thread starts.
* \note This is primarily used to set the thread name while profiling.
*/
void PreLoop() override;
//! \brief Set the simulator of the worker.
/**
* \param pSimulator the new simulator.
* \note This function is primarily for testing.
* However, it could also be useful in the long run.
*/
//void SetSimulator ( std::unique_ptr<ISimulatorInterface> pSimulator );
private:
//! \brief Pointer to simulator interface for outdoor scenarios
std::unique_ptr<ISimulatorInterface> m_oSimulator;
//! \brief If busy, this holds a pointer to the scene update to be simulated
std::unique_ptr<CUpdateScene> m_pUpdate = nullptr;
//! \brief Trigger for starting a thread loop.
VistaThreadEvent m_evTriggerLoop;
//! Indicates whether worker is busy or not
ITAAtomicBool m_bBusy = false;
///
/// \{
/// \brief Bools for handling the stop of the loop.
///
/// As these will be accessed by two threads, they have to be atomic.
///
ITAAtomicBool m_bStopIndicated = false;
ITAAtomicBool m_bResetIndicated = false;
/// \}
#ifdef WITH_PROFILER
static std::size_t iWorkerMaxID;
#endif
};
} // namespace OutdoorAcoustics
} // namespace SimulationScheduler
} // namespace ITA
#endif // INCLUDE_WATCHER_ITA_SIMULATION_SCHEDULER_OUTDOOR_ACOUSTICS_ART_WORKER_THREAD
\ No newline at end of file
#endif // INCLUDE_WATCHER_ITA_SIMULATION_SCHEDULER_OUTDOOR_ACOUSTICS_WORKER_THREAD
\ No newline at end of file
// Header include
#include <ITA/SimulationScheduler/OutdoorAcoustics/ART/art_worker_thread.h>
#include <ITA/SimulationScheduler/OutdoorAcoustics/outdoor_worker_thread.h>
// Simulation scheduler includes
#include <ITA/SimulationScheduler/scheduler_interface.h>
#include <ITA/SimulationScheduler/OutdoorAcoustics/outdoor_simulation_result.h>
#include <ITA/SimulationScheduler/Profiler/profiler.h>
#include "../../configuration_keys.h"
#include "../configuration_keys.h"
// Vista includes
#include <VistaBase/VistaTimeUtils.h>
......@@ -21,191 +21,188 @@ namespace ITA
{
namespace OutdoorAcoustics
{
namespace ART
#ifdef WITH_PROFILER
std::size_t CWorkerThread::iWorkerMaxID = 0;
#endif
CWorkerThread::WorkerThreadConfig::WorkerThreadConfig()
: WorkerThreadConfig("Unkown")
{ }
CWorkerThread::WorkerThreadConfig::WorkerThreadConfig(const std::string& sType)
: WorkerConfig(GetType())
, m_sSimulatorType(sType)
, sSimulatorType(m_sSimulatorType)
{
#ifdef WITH_PROFILER
std::size_t CWorkerThread::iWorkerMaxID = 0;
#endif
CWorkerThread::WorkerThreadConfig::WorkerThreadConfig ( )
: WorkerThreadConfig( "Unkown" )
{ }
CWorkerThread::WorkerThreadConfig::WorkerThreadConfig(const std::string& sType)
: WorkerConfig(GetType())
, m_sSimulatorType( sType )
, sSimulatorType( m_sSimulatorType )
{
}
}
VistaPropertyList CWorkerThread::WorkerThreadConfig::Store ( ) const
{
auto oProperties = WorkerConfig::Store ( );
VistaPropertyList CWorkerThread::WorkerThreadConfig::Store() const
{
auto oProperties = WorkerConfig::Store();
oProperties.SetValue (SIMULATOR_TYPE_KEY, sSimulatorType );
oProperties.SetValue(SIMULATOR_TYPE_KEY, sSimulatorType);
return oProperties;
}
return oProperties;
}
void CWorkerThread::WorkerThreadConfig::Load ( const VistaPropertyList& oProperties )
{
WorkerConfig::Load ( oProperties );
void CWorkerThread::WorkerThreadConfig::Load(const VistaPropertyList& oProperties)
{
WorkerConfig::Load(oProperties);
oProperties.GetValue (SIMULATOR_TYPE_KEY, m_sSimulatorType);
}
oProperties.GetValue(SIMULATOR_TYPE_KEY, m_sSimulatorType);
}
CWorkerThread::CWorkerThread ( const WorkerThreadConfig& oConfig, ISchedulerInterface* pParent ) :
IWorkerInterface ( pParent ), m_evTriggerLoop ( VistaThreadEvent::NON_WAITABLE_EVENT )
{
//oConfig;
//m_oSimulator = std::make_unique<CSimulator> ( m_eFieldOfDuty, oConfig.sRavenProjectFilePath );
CWorkerThread::CWorkerThread(const WorkerThreadConfig& oConfig, ISchedulerInterface* pParent) :
IWorkerInterface(pParent), m_evTriggerLoop(VistaThreadEvent::NON_WAITABLE_EVENT)
{
//oConfig;
//m_oSimulator = std::make_unique<CSimulator> ( m_eFieldOfDuty, oConfig.sRavenProjectFilePath );
Run ( );
}
Run();
}
CWorkerThread::~CWorkerThread ( )
{
m_bStopIndicated = true;
m_evTriggerLoop.SignalEvent ( );
CWorkerThread::~CWorkerThread()
{
m_bStopIndicated = true;
m_evTriggerLoop.SignalEvent();
// Wait for the end of the simulation
while ( IsBusy ( ) ) VistaTimeUtils::Sleep ( 100 );
// Wait for the end of the simulation
while (IsBusy()) VistaTimeUtils::Sleep(100);
StopGently ( true );
}
StopGently(true);
}
void CWorkerThread::PushUpdate(std::unique_ptr<CUpdateScene> pUpdate)
{
//PROFILER_FUNCTION ( );
PROFILER_VALUE("Update to Worker", pUpdate->GetID());
//auto pTask = CreateTaskFromUpdate ( std::move ( pUpdate ) );
assert(!IsBusy());
m_bBusy = true;
void CWorkerThread::PushUpdate ( std::unique_ptr<CUpdateScene> pUpdate )
m_pUpdate = std::move(pUpdate);
// Stop if reset is running.
if (m_bResetIndicated)
{
//PROFILER_FUNCTION ( );
PROFILER_VALUE ( "Update to Worker", pUpdate->GetID ( ) );
//auto pTask = CreateTaskFromUpdate ( std::move ( pUpdate ) );
assert ( !IsBusy ( ) );
m_bBusy = true;
m_pUpdate = std::move(pUpdate);
// Stop if reset is running.
if ( m_bResetIndicated )
{
m_pUpdate = nullptr;
m_bBusy = false;
return;
}
// Start the loop and simulation.
m_evTriggerLoop.SignalEvent ( );
m_pUpdate = nullptr;
m_bBusy = false;
return;
}
void CWorkerThread::Reset ( )
{
// Signal reset
m_bResetIndicated = true;
// Start the loop and simulation.
m_evTriggerLoop.SignalEvent();
}
// Wait for the end of the simulation
while ( IsBusy ( ) ) VistaTimeUtils::Sleep ( 100 );
void CWorkerThread::Reset()
{
// Signal reset
m_bResetIndicated = true;
// Reset the simulator
m_oSimulator->Reset ( );
// Wait for the end of the simulation
while (IsBusy()) VistaTimeUtils::Sleep(100);
// Reset the flags
m_bResetIndicated = false;
}
// Reset the simulator
m_oSimulator->Reset();
void CWorkerThread::Shutdown()
{
m_bStopIndicated = true;
m_evTriggerLoop.SignalEvent ( );
// Reset the flags
m_bResetIndicated = false;
}
// Wait for the end of the simulation
while ( IsBusy ( ) ) VistaTimeUtils::Sleep ( 100 );
void CWorkerThread::Shutdown()
{
m_bStopIndicated = true;
m_evTriggerLoop.SignalEvent();
StopGently ( true );
}
// Wait for the end of the simulation
while (IsBusy()) VistaTimeUtils::Sleep(100);
StopGently(true);
}
std::unique_ptr<IWorkerInterface> CWorkerThread::CreateWorker(
const std::shared_ptr<IWorkerInterface::WorkerConfig>& pConfig, ISchedulerInterface* pParent)
{
return std::make_unique<CWorkerThread>(dynamic_cast<const WorkerThreadConfig&>(*pConfig), pParent);
}
//void CWorkerThread::SetSimulator ( std::unique_ptr<ISimulatorInterface> pSimulator )
//{
// m_pSimulator = std::move ( pSimulator );
//}
std::unique_ptr<IWorkerInterface> CWorkerThread::CreateWorker (
const std::shared_ptr<IWorkerInterface::WorkerConfig>& pConfig, ISchedulerInterface* pParent )
bool CWorkerThread::LoopBody()
{
// Wait for trigger
m_evTriggerLoop.WaitForEvent(true);
m_evTriggerLoop.ResetThisEvent();
PROFILER_FUNCTION();
if (m_bStopIndicated)
{
return std::make_unique<CWorkerThread> ( dynamic_cast< const WorkerThreadConfig& >( *pConfig ), pParent );
IndicateLoopEnd();
PROFILER_EVENT_COUNT("Loop Stop");
return false;
}
//void CWorkerThread::SetSimulator ( std::unique_ptr<ISimulatorInterface> pSimulator )
//{
// m_pSimulator = std::move ( pSimulator );
//}
assert(!m_bResetIndicated);
assert(m_pUpdate);
bool CWorkerThread::LoopBody ( )
{
// Wait for trigger
m_evTriggerLoop.WaitForEvent ( true );
m_evTriggerLoop.ResetThisEvent ( );
PROFILER_FUNCTION ( );
if ( m_bStopIndicated )
{
IndicateLoopEnd ( );
PROFILER_EVENT_COUNT ( "Loop Stop" );
return false;
}
assert ( !m_bResetIndicated );
assert ( m_pUpdate );
const unsigned int uiUpdateID = m_pUpdate->GetID();
//R_INFO ( "raven::WorkerThread:\tStarting simulation on Task %i, SimType %i\n", pTask->uiID, pTask->eSimulationType );
PROFILER_SECTION ( "Compute Update/Task" );
PROFILER_VALUE ( "Compute Update/Task", uiUpdateID);
std::unique_ptr<COutdoorSimulationResult> pResult = nullptr;
try
{
// Simulate (blocking)
DEBUG_PRINTF ( "[ART Thread Worker]\t Simulation Started\n" );
pResult = m_oSimulator->Compute ( std::move(m_pUpdate) );
m_pUpdate = nullptr;
DEBUG_PRINTF ( "[ART Thread Worker]\t Simulation Finished\n" );
}
catch ( ITAException& e )
{
m_pUpdate = nullptr;
std::cerr << e.ToString ( );
}
PROFILER_VALUE ( "Update/Task Simulated", uiUpdateID);
PROFILER_END_SECTION ( );
try
{
if (pResult)
m_pParentScheduler->HandleSimulationFinished ( std::move ( pResult ) );
}
catch ( ITAException& e )
{
std::cerr << e.ToString ( );
}
PROFILER_VALUE ( "Result handled", uiUpdateID);
//R_INFO ( "raven::WorkerThread:\tTask send to scheduler\n" );
// Worker is free again
m_bBusy = false;
const unsigned int uiUpdateID = m_pUpdate->GetID();
return true;
}
//R_INFO ( "raven::WorkerThread:\tStarting simulation on Task %i, SimType %i\n", pTask->uiID, pTask->eSimulationType );
void CWorkerThread::PreLoop()
PROFILER_SECTION("Compute Update/Task");
PROFILER_VALUE("Compute Update/Task", uiUpdateID);
std::unique_ptr<COutdoorSimulationResult> pResult = nullptr;
try
{
#ifdef WITH_PROFILER
const std::string sThreadName = "Outdoor Worker Thread " + std::to_string(iWorkerMaxID++);
// Simulate (blocking)
DEBUG_PRINTF("[ART Thread Worker]\t Simulation Started\n");
pResult = m_oSimulator->Compute(std::move(m_pUpdate));
m_pUpdate = nullptr;
DEBUG_PRINTF("[ART Thread Worker]\t Simulation Finished\n");
}
catch (ITAException & e)
{
m_pUpdate = nullptr;
std::cerr << e.ToString();
}
PROFILER_VALUE("Update/Task Simulated", uiUpdateID);
PROFILER_END_SECTION();
SetThreadName ( sThreadName );
PROFILER_NAME_THREAD ( sThreadName );
#endif
try
{
if (pResult)
m_pParentScheduler->HandleSimulationFinished(std::move(pResult));
}
catch (ITAException & e)
{
std::cerr << e.ToString();
}
} // namespace Raven
} // namespace RoomAcoustics
PROFILER_VALUE("Result handled", uiUpdateID);
//R_INFO ( "raven::WorkerThread:\tTask send to scheduler\n" );
// Worker is free again
m_bBusy = false;
return true;
}
void CWorkerThread::PreLoop()
{
#ifdef WITH_PROFILER