Hi,

here's a "few" more comments/hints/warnings on Nasal and simulation
performance in general.

First of all: it's not meant _against_ anybody. It's great to have a
tiny scripting engine in FG. It's great to have an option for custom
extensions. And we're certainly seeing very nice examples (absolutely
including ThorstenIR's local weather, since he brought that up).

I'm just making a point here that the Nasal engine does have
performance issues, which we should be aware of and care about.

When evaluating simulation performance, don't get fooled by the frame
rate. What's really important to us is the "worst case frame latency".
Even if the system is producing a huge average of 100 frames per
second, it can still look absolutely crappy, if only a single frame
took more than 20-30ms, since that's immediately visible to the human
eye (note to self: add a "worst case latency" indicator). So, we're
building a real-time system here, and 20-30ms is our timing
constraint.

Nasal needs to run a garbage collection every now and then. This means
an extra delay, and may become noticeable, if it causes a frame to
violate the timing constraint. _When_ and _where_ in the Nasal code
the g/c triggers, is almost random, so you cannot attribute the g/c
delay to the point where it happened.

The effect depends on two properties: (1) how long does it take, and
(2) how often does it happen. These issues are triggered by different
properties of the code. If we can keep the delay below the limit,
everything is perfect. If we cannot, than we should at least reduce
its frequency. One stutter per minute may be acceptable. Once every
second looks absolutely intolerable (though you may still get a funky
100fps indication!).

1. The length of the delay depends on the number of references the
garbage collector needs to traverse: variables (data), but also
functions, which are just like variables in Nasal, e.g.
  var myVariable = 42;
  var myFunction = func()...
It doesn't depend on the size of a particular function or basic
variable though. The garbage collector needs to look and follow every
single reference to find out what's still in use. The delay is
proportional to the number of elements which were
loaded/initialized/created in Nasal. It hardly depends on the
length/complexity/frequency of Nasal computation though, since the
average number of references usually won't change too much.

I have instrumented the Nasal g/c to show the number of references
caused by generic Nasal scripts and by different aircraft (subtracting
the references caused by generic scripts) with current GIT:

39128   all generic stuff (i.e. fgdata/Nasal...)
 3475   UFO
 4788   c172p
 6007   SenecaII
 8283   B777-200ER
19270   F14
86122   Concorde

So, for most aircraft, the a/c specific Nasal is negligible. Time
consumed by garbage collection almost depends on generic stuff alone
(40K of references traversed in each run). Only some complex aircraft
significantly influence the g/c performance themselves, e.g. the
Concorde. It's ok if advanced models require advanced CPUs. But it's
not so nice with generic stuff, since it affects everyone and every
aircraft.
Currently, we load all fgdata/Nasal/*.nas at startup. Whether the code
is ever used or not, or a particular feature is disabled, doesn't
matter much. It's loaded and initialized, increases the number of
references, thus delays the g/c.
For the test above, I had _disabled_ multiplayer/wildfire/target
tracking/local weather/redout. The numbers hardly change when enabling
features though.

Since the local weather topic was mentioned: yes, it's large, but only
responsible for about 11K of references, so about 1/4 of current
generic Nasal stuff (when disabled).

2) The g/c frequency mainly depends on how much stuff is done in
Nasal, including the number of timers and the timer frequencies. So,
in contrast to (1), this very much depends on enabled features, and
strongly on specific aircraft (see Robert's email on frequency).
I also added instrumentation here to see how our generic stuff is
doing. There's several timers which run at full frame rate, even when
the related feature is disabled:

fgdata/Nasal/mp_broadcast.nas:146
fgdata/Nasal/redout.nas:93
fgdata/Nasal/wildfire.nas:506
fgdata/Nasal/track_target.nas:194

Even when they're almost doing nothing, it'd still help if they were
stopped or at least slowed down, when the related feature was
disabled. They affect garbage collection since a lot of (useless)
contexts are created and need to be cleared at some point - hence
triggering the g/c more often than necessary.

Typically many of our Nasal timer handlers look like this:
    myTimer = func() {
      if (getprop("/foo/feature/enabled"))
      {
         ...
      }
      settimer(myTimer, 0.0); // run again in next update loop
    }

This would already improve things (20-100 times fewer contexts being
created/removed):
    myTimer = func() {
      if (getprop("/foo/feature/enabled"))
      {
         ...
         settimer(myTimer, 0.0); // enabled, fast update (once per frame)
      }
      else
      {
         settimer(myTimer, 1.0); // disabled, slow update (once per second)
      }
    }

You could also add a listener to "foo/feature/enabled" to start
related timers only when really necessary. See this fix (for
track_target.nas):
https://www.gitorious.org/fg/fgdata/commit/d8249ef54a96c7c71bfbf187df349bdcbfabe0cb
Apparently "local weather" is another good example here: I saw none of
it running, unless I enabled the feature (well done!).

Apart from timers, authors will know best how to limit/reduce the load
of their scripts. And of course, similar improvements would help
specific aircraft.

Conclusion:
* We want a smooth simulation, not just a high frame rate.
* Nasal is great for small stuff, but it's currently not designed to
hold large amounts of code or data.
* We can ignore the issues (accept jitters or keep buying faster machines).
* We can try to improve the Nasal engine, i.e. accelerate garbage
collection, but it's probably very tricky and not going to happen
(volunteers?).
* We can try to avoid / lessen the issue: implement larger generic
stuff without Nasal (C++, XML animation rules etc), by improving Nasal
scripts itself (see above), or by loading generic Nasal scripts on
demand/when enabled only (so users can choose).

And since something like "don't complain, just do it" was mentioned:
I'm not complaining (my new machine is doing fine for now). I've just
analyzed it and mention the facts. Yes, I think it'd be good to see
some generic things ported over to C++: indeed local weather, but some
multiplayer
stuff too. But no, I'm not going to port it - at least not local
weather (feel like messing with enough modules already :) ).

Over and out, :)
Thorsten

------------------------------------------------------------------------------
Enable your software for Intel(R) Active Management Technology to meet the
growing manageability and security demands of your customers. Businesses
are taking advantage of Intel(R) vPro (TM) technology - will your software 
be a part of the solution? Download the Intel(R) Manageability Checker 
today! http://p.sf.net/sfu/intel-dev2devmar
_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/flightgear-devel

Reply via email to