Howto:Troubleshooting Nasal Callbacks: Difference between revisions
Jump to navigation
Jump to search
Line 32: | Line 32: | ||
| date = Aug 29th, 2014 | | date = Aug 29th, 2014 | ||
| added = Aug 29th, 2014 | | added = Aug 29th, 2014 | ||
| script_version = 0.23 | |||
}} | |||
}} | |||
{{FGCquote | |||
|1= We've (hopefully successfully!) reduced the number of property listeners generated by the Effects system massively - there should now be only one per property. I'm hopeful that this may provide a performance boost for CPU-limited systems, as well as removing one crash source. | |||
|2= {{cite web | |||
| url = http://sourceforge.net/p/flightgear/mailman/message/32875050/ | |||
| title = <nowiki>Re: [Flightgear-devel] crash in SGPropertyNode::fireValueChanged</nowiki> | |||
| author = <nowiki>Stuart Buchanan</nowiki> | |||
| date = Sep 27th, 2014 | |||
| added = Sep 27th, 2014 | |||
| script_version = 0.23 | | script_version = 0.23 | ||
}} | }} |
Revision as of 20:47, 31 January 2016
Background
At EDXH, the Effect system attaches approx. 1500 Listeners to the property tree but only to 17 unique properties At KSFO, the Effect system attaches some 10000 Listeners to the property tree - but also only to 17 unique properties. That's with shader quality set toero (all off). — Torsten Dreyer (Sep 4th, 2014). Re: [Flightgear-devel] crash in SGPropertyNode::fireValueChanged.
(powered by Instant-Cquotes) |
On my old Laptop, (1.6GH dual core, GeForce Go 7400, 3Gb RAM) FlightGear has becom barely usable over the last few years. Framerates of max 20 at EDXH and single digits at KSFO. — Torsten Dreyer (Sep 4th, 2014). Re: [Flightgear-devel] crash in SGPropertyNode::fireValueChanged.
(powered by Instant-Cquotes) |
Without the patch, thousands of listeners were triggered each frame — Torsten Dreyer (Aug 29th, 2014). Re: [Flightgear-devel] crash in SGPropertyNode::fireValueChanged.
(powered by Instant-Cquotes) |
We've (hopefully successfully!) reduced the number of property listeners generated by the Effects system massively - there should now be only one per property. I'm hopeful that this may provide a performance boost for CPU-limited systems, as well as removing one crash source. — Stuart Buchanan (Sep 27th, 2014). Re: [Flightgear-devel] crash in SGPropertyNode::fireValueChanged.
(powered by Instant-Cquotes) |
usually, "events" means Nasal callbacks (timers) - however, it's also often not just Nasal per se, but misuse of timers - in general, settimer() is a API that is prone to being used improperly, because it needs to be consciously used, i.e. to enable/disable loops and to prevent them from being "registered" (invoked) too often - which is the most common pattern of misuse we've seen so far: Nasal based callbacks that end up being invoked doens (or even hundreds) of times despite being only intended to be invoked once per interval.
However, to be fair, this is not specific to Nasal - A few months ago, Torsten fixed pretty much the exact same bug in the C++ effects code which was registering thousands of identical callbacks. The underlying problem here is that the SGPropertyNode code does not currently support any form of troubleshooting, i.e. to do callback tracking - for details, refer to: Towards better troubleshooting The maketimer() API can be used to help prevent such issues when using timers, but listeners are a completely different matter (if in doubt, please file a feature request) |
Objective
Implementation
We will be wrapping/overriding the problematic APIs at the global level to provide functions that internally support callback/registration tracking, and which can automatically detect improper use of these APIs:
var ObjectIdentity = func(obj) {
return id(obj);
};
# TODO: need to use call/compile to track call location
var TrackableResource = {
new: func() {
var m={parents:[TrackableResource]};
m.objects=[];
return m;
},
del: func() {
},
};
var TrackableAPI = {
new: func(api) {
var m = { parents:[TrackableAPI] };
m.collection = {};
return m;
},
del: func() {},
getCallback: func() {return me.invoke},
invoke: func (callback, interval) {
var key=id(callback);
if (me.collection[key]!=nil)
print("Warning, key/callback already in collection: ");
},
};
var setlistener = TrackableAPI.new(api: setlistener).getCallback();
# removelistener
var settimer = TrackableAPI.new(api: settimer).getCallback();
var test = func() {
## improper use of APIs:
var foo = func;
for (var i=0;i<=5;i++) {
# 5 listeners registered for the same property/callback:
setlistener("/sim/foo", foo);
# invoke foo again after 5 seconds
settimer(foo, 5);
} # for loop
}; # of test
Integration
The corresponding APIs should be either loaded globally via $FG_ROOT/Nasal or explicitly loaded via the -set.xml file: