Added mainloop frame notifications
Using Emesary Global Transmitter the following events are notified * Frame Begin * Frame End * Mainloop started * Mainloop stopped This integrates with the background threaded Nasal Garbage collection (simgear:nasal/cppbind/NasalEmesaryInterface.hxx) and is also controlled by the properties as follows * /sim/nasal-gc-threaded (true) - use background threaded GC * /sim/nasal-gc-threaded-wait (false) - at the start of the frame wait for the previous GC thread to complete. I initially thought that the wait at the start of the frame would be necessary; however in 100 or so hours of flight without the await for completion at the start of frame no threading problems (or any other problems) were shown; so nasal-gc-threaded-wait is defaulted to false which gives a slight boost in performance. So what this does is to it removes the GC pause of 10-20ms every 4 seconds (test using the F-15). This change doesn't really give much extra performance per frame because normally GC is only performed when needed.
This commit is contained in:
parent
8c4334e3ae
commit
6ebc91d3f7
1 changed files with 56 additions and 3 deletions
|
@ -56,6 +56,8 @@ extern bool global_crashRptEnabled;
|
||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/structure/commands.hxx>
|
#include <simgear/structure/commands.hxx>
|
||||||
|
#include <simgear/emesary/emesary.hxx>
|
||||||
|
#include <simgear/emesary/notifications.hxx>
|
||||||
|
|
||||||
#include <Add-ons/AddonManager.hxx>
|
#include <Add-ons/AddonManager.hxx>
|
||||||
#include <Main/locale.hxx>
|
#include <Main/locale.hxx>
|
||||||
|
@ -101,11 +103,52 @@ using std::vector;
|
||||||
extern int _bootstrap_OSInit;
|
extern int _bootstrap_OSInit;
|
||||||
|
|
||||||
static SGPropertyNode_ptr frame_signal;
|
static SGPropertyNode_ptr frame_signal;
|
||||||
|
static SGPropertyNode_ptr nasal_gc_threaded;
|
||||||
|
static SGPropertyNode_ptr nasal_gc_threaded_wait;
|
||||||
|
|
||||||
// What should we do when we have nothing else to do? Let's get ready
|
#ifdef NASAL_BACKGROUND_GC_THREAD
|
||||||
// for the next move and update the display?
|
extern "C" {
|
||||||
|
extern void startNasalBackgroundGarbageCollection();
|
||||||
|
extern void stopNasalBackgroundGarbageCollection();
|
||||||
|
extern void performNasalBackgroundGarbageCollection();
|
||||||
|
extern void awaitNasalGarbageCollectionComplete(bool can_wait);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
static simgear::Notifications::MainLoopNotification mln_begin(simgear::Notifications::MainLoopNotification::Type::Begin);
|
||||||
|
static simgear::Notifications::MainLoopNotification mln_end(simgear::Notifications::MainLoopNotification::Type::End);
|
||||||
|
static simgear::Notifications::MainLoopNotification mln_started(simgear::Notifications::MainLoopNotification::Type::Started);
|
||||||
|
static simgear::Notifications::MainLoopNotification mln_stopped(simgear::Notifications::MainLoopNotification::Type::Stopped);
|
||||||
|
static simgear::Notifications::NasalGarbageCollectionConfigurationNotification *ngccn = nullptr;
|
||||||
|
// This method is usually called after OSG has finished rendering a frame in what OSG calls an idle handler and
|
||||||
|
// is reposonsible for invoking all of the relevant per frame processing; most of which is handled by subsystems.
|
||||||
static void fgMainLoop( void )
|
static void fgMainLoop( void )
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// the Nasal GC will automatically run when (during allocation) it discovers that more space is needed.
|
||||||
|
// This has a cost of between 5ms and 50ms (depending on the amount of currently active Nasal).
|
||||||
|
// The result is unscheduled and unpredictable pauses during normal operation when the garbage collector
|
||||||
|
// runs; which typically occurs at intervals between 1sec and 20sec.
|
||||||
|
//
|
||||||
|
// The solution to this, which overall increases CPU load, is to use a thread to do this; as Nasal is thread safe
|
||||||
|
// so what we do is to launch the garbage collection at the end of the main loop and then wait for completion at the start of the
|
||||||
|
// next main loop.
|
||||||
|
// So although the overall CPU is increased it has little effect on the frame rate; if anything it is an overall benefit
|
||||||
|
// as there are no unscheduled long duration frames.
|
||||||
|
//
|
||||||
|
// The implementation appears to work fine without waiting for completion at the start of the frame - so
|
||||||
|
// this wait at the start can be disabled by setting the property /sim/nasal-gc-threaded-wait to false.
|
||||||
|
|
||||||
|
// first we see if the config has changed. The notification will return true from SetActive/SetWait when the
|
||||||
|
// value has been changed - and thus we notify the Nasal system that it should configure itself accordingly.
|
||||||
|
auto use_threaded_gc = nasal_gc_threaded->getBoolValue();
|
||||||
|
auto threaded_wait = nasal_gc_threaded_wait->getBoolValue();
|
||||||
|
bool notify_gc_config = false;
|
||||||
|
notify_gc_config = ngccn->SetActive(use_threaded_gc);
|
||||||
|
notify_gc_config |= ngccn->SetWait(threaded_wait);
|
||||||
|
if (notify_gc_config)
|
||||||
|
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(*ngccn);
|
||||||
|
|
||||||
|
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_begin);
|
||||||
|
|
||||||
if (sglog().has_popup()) {
|
if (sglog().has_popup()) {
|
||||||
std::string s = sglog().get_popup();
|
std::string s = sglog().get_popup();
|
||||||
|
@ -126,6 +169,8 @@ static void fgMainLoop( void )
|
||||||
// flush commands waiting in the queue
|
// flush commands waiting in the queue
|
||||||
SGCommandMgr::instance()->executedQueuedCommands();
|
SGCommandMgr::instance()->executedQueuedCommands();
|
||||||
simgear::AtomicChangeListener::fireChangeListeners();
|
simgear::AtomicChangeListener::fireChangeListeners();
|
||||||
|
|
||||||
|
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initTerrasync()
|
static void initTerrasync()
|
||||||
|
@ -240,6 +285,8 @@ static void registerMainLoop()
|
||||||
{
|
{
|
||||||
// stash current frame signal property
|
// stash current frame signal property
|
||||||
frame_signal = fgGetNode("/sim/signals/frame", true);
|
frame_signal = fgGetNode("/sim/signals/frame", true);
|
||||||
|
nasal_gc_threaded = fgGetNode("/sim/nasal-gc-threaded", true);
|
||||||
|
nasal_gc_threaded_wait = fgGetNode("/sim/nasal-gc-threaded-wait", true);
|
||||||
fgRegisterIdleHandler( fgMainLoop );
|
fgRegisterIdleHandler( fgMainLoop );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,6 +423,10 @@ static void fgIdleFunction ( void ) {
|
||||||
// run the main loop.
|
// run the main loop.
|
||||||
fgSetBool("sim/sceneryloaded", false);
|
fgSetBool("sim/sceneryloaded", false);
|
||||||
registerMainLoop();
|
registerMainLoop();
|
||||||
|
|
||||||
|
ngccn = new simgear::Notifications::NasalGarbageCollectionConfigurationNotification(nasal_gc_threaded->getBoolValue(), nasal_gc_threaded_wait->getBoolValue());
|
||||||
|
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(*ngccn);
|
||||||
|
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_started);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( idle_state == 2000 ) {
|
if ( idle_state == 2000 ) {
|
||||||
|
@ -546,8 +597,8 @@ int fgMainInit( int argc, char **argv )
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
|
flightgear::initApp(argc, argv);
|
||||||
if (showLauncher) {
|
if (showLauncher) {
|
||||||
flightgear::initApp(argc, argv);
|
|
||||||
flightgear::checkKeyboardModifiersForSettingFGRoot();
|
flightgear::checkKeyboardModifiersForSettingFGRoot();
|
||||||
|
|
||||||
if (!flightgear::runLauncherDialog()) {
|
if (!flightgear::runLauncherDialog()) {
|
||||||
|
@ -627,6 +678,8 @@ int fgMainInit( int argc, char **argv )
|
||||||
frame_signal.clear();
|
frame_signal.clear();
|
||||||
fgOSCloseWindow();
|
fgOSCloseWindow();
|
||||||
|
|
||||||
|
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_stopped);
|
||||||
|
|
||||||
simgear::clearEffectCache();
|
simgear::clearEffectCache();
|
||||||
|
|
||||||
// clean up here; ensure we null globals to avoid
|
// clean up here; ensure we null globals to avoid
|
||||||
|
|
Loading…
Reference in a new issue