Board index FlightGear Development Nasal

How to bypass Nasal Garbage collector, a howto.

Nasal is the scripting language of FlightGear.

How to bypass Nasal Garbage collector, a howto.

Postby Necolatis » Sat Mar 18, 2017 5:59 am

There has been lot of talk over the years about the slow Nasal Garbage collector.

I am not sure if this is well known, but I found out a way to bypass it, that at least for fast loops works very well.

The solution is very simple; don't initialize ANY variables in loops.

Look at this code:

Code: Select all
var loop = func {
 var a = 4;
 var b = 64;
 var c = a+b;
 settimer(loop, 0);
}


Imagine it was 50 variables instead of just 3. That gives a performance hit with garbage collecting.

Code: Select all
var a = nil;
var b = nil;
var c = nil;
var loop = func {
 a = 4;
 b = 64;
 c = a+b;
 settimer(loop, 0);
}


And that's how to avoid the garbage collector, just keep em in memory.
Ofc. the code is ugly and could have been a class instead of just a method, but I hope the idea comes across.

I have been working on a very large nasal file with many lines of code, most of it methods running in a very fast loop, probably 50-150 variables initialized every frame in all the called methods combined. And the performance improvement I saw from using this principle, was significant.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore


Hangar: https://sites.google.com/site/fghangar/
User avatar
Necolatis
 
Posts: 1907
Joined: Mon Oct 29, 2012 12:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2018.3.2
OS: Windows 10

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sat Mar 18, 2017 6:58 am

We previously covered that (and I think it's also mentioned in the wiki), it's a common optimization technique - especially in languages that don't use any/much code optimization (constant folding, loop unrolling etc) - for other -more specific- advice, search the forum for ways that may help reduce "GC pressure"
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby Necolatis » Sat Mar 18, 2017 7:05 am

Oh, sorry. I will try to find those pages.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore


Hangar: https://sites.google.com/site/fghangar/
User avatar
Necolatis
 
Posts: 1907
Joined: Mon Oct 29, 2012 12:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2018.3.2
OS: Windows 10

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sat Mar 18, 2017 7:20 am

No need to apologize - great that you figured this out on your own, but maybe also unfortunate that the wiki does not seem to cover this prominently enough - so maybe we should really come up with a GC/Nasal howto - and use your posting as a template ?

Speaking in general: avoiding any redundant/unnecessary work in loops (repeated code) pays off - no matter if that means re-allocating data structures/variables or doing unnecessary computations - i.e. keep those out of the loop body.

A modern compiler will automatically recognize such code and optimize it accordingly, Nasal's code generator will not - it's dead simple and usually does what you tell it to do, no matter how dumb that may be.

By the way, to really understand the Nasal GC, I suggest to check out these:

https://github.com/andyross/nasal/blob/ ... gcperf.nas
http://wiki.flightgear.org/How_the_Nasal_GC_works


PS: You probably want to start using maketimer() instead pf settimer()
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sun Sep 03, 2017 2:46 pm

I have been working on a very large nasal file with many lines of code, most of it methods running in a very fast loop, probably 50-150 variables initialized every frame in all the called methods combined. And the performance improvement I saw from using this principle, was significant.


you mentioned already that the same method should work for a Nasal class (hash) with a properly set up parents vector - have you done any measurements to see how this compares to the approach you posted here ?
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby Octal450 » Sun Sep 03, 2017 2:54 pm

I've been using this exact technique on my A320Family and upcoming MD-11Family for months. It has increased frames a ton!

Kind Regards,
Josh
Octal450

FGFS Aircraft Developer
Lead Developer at Immersive Design Group (Join our Discord!)
Download High Quality Aircraft from Octal450 Hangar
Dream no small dream; it lacks magic. Dream large. Then make the dream real. - Donald Douglas
User avatar
Octal450
 
Posts: 4095
Joined: Tue Oct 06, 2015 12:51 pm
Location: A far corner of my room
Callsign: WTF450/Octal
Version: 2018.3.2
OS: Windows 10 x64

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sun Sep 03, 2017 3:15 pm

Yeah, sure - but the real issue a different one, a structural one, because it is next to impossible to reuse that kind of code in a sane fashion, which already is a long-standing challenge most aircraft-side Nasal code is facing, and which is contributing to other problems.
I do understand why and how this affects the "GC pressure" - I actually once documented the Nasal GC: http://wiki.flightgear.org/How_the_Nasal_GC_works
However, I also once helped port Gijs' original ND code, and it didn't support multiple independent instances and was highly aircraft specific, that's the kind of thing we generally want to avoid.

For the technical background, refer to the article that I added to the wiki after rewriting Gijs' code accordingly: http://wiki.flightgear.org/Howto:Coding ... #Variables

Just to be very clear about it: the only reason why so many aircraft can use Gijs' NavDisplay (ND) is the fact that it is NOT using that approach anymore.
Thus, I would suggest to tread very carefully here. Necolatis seems to have a coding background, so he surely understands the repercussions of using this approach - but most people will not realize that they are sacrificing reusability by using variables like that - unless they're willing to use hashes or vectors to put their instance-specific state there.

Thus, before pursuing this, please do make sure that you understand the repercussions - for example, here's a wiki article that I put together after looking at some aircraft code a while ago: http://wiki.flightgear.org/Howto:Start_ ... s_in_Nasal

And it basically looked like this:
Code: Select all
var wp1 = 0;
var wp1alt = 0;
var wp1dist = 0;
var wp1angle = 0;
var wp1length = 0;
var wp1id = "";
var wp1brg = 0;

var wp2 = 0;
var wp2alt = 0;
var wp2dist = 0;
var wp2angle = 0;
var wp2length = 0;
var wp2id = "";
var wp2brg = 0;

var wp3 = 0;
var wp3alt = 0;
var wp3dist = 0;
var wp3angle = 0;
var wp3length = 0;
var wp3id = "";
var wp3brg = 0;

var wp4 = 0;
var wp4alt = 0;
var wp4dist = 0;
var wp4angle = 0;
var wp4length = 0;
var wp4id = "";
var wp4brg = 0;
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby Necolatis » Sun Sep 03, 2017 3:33 pm

It was just an example, its not how I code (most of the time). I use hashes.

I just thought a simple example like that would make the point come across clearer, and not appear too convoluted to read for those that do not program in hashes.

Here the example is in a hash method. (being called from a maketimer so loop call omited)

Code: Select all
loop: func {
 me.a = 4;
 me.b = 64;
 me.c = me.a+me.b;
},


Same principle, variables are global to the hash, instead of global to the namespace.
"Airplane travel is nature's way of making you look like your passport photo."
— Al Gore


Hangar: https://sites.google.com/site/fghangar/
User avatar
Necolatis
 
Posts: 1907
Joined: Mon Oct 29, 2012 12:40 am
Location: EKOD
Callsign: Leto
IRC name: Neco
Version: 2018.3.2
OS: Windows 10

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sun Sep 03, 2017 3:38 pm

If people don't feel comfortable using OOP/hashes in Nasal, they could instead continue to use functions but wrapped in closures - that way, everything would remain "as is", but therre would still be a way to have instance-specific state:


Code: Select all

var makePosition = func(lat, lon, alt) {

return func() {
print("altitude: ", alt);
}


};

var p = makePosition(1,2,3) ();

Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby legoboyvdlp » Sun Dec 03, 2017 1:26 pm

Sorry for bringing this up again, but I'd be interested to know more about loop optimization and constant folding, mentioned above by Hooray. How can I implement this in Nasal?
User avatar
legoboyvdlp
 
Posts: 6652
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sun Dec 03, 2017 1:44 pm

basically, do the least amount of work possible in your loop bodies. For that, you should identify everything that is likely to remain "constant", and move such stuff out of the actual loop body. That also applies to unnecessaryr re-allocations of data structures/variables.

However, to be honest, if you are hitting an actual bottleneck, it makes more sense to look at what exactly the problem is - loop optimizations are rather low-level and won't do any magic, it is much more likely that algorithmic improvements will pay off better.

To see what is exactly going on, use debug.benchmark() in your code for the various "workhorse" functions. That will tell you where your code is spending its execution time (in Nasal space).

To see what is going in between C and Nasal, it would make sense to use the "built-in profiler" (refer to the wiki for details) or use an actual external profiler (gprof will do for starters, but oprofile is much better)

But again, the key is doing the least amount of work in your Nasal code, and trying to stay in C space whenever possible, and especially loops are places where inefficient code may add up quickly - doing something dumb "once per frame" is obviously not a problem, but executing a loop with 500 iterations, may quickly show up.

And that doesn't just apply to conventional loops, but also "loops" in the form of callbacks invoked via timers or listeners.

The "constant folding/loop optimization" stuff is really only useful if you already know that everything else is well-optimized. Otherwise, I would not even look at it.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby legoboyvdlp » Sun Dec 03, 2017 3:05 pm

OK, many thanks :)
Jonathan
User avatar
legoboyvdlp
 
