Howto:Disable Nasal entirely

From FlightGear wiki
Revision as of 17:18, 23 February 2016 by Hooray (talk | contribs) (→‎Patch: FGNasalSys null pointer check for NasalModelData)
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.
disable Nasal scripting
Started in 03/2014
Description provide an optional FlightGear startup mode to disable Nasal scripting entirely for regression testing purpososes
Contributor(s) Hooray
Status proof-of-concept (working patch)

Motivation

Nasal, and particularly its garbage collector (GC), is known for having a certain impact on the frame rate, and frame spacing - however, there are performance issues other than Nasal code, and Nasal related issues may contribute to masking such issues - so far, it's been impossible to easily disable Nasal entirely - the following patch makes it possible to disable Nasal completely, so that it can be eliminated from the equation altogether. This startup mode will obviously only be of interest to developers and power-users, i.e. those interested in doing regression testing, and understanding FlightGear issues (resource leaks, performance issues etc).

Cquote1.png Instead of adding just-another-feature we need to strip it down to getting a fast and constand fps rendering engine. Everything else needs to run outside the main loop and has to interact with the core by, say HLA/RTI or whatever IPC we have.
Cquote2.png
Cquote1.png I'd just recommend to not do it but to focus on detangling the subsystems and creating a distributes simulation instead. That's my vision.
Cquote2.png

Objective

disable Nasal scripting

Background

  • Nasal performance
  • garbage collection overhead
  • impact on frame rate and frame spacing
Cquote1.png I should still have an old topic branch that disabled FGNasalSys entirely - i.e. the fg_init.cxx, but also the roughly ~10 places where a handle (pointer) to the FGNasalSys instance in the SGSubsysmMgr is acquired to run some Nasal code on demand (think GUI, joystick, keyboard, AI/scenery stuff).

In and of itself, that will obviously not be particularly useful, because fgfs is rather "crippled" with so much of its (current) UI/aircraft functionality tied to Nasal code all over the place, but it may still be interesting for the FGPythonSys effort, because it provides a good baseline for fgfs performance without _any_ Nasal code running at all, including obviously GC issues - even if only to illustrate (and prove) that FlightGear is still suffering from resource leaks and race conditions that have nothing to do with Nasal.

In other words, this is something where FGPythonSys and FGNasalSys could benefit eachother in the near term, while providing benefits for FG in the long term.
Cquote2.png
Cquote1.png that could be quite useful for experimentation purposes, unit testing, and maybe coming up with a FGScriptingSys base class.
Cquote2.png

Status

Cquote1.png in its current form it cannot be committed "as is", because it does not deal with scenery/tile related Nasal hooks, i.e. those using NasalModelData* - which is primarily the scenery/tile manager code, AIBase and the CanvasMgr stuff.

Those are the locations that would need to also use a FGNasalSys NULL pointer check and skip the execution of the corresponding portions of the code. I never ran into this because I used the minimal startup profile (as per the wiki) to do the corresponding troubleshooting, with AI and scenery/terrain stuff also disabled entirely.

Like I said, it wasn't really intended to be used "as is" - you definitely need to know what you're doing. Apart from that, someone using this "mode" would obviously also understand where a FGNasalSys related segfaults come from with Nasal disabled
Cquote2.png

News / Updates

Changelog

Gallery

Roadmap

Template:Roadmap

Related

fgfs.log

view:3:$FG_SRC/Viewer/splash.cxx:445:Splash screen progress finishing-subsystems
nasal:5:$FG_SRC/Main/fg_init.cxx:912:Nasal support disabled:Initialization
general:3:$FG_SRC/Time/TimeManager.cxx:411:After TimeManager::setTimeOffset(): warp = 0
nasal:5:$FG_SRC/Network/HTTPClient.cxx:331:Nasal support disabled:package manager
instruments:3:$FG_SRC/Instrumentation/gps.cxx:377:GPS saw route-manager flight-plan replaced.
autopilot:3:$FG_SRC/Autopilot/route_mgr.cxx:780:route manager, current-wp is now -1
nasal:5:$FG_SRC/Input/FGKeyboardInput.cxx:118:Nasal support disabled:Keyboard bindings
ai:3:$FG_SRC/AIModel/AIManager.cxx:167:loading scenario 'nimitz_demo'
general:3:$FG_SRC/Main/fg_init.cxx:916:Subsystems postinit took:48
general:3:$FG_SRC/Main/fg_init.cxx:925:

Patch

Note  The following patch only works during startup/initialization, i.e. set the boolean property

/sim/startup/disable-nasal via something like --prop:/sim/startup/disable-nasal=1 and the initialization of the Nasal susbystem (FGNasalSys) will be disabled, as well as all calls to the system from other subsystems (GUI, Canvas, bindings, package manager etc)


diff --git a/src/AIModel/AIManager.cxx b/src/AIModel/AIManager.cxx
index 4faf23e..e09db60 100644
--- a/src/AIModel/AIManager.cxx
+++ b/src/AIModel/AIManager.cxx
@@ -72,6 +72,10 @@ public:
         std::string loadScript = nasalScripts->getStringValue("load");
         if (!loadScript.empty()) {
             FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+	    if(!nasalSys) { 
+		NASAL_DISABLED("AI scenarios");
+		return;
+	    }
             std::string moduleName = "scenario_" + _internalName;
             nasalSys->createModule(moduleName.c_str(), moduleName.c_str(),
                                    loadScript.c_str(), loadScript.size(),
@@ -86,8 +90,10 @@ public:
         }
         
         FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
-        if (!nasalSys)
-            return;
+        if(!nasalSys) { 
+		NASAL_DISABLED("AI scenarios");
+		return;
+	    }
         
         std::string moduleName = "scenario_" + _internalName;
         if (!_unloadScript.empty()) {
diff --git a/src/GUI/CanvasWidget.cxx b/src/GUI/CanvasWidget.cxx
index f68fe22..52ed2f4 100644
--- a/src/GUI/CanvasWidget.cxx
+++ b/src/GUI/CanvasWidget.cxx
@@ -72,10 +72,13 @@ CanvasWidget::CanvasWidget( int x, int y,
     return;
 
   FGNasalSys *nas = dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
-  if( !nas )
+  if( !nas ) {
     SG_LOG( SG_GENERAL,
             SG_ALERT,
             "CanvasWidget: Failed to get nasal subsystem!" );
+  NASAL_DISABLED("PUI CanvasWidget");
+  return;
+  }
 
   const std::string file = std::string("__canvas:")
                          + cprops->getStringValue("name");
diff --git a/src/GUI/FGPUIDialog.cxx b/src/GUI/FGPUIDialog.cxx
index 30cbef7..f66f40e 100644
--- a/src/GUI/FGPUIDialog.cxx
+++ b/src/GUI/FGPUIDialog.cxx
@@ -672,7 +672,9 @@ FGPUIDialog::FGPUIDialog (SGPropertyNode *props) :
             FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
             if (nas)
                 nas->createModule(_module.c_str(), _module.c_str(), s, strlen(s), props);
+	    else NASAL_DISABLED("Nasal embedded in PUI dialogs");	
         }
+		
     }
     display(props);
 }
@@ -1056,7 +1058,11 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
           }
         } else {
           FGNasalSys* nasal = (FGNasalSys*) globals->get_subsystem("nasal");
+	  if(nasal) 	  
           obj->setBuffer(nasal->log());
+	  else {
+	  NASAL_DISABLED("PUI");
+	  }
         }
 
         setupObject(obj, props);
diff --git a/src/GUI/FileDialog.cxx b/src/GUI/FileDialog.cxx
index 2047898..d71d910 100644
--- a/src/GUI/FileDialog.cxx
+++ b/src/GUI/FileDialog.cxx
@@ -100,6 +100,10 @@ public:
         object(obj)
     {
         FGNasalSys* sys = static_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+        if(!sys) {
+	NASAL_DISABLED("FileDialog");
+	 return;
+	}
         _gcKeys[0] = sys->gcSave(f);
         _gcKeys[1] = sys->gcSave(obj);
     }
@@ -107,7 +111,10 @@ public:
     virtual void onFileDialogDone(FGFileDialog* instance, const SGPath& aPath)
     {
         FGNasalSys* sys = static_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
-        
+        if(!sys) {
+	NASAL_DISABLED("FileDialog (done)");
+	return;
+	} 
         naContext ctx = naNewContext();
         naRef args[1];
         args[0] = nasal::to_nasal(ctx, aPath);
@@ -119,6 +126,10 @@ public:
     ~NasalCallback()
     {
         FGNasalSys* sys = static_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+	if(!sys) {
+	NASAL_DISABLED("FileDialog");
+	return;
+	}
         sys->gcRelease(_gcKeys[0]);
         sys->gcRelease(_gcKeys[1]);
     }
diff --git a/src/Input/FGEventInput.cxx b/src/Input/FGEventInput.cxx
index 29bdc6e..7bbab09 100644
--- a/src/Input/FGEventInput.cxx
+++ b/src/Input/FGEventInput.cxx
@@ -236,6 +236,7 @@ FGInputDevice::~FGInputDevice()
     }
     nas->deleteModule(nasalModule.c_str());
   }
+  else NASAL_DISABLED("FGInputDevice");
 } 
 
 void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
@@ -264,7 +265,7 @@ void FGInputDevice::Configure( SGPropertyNode_ptr aDeviceNode )
       FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal");
       if (nas)
         nas->createModule(nasalModule.c_str(), nasalModule.c_str(), s.c_str(), s.length(), deviceNode );
-    }
+    } else NASAL_DISABLED("FGInputDevice::Configure");
   }
 
 }
diff --git a/src/Input/FGJoystickInput.cxx b/src/Input/FGJoystickInput.cxx
index 069e9d8..d6d3fd8 100644
--- a/src/Input/FGJoystickInput.cxx
+++ b/src/Input/FGJoystickInput.cxx
@@ -208,14 +208,16 @@ void FGJoystickInput::postinit()
     std::ostringstream str;
     str << "__js" << i;
     std::string module = str.str();
+    unsigned int j;
+    if (nasalsys) {
     nasalsys->createModule(module.c_str(), module.c_str(), "", 0);
 
     PropertyList nasal = js_node->getChildren("nasal");
-    unsigned int j;
     for (j = 0; j < nasal.size(); j++) {
       nasal[j]->setStringValue("module", module.c_str());
       nasalsys->handleCommand(nasal[j]);
     }
+    } else NASAL_DISABLED("Joystick bindings");
 
     //
     // Initialize the axes.
diff --git a/src/Input/FGKeyboardInput.cxx b/src/Input/FGKeyboardInput.cxx
index 8ff3d0a..004547e 100644
--- a/src/Input/FGKeyboardInput.cxx
+++ b/src/Input/FGKeyboardInput.cxx
@@ -109,11 +109,13 @@ void FGKeyboardInput::postinit()
   }
 
   FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