Posts: 6652
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sun Dec 03, 2017 4:13 pm

What's usual helpful in such situations is being able to post a down-stripped version of your code here so that people can try and run it to see for themselves - most of the topics where people can post such code, i.e. code that can be executed via the Nasal code, tend to get pretty good responses quickly.

Thus, if you can structure your code accordingly, that will be helpful in and of itself - even if you aren't planning on doing any optimizations yourself.
You will also notice that the same kind of structure is helpful when even just using the debug.benchmark() and profiling APIs
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am

Re: How to bypass Nasal Garbage collector, a howto.

Postby legoboyvdlp » Sun Dec 03, 2017 6:14 pm

I'm not sure I understand you... you mean code that can run when put through the Nasal Console in-sim, so standalone code that doesn't require any other files?
User avatar
legoboyvdlp
 
Posts: 6652
Joined: Sat Jul 26, 2014 1:28 am
Callsign: YV-LEGO
Version: 2018.3.1
OS: Windows 10 HP

Re: How to bypass Nasal Garbage collector, a howto.

Postby Hooray » Sun Dec 03, 2017 6:37 pm

Yeah, which is to say that a self-contained piece of code can be more easily tested, so that people can more easily reproduce a problem, or help with doing troubleshooting/benchmarking or actually profiling and optimizing such code.

Requiring people to download/install files (let alone, aircraft or scenery) is not exactly a low barrier to entry. As a matter of fact, most of the people who could help with such matters on the forum/devel list are usually those not even "using" FlightGear in the conventional sense, but primarily developing stuff, i.e. power users or core developers - and here, asking someone to reproduce a problem by downloading/installing a certain aircraft or scenery chunk adds to the workload unnecessarily, as would having to actually fly a certain aircraft for a while to see a certain issue (running out of memory, segfaults/crashes or other obscure problems).

Thus, if you can, it is usually a good idea to come up with a piece of code that exhibits the same problem, but that is sufficiently self-contained to be shared via the forum/wiki or devel list (pastebin), so that other contributors can more easily see if they can repro a certain problem or not.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11313
Joined: Tue Mar 25, 2008 8:40 am


Return to Nasal

Who is online

Users browsing this forum: No registered users and 0 guests