+  if(nasalsys) {
   PropertyList nasal = key_nodes->getChildren("nasal");
   for (unsigned int j = 0; j < nasal.size(); j++) {
     nasal[j]->setStringValue("module", module.c_str());
     nasalsys->handleCommand(nasal[j]);
   }
+} else NASAL_DISABLED("Keyboard bindings");
 
   PropertyList keys = key_nodes->getChildren("key");
   for (unsigned int i = 0; i < keys.size(); i++) {
diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx
index 1e93a0b..e07d4b9 100644
--- a/src/Main/fg_commands.cxx
+++ b/src/Main/fg_commands.cxx
@@ -185,7 +185,13 @@ do_null (const SGPropertyNode * arg)
 static bool
 do_nasal (const SGPropertyNode * arg)
 {
-    return ((FGNasalSys*)globals->get_subsystem("nasal"))->handleCommand(arg);
+    FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+    if(!nasalSys) {
+	NASAL_DISABLED("fgcomand nasal (bindings)");
+	return false;
+    }
+    return nasalSys->handleCommand(arg);
+    
 }
 
 /**
diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx
index 61d3425..d8bd11a 100644
--- a/src/Main/fg_init.cxx
+++ b/src/Main/fg_init.cxx
@@ -904,11 +904,12 @@ void fgPostInitSubsystems()
     // Initialize the Nasal interpreter.
     // Do this last, so that the loaded scripts see initialized state
     ////////////////////////////////////////////////////////////////////////
+if(!fgGetBool("/sim/startup/disable-nasal",false)) {
     FGNasalSys* nasal = new FGNasalSys();
     globals->add_subsystem("nasal", nasal, SGSubsystemMgr::INIT);
     nasal->init();
     SG_LOG(SG_GENERAL, SG_INFO, "Nasal init took:" << st.elapsedMSec());
-
+}   else NASAL_DISABLED("Initialization");
     // initialize methods that depend on other subsystems.
     st.stamp();
     globals->get_subsystem_mgr()->postinit();
diff --git a/src/Network/ATC-Main.cxx b/src/Network/ATC-Main.cxx
index 6c0da9b..00cd91a 100644
--- a/src/Network/ATC-Main.cxx
+++ b/src/Network/ATC-Main.cxx
@@ -223,10 +223,12 @@ bool FGATCMain::process() {
     // directly provide.
 
     FGNasalSys *n = (FGNasalSys*)globals->get_subsystem("nasal");
+    if(n) {
     bool result = n->parseAndRun( "atcsim.update()" );
     if ( !result ) {
         SG_LOG( SG_NETWORK, SG_ALERT, "Nasal: atcsim.update() failed!" );
     }
+    } else NASAL_DISABLED("ATC-Main");
 
     // process the ATC outputs
     if ( output0 != NULL && board0_locked ) {
diff --git a/src/Network/HTTPClient.cxx b/src/Network/HTTPClient.cxx
index e6d2b29..48376ab 100644
--- a/src/Network/HTTPClient.cxx
+++ b/src/Network/HTTPClient.cxx
@@ -327,6 +327,10 @@ void FGHTTPClient::postinit()
   pkg::Root* packageRoot = globals->packageRoot();
   if (packageRoot) {
     FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
+    if(!nasalSys) {
+	NASAL_DISABLED("package manager");
+	return;
+	}
     nasal::Hash nasalGlobals = nasalSys->getGlobals();
     nasal::Hash nasalPkg = nasalGlobals.createHash("pkg"); // module
     nasalPkg.set("root", packageRoot);
diff --git a/src/Scripting/NasalModelData.cxx b/src/Scripting/NasalModelData.cxx
index e4f2269..930790d 100644
--- a/src/Scripting/NasalModelData.cxx
+++ b/src/Scripting/NasalModelData.cxx
@@ -118,6 +118,11 @@ void FGNasalModelData::load()
   const char *s = _load ? _load->getStringValue() : "";
   FGNasalSys* nasalSys = (FGNasalSys*) globals->get_subsystem("nasal");
 
+  if(!nasalSys) {
+	NASAL_DISABLED("NasalModelData");
+	return;
+  }
+
   // Add _module_id to script local hash to allow placing canvasses on objects
   // inside the model.
   nasal::Hash module = nasalSys->getGlobals().createHash(_module);
diff --git a/src/Scripting/NasalPositioned.cxx b/src/Scripting/NasalPositioned.cxx
index 55c79a2..cf45960 100644
--- a/src/Scripting/NasalPositioned.cxx
+++ b/src/Scripting/NasalPositioned.cxx
@@ -1831,6 +1831,10 @@ public:
   NasalFPDelegateFactory(naRef code)
   {
     _nasal = (FGNasalSys*) globals->get_subsystem("nasal");
+    if(!_nasal) {
+	NASAL_DISABLED("Nasal flightplan delegates");
+	return;
+	}
     _func = code;
     _gcSaveKey = _nasal->gcSave(_func);
   }
diff --git a/src/Scripting/NasalSys.hxx b/src/Scripting/NasalSys.hxx
index 096a591..af01ff2 100644
--- a/src/Scripting/NasalSys.hxx
+++ b/src/Scripting/NasalSys.hxx
@@ -30,11 +30,14 @@ namespace simgear { class BufferedLogCallback; }
 
 SGPropertyNode* ghostToPropNode(naRef ref);
 
+#define NASAL_DISABLED(feature) SG_LOG(SG_NASAL, SG_ALERT, "Nasal support disabled:" << feature)
+
 class FGNasalSys : public SGSubsystem
 {
 public:
     FGNasalSys();
     virtual ~FGNasalSys();
+
     virtual void init();
     virtual void shutdown();