Board index FlightGear Development Canvas

Performance issues

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Performance issues

Postby Hooray » Wed Sep 19, 2012 10:58 pm

TheTom wrote:Yeah. Looks really great - Exactly what I wanted to do :) Only performance needs to improve. If KSFO is too fast try KNUQ ;)


The taxiways at KSFO/KNUQ also make it obvious that we should really be putting each type of "feature" into different layers/groups - so that we can reuse groups that were not changed - just look at the update delay caused by checking "Display Tower" if taxiways are shown: everything will be updated currently, while it would suffice to merely update just a single group and reused cached vector data otherwise. Same goes for disabling the tower again.
Overall, this is a fairly good test case to change the design slightly and improve the performance of the underlying canvas code.

At the moment, updating the KSFO airport view with taxiways, will switch from 11 to 475 active OpenVG paths in the canvas tree, and because all the features share the same top-level group, the whole group gets updated and redrawn when enabling/disabling other features, even though disabling/enabling a certain group (layer) would be more efficient.

Bottom line being, part of the problem is an algorithmic one because of the way the Nasal code is currently written - a pretty low-hanging fruit obviously, which should be easy to fix by putting each type of feature (runways, taxiways, tower, parking etc) in a separate layer and update it individually, so that groups are not unnecessarily updated and marked "dirty" by the canvas system.
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Using a canvas map in the GUI

Postby Hooray » Thu Sep 20, 2012 10:13 am

It seems, some of the performance issues also come from the sheer amount of properties that are set for airports like KNUQ currently - even without looking at the Nasal code in the airport selection dialog, or the Nasal code in map.nas - just by copying the canvas group to another (non-canvas) tree may take 1-2.5 seconds (note that the copy() helper uses the props.Node wrapper and NOT the raw getprop()/setprop() functions, which are known to be faster meanwhile):

  • Open the airport selection dialog
  • look up KNUQ
  • paste this into your Nasal console, and execute it:
Code: Select all
var src = props.globals.getNode("/canvas/by-index/texture/group/map",1);
var dest = props.globals.getNode("/temp/",1);

dest.removeChildren();

var start = systime();
props.copy(src, dest );
var end = systime();
var delta = end - start;
print(delta);


In other words, it would make sense to optimize the OpenVG drawing mode a little, to reduce the amount of total paths ;-)
Last edited by Hooray on Thu Sep 20, 2012 10:16 am, edited 1 time in total.
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Using a canvas map in the GUI

Postby Hooray » Thu Sep 20, 2012 10:36 am

If it's really the amount of property accesses that contribute to the performance issue, it'd be a classical case where a conventional GUI fires a worker thread to remain responsive until all the background work has been proceseed.

Surprisingly, running props.copy() asynchronously via thread.newthread() doesn't segfault here. Note that it does take slightly longer than running the same operation in the main loop, but at least the GUI remains responsive:

- Open the airport selection dialog
- look up KNUQ
- paste this into your Nasal console, and execute it:
Code: Select all
var src = props.globals.getNode("/canvas/by-index/texture/group/map",1);
var dest = props.Node.new();
var finished = 0;
var delta = 0;

var async_copy = func {
  var start=systime();
  props.copy(src,dest);
  delta = systime()-start;
  finished = 1;
}

thread.newthread( async_copy );

var check_thread = func {
  if (!finished) return settimer(check_thread,0.2);
  print("Async copy took:", delta);
}


check_thread();


This would seem to suggest that, with some changes to the C++ code, we could assemble a canvas tree asynchronously (in the background) and afterwards make it available in the global tree. In that case, it would probably make sense to add a hook to the canvas system to disable its listeners for a certain branch, so that the copy operation doesn't invoke any listeners for any of the added children - and just set a "finished" signal after the copy operation has completed, so that the canvas can "parse" and process the new tree.
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby stuart » Thu Sep 20, 2012 12:28 pm

I expect to be able to fix this by rendering all the taxiways as a single object. Might even get it done this evening.

-Stuart
G-MWLX
User avatar
stuart
Moderator
 
Posts: 1469
Joined: Wed Nov 29, 2006 9:56 am
Location: Edinburgh
Callsign: G-MWLX

Re: Performance issues

Postby zakalawe » Thu Sep 20, 2012 12:59 pm

Copying property trees already has a C++ method, the best solution would be to expose this to Nasal directly. No crazy threading required then :)
zakalawe
 
Posts: 1152
Joined: Sat Jul 19, 2008 4:48 pm
Location: Edinburgh, Scotland
Callsign: G-ZKLW
Version: next
OS: Mac

Re: Performance issues

Postby Hooray » Thu Sep 20, 2012 1:11 pm

zakalawe wrote in Thu Sep 20, 2012 12:59 pm:Copying property trees already has a C++ method, the best solution would be to expose this to Nasal directly. No crazy threading required then :)


I know what you are trying to say - but the point was not that the copy operation is slow: After all, we don't copy the nodes usually. The point was just that there's TONS of data in the property tree in cases like KNUQ (1200+ paths).
And I used props.copy() as a test case to see how long it takes in Nasal space to write so many properties to the tree, because that's exactly what the code is doing to: Setting 1200+ paths in the canvas.
So I wanted to see how long this operation takes in and of itself.

I only mentioned threading because it's a classical solution for the problem: we want the main loop (GUI) to remain responsive, while work is getting done - that's exactly where worker threads are usually used. The work we are doing is writing tons of vector information to the property tree. While props.Node is known to be slower than their setprop/getprop equivalents, it's still LOTS of data that's written there regardless.

I am not disagreeing, having a fast "copy" operation available would be useful - but it would not solve the problem here, which is not just in ShivaVG (i.e. tesselation?), but also the sheer amount of data we are writing to the property tree per frame.

In other places, people usually spread the load across multiple frames using split-frame loops - here, we are trying to do everything at once.

Now, regarding threading: The only thing it could help us with, is staying responsive and offloading the canvas-tree building to a worker thread.
It's definitely not a complete solution, it would just help with this particular problem, i.e. responsiveness.


BTW: Did you check how long it takes in C++ space to copy a complete canvas tree of KNUQ (i.e. process all nodes)?
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby Hooray » Thu Sep 20, 2012 2:51 pm

TheTom wrote:
Hooray wrote:For example, In C++:
- modify the canvas group such that it always renders to a separate canvas (i.e. nested canvas), i.e. a "sub texture"
- render each group asynchronously (to the group-specific texture)
- so that we have one texture per group (that can be easily cached/reused)
- combine the final output by going through all active/enabled groups and merging all group textures

I already had something similar in mind. I just don't know yet how to do (fast) one-time render-to-texture with OSG. I don't know if you have tried using recursive canvas, but it somehow has a noticeable performance impact. Loads of possibilities for improvements :)

BTW: I just finished running fgfs via oprofile, and there, the canvas system shows up pretty prominently now - and because you mention shiva, one of the hotspots in shiva seems to be in shPaintArrayFind

And then, it's mostly:
osg::Group::traverse(osg::NodeVisitor&)
fgfs canvas::Map::update(double)


TheTom wrote:
hooray wrote:PS: Even on my main computer, rendering KNUQ with taxiways takes 10 seconds :D

Every frame? For me this takes about 140-150ms additionally. What should improve rendering time significantly is putting all taxiways in a single path (if not I'll have to modify ShivaVG).

No, 10 seconds just during instantiation - and afterwards, the frame latency is up to 100-120ms here, with ~10 fps from then on
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby Hooray » Thu Sep 20, 2012 3:19 pm

What I tried to mention earlier is this: The Canvas is basically a fully interactive state machine, so that it will permanently re-compute its internal state when properties are written to the tree.
However, in cases where we write lots of state subsequently to the tree, it might be better to disable this interactive "processing", dump all the data to the tree, and then explicitly trigger a signal to parse/process the new tree. That should prevent a fair amount of listener invocations, because there would be only a single invocation to parse the whole/complete tree.
That would also make it possible to spread the parsing/processing of the tree across multiple frames optionally.

For example, here's a typical backtrace when interrupting the KNUQ instantiation (look at all the valueChanged() calls):

Code: Select all
#0  0x0000000000aec8f3 in canvas::Element::valueChanged (this=0xae3175, child=0x7fffffffba70) at /home/hooray/sources/flightgear/src/Canvas/elements/element.cxx:210
#1  0x0000000000ae1249 in Canvas::valueChanged (this=0xf1a58b0, node=0xf11ff90) at /home/hooray/sources/flightgear/src/Canvas/canvas.cxx:375
#2  0x00000000012faf8a in SGPropertyNode::fireValueChanged (this=0xf1a5800, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2089
#3  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0xf1b3df0, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#4  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0xf1b3030, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#5  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0xf2282e0, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#6  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0xf182ab0, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#7  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0xf11dbe0, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#8  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0xf11ff90, node=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#9  0x00000000012faedd in SGPropertyNode::fireValueChanged (this=0xf11ff90) at /home/hooray/sources/simgear/simgear/props/props.cxx:2069
#10 0x00000000012fca35 in SGPropertyNode::set_string (this=0xf11ff90, val=0x10940970 "E-122.052756307043") at /home/hooray/sources/simgear/simgear/props/props.cxx:508
#11 0x00000000012f9aac in SGPropertyNode::setStringValue (this=0xf11ff90, value=0x10940970 "E-122.052756307043") at /home/hooray/sources/simgear/simgear/props/props.cxx:1523
#12 0x0000000000e7a4c2 in f_setValue (c=0x73a1960, me=..., argc=2, args=0x73a2590) at /home/hooray/sources/flightgear/src/Scripting/nasal-props.cxx:231
#13 0x00000000012db19b in setupFuncall (ctx=0x73a1960, nargs=2, mcall=0, named=0) at /home/hooray/sources/simgear/simgear/nasal/code.c:316
#14 0x00000000012ded43 in run (ctx=0x73a1960) at /home/hooray/sources/simgear/simgear/nasal/code.c:708
#15 0x00000000012dfd90 in naCall (ctx=0x73a1960, func=..., argc=4, args=0x7fffffffc230, obj=..., locals=...) at /home/hooray/sources/simgear/simgear/nasal/code.c:873
#16 0x0000000000e6cf75 in FGNasalSys::callMethod (this=0x704cb10, code=..., self=..., argc=4, args=0x7fffffffc230, locals=...) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:138
#17 0x0000000000e6cef2 in FGNasalSys::call (this=0x704cb10, code=..., argc=4, args=0x7fffffffc230, locals=...) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:123
#18 0x0000000000e71f5e in FGNasalListener::call (this=0xf1b2070, which=0xbb1d340, mode=...) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:1039
#19 0x0000000000e72029 in FGNasalListener::valueChanged (this=0xf1b2070, node=0xbb1d340) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:1047
#20 0x00000000012faf8a in SGPropertyNode::fireValueChanged (this=0xbb1d340, node=0xbb1d340) at /home/hooray/sources/simgear/simgear/props/props.cxx:2089
#21 0x00000000012faedd in SGPropertyNode::fireValueChanged (this=0xbb1d340) at /home/hooray/sources/simgear/simgear/props/props.cxx:2069
#22 0x00000000012fca35 in SGPropertyNode::set_string (this=0xbb1d340, val=0x712dea0 "KNUQ") at /home/hooray/sources/simgear/simgear/props/props.cxx:508
#23 0x00000000012f98db in SGPropertyNode::setStringValue (this=0xbb1d340, value=0x712dea0 "KNUQ") at /home/hooray/sources/simgear/simgear/props/props.cxx:1492
#24 0x00000000012faa49 in SGPropertyNode::setStringValue (this=0x1988540, relative_path=0x7fffffffc520 "/sim/gui/dialogs/airports/selected-airport/id", value=0x712dea0 "KNUQ")
    at /home/hooray/sources/simgear/simgear/props/props.cxx:1928
#25 0x0000000000e6dc46 in f_setprop (c=0x70f79e0, me=..., argc=2, args=0x70f85f0) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:278
#26 0x00000000012db19b in setupFuncall (ctx=0x70f79e0, nargs=2, mcall=0, named=0) at /home/hooray/sources/simgear/simgear/nasal/code.c:316
#27 0x00000000012ded43 in run (ctx=0x70f79e0) at /home/hooray/sources/simgear/simgear/nasal/code.c:708
#28 0x00000000012dfd90 in naCall (ctx=0x70f79e0, func=..., argc=0, args=0x0, obj=..., locals=...) at /home/hooray/sources/simgear/simgear/nasal/code.c:873
#29 0x0000000000e6cf75 in FGNasalSys::callMethod (this=0x704cb10, code=..., self=..., argc=0, args=0x0, locals=...) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:138
#30 0x0000000000e6cef2 in FGNasalSys::call (this=0x704cb10, code=..., argc=0, args=0x0, locals=...) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:123
#31 0x0000000000e70e98 in FGNasalSys::handleCommand (this=0x704cb10, moduleName=0xf1742a0 "__dlg:airports", fileName=0x1097c248 "/sim/bindings/gui/binding[9]", src=0xf1741d0 "listbox()", arg=0xf1740b0)
    at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:861
#32 0x0000000000e70f52 in FGNasalSys::handleCommand (this=0x704cb10, arg=0xf1740b0) at /home/hooray/sources/flightgear/src/Scripting/NasalSys.cxx:873
#33 0x0000000000a32cc9 in do_nasal (arg=0xf1740b0) at /home/hooray/sources/flightgear/src/Main/fg_commands.cxx:180
#34 0x000000000130c701 in SGBinding::fire (this=0xf174380) at /home/hooray/sources/simgear/simgear/structure/SGBinding.cxx:68
#35 0x0000000000ba7a73 in action_callback (object=0x71e0d60) at /home/hooray/sources/flightgear/src/GUI/FGPUIDialog.cxx:423




This demonstrates that this particular problem wouldn't be addressed by creating canvas layers in C++ instead of Nasal
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby Hooray » Thu Sep 20, 2012 3:25 pm

What's a little surprising is that once the map is completely drawn, the canvas::Path::childChanged() method still gets invoked at frame rate - even though, there shouldn't be anything modifying the vector data:

Code: Select all
#0  0x00007ffff46dcb8b in std::string::compare(char const*) const () from /usr/lib/libstdc++.so.6
#1  0x0000000000a39348 in std::operator==<char, std::char_traits<char>, std::allocator<char> > (__lhs=..., __rhs=0x13b7b14 "cmd") at /usr/include/c++/4.4/bits/basic_string.h:2267
#2  0x0000000000afbd5d in canvas::Path::childChanged (this=0xfdecd60, child=0x10bbe100) at /home/hooray/sources/flightgear/src/Canvas/elements/path.cxx:392
#3  0x0000000000aeca5c in canvas::Element::valueChanged (this=0xfdecd60, child=0x10bbe100) at /home/hooray/sources/flightgear/src/Canvas/elements/element.cxx:229
#4  0x00000000012faf8a in SGPropertyNode::fireValueChanged (this=0xf2f1750, node=0x10bbe100) at /home/hooray/sources/simgear/simgear/props/props.cxx:2089
#5  0x00000000012fafcf in SGPropertyNode::fireValueChanged (this=0x10bbe100, node=0x10bbe100) at /home/hooray/sources/simgear/simgear/props/props.cxx:2093
#6  0x00000000012faedd in SGPropertyNode::fireValueChanged (this=0x10bbe100) at /home/hooray/sources/simgear/simgear/props/props.cxx:2069
#7  0x00000000012fc991 in SGPropertyNode::set_double (this=0x10bbe100, val=-73.521476745605469) at /home/hooray/sources/simgear/simgear/props/props.cxx:490
#8  0x00000000012f96a9 in SGPropertyNode::setDoubleValue (this=0x10bbe100, value=-73.521476745605469) at /home/hooray/sources/simgear/simgear/props/props.cxx:1441
#9  0x0000000000af77bc in canvas::GeoNodePair::setScreenPos (this=0x10319d40, x=22.1549797, y=-73.5214767) at /home/hooray/sources/flightgear/src/Canvas/elements/map/geo_node_pair.hxx:99
#10 0x0000000000af6404 in canvas::Map::update (this=0xf1b3110, dt=0.14999999999999999) at /home/hooray/sources/flightgear/src/Canvas/elements/map.cxx:85
#11 0x0000000000af2511 in canvas::Group::update (this=0xf1b3eb0, dt=0.14999999999999999) at /home/hooray/sources/flightgear/src/Canvas/elements/group.cxx:47
#12 0x0000000000af2511 in canvas::Group::update (this=0xf1a5ac0, dt=0.14999999999999999) at /home/hooray/sources/flightgear/src/Canvas/elements/group.cxx:47
#13 0x0000000000ae046d in Canvas::update (this=0xf1a58b0, delta_time_sec=0.14999999999999999) at /home/hooray/sources/flightgear/src/Canvas/canvas.cxx:156
#14 0x0000000000b18028 in PropertyBasedMgr::update (this=0x222b730, delta_time_sec=0.14999999999999999) at /home/hooray/sources/flightgear/src/Canvas/property_based_mgr.cxx:44


The shiva side of things shows shPaintArrayFind as one of the more common hotspots:


Code: Select all
#0  0x000000000139722d in shPaintArrayFind (a=0xf25e5d0, item=0x1101dbf0) at /home/hooray/sources/flightgear/src/Canvas/ShivaVG/src/shArrayBase.h:340
#1  0x000000000138de26 in shIsValidPaint (c=0xf25dfd0, h=0x1101dbf0) at /home/hooray/sources/flightgear/src/Canvas/ShivaVG/src/shContext.c:209
#2  0x0000000001397603 in vgSetPaint (paint=0x1101dbf0, paintModes=2) at /home/hooray/sources/flightgear/src/Canvas/ShivaVG/src/shPaint.c:107
#3  0x0000000000afd4e3 in canvas::PathDrawable::drawImplementation (this=0xfb2f1f0, renderInfo=...) at /home/hooray/sources/flightgear/src/Canvas/elements/path.cxx:209

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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby TheTom » Thu Sep 20, 2012 3:45 pm

Hooray wrote in Thu Sep 20, 2012 3:25 pm:What's a little surprising is that once the map is completely drawn, the canvas::Path::childChanged() method still gets invoked at frame rate - even though, there shouldn't be anything modifying the vector data:

I've checked this one. It's caused by updating the zoom level with a timer. If only updating the range of the map when it actually changes I gain about 70ms. This is because the on a range change the map currently has to reproject every point which is specified using lat/lon.
TheTom
 
Posts: 321
Joined: Sun Oct 09, 2011 10:20 am

Re: Performance issues

Postby Hooray » Thu Sep 20, 2012 3:59 pm

Yes, I just noticed that, too - I guess that proves the earlier point that we need to fix the timer-based "updateZoom" approach ...and use properties that can be attached to layers, which isn't too bad, because the timer was leaking anyhow ;-)

So that we can have a number of "feature layers" for airports, navaids, fixes, tower, parking positions etc - and then just update them by linking a property to a callback in the form of:

setlistener("/foo/bar/toggle-runways", func mymap.update_zoom_layer( canvas.map.layers.RUNWAYS ) ) ;


PS: Profiling again, this time, without the timer-based zoom function.
EDIT: Google PerfTools:

Image
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby Hooray » Thu Sep 20, 2012 9:43 pm

Here's a little patch that adds two new fgcommands to FG in order to directly integrate the Google PerfTools into fgfs (optionally) - this makes it possible to easily invoke the profiler for specific phases of the code, i.e. you'll get extremely fine-grained information on what's going on - just by wrapping the code (functions/loops) in between the fgcommands:

Code: Select all
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 617d93d..fb3992e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -153,6 +153,9 @@ find_package(OpenGL  REQUIRED)
 find_package(OpenAL  REQUIRED)
 find_package(OpenSceneGraph 3.0.0 REQUIRED osgText osgSim osgDB osgParticle osgFX osgUtil osgViewer osgGA)
 
+# check optionally supported dependencies
+find_package(GooglePerfTools)
+
 if(ENABLE_FGADMIN)
     find_package(FLTK)
 
diff --git a/CMakeModules/FindGooglePerfTools.cmake b/CMakeModules/FindGooglePerfTools.cmake
new file mode 100644
index 0000000..bb125d5
--- /dev/null
+++ b/CMakeModules/FindGooglePerfTools.cmake
@@ -0,0 +1,66 @@
+# -*- cmake -*-
+
+# - Find Google perftools
+# Find the Google perftools includes and libraries
+# This module defines
+#  GOOGLE_PERFTOOLS_INCLUDE_DIR, where to find heap-profiler.h, etc.
+#  GOOGLE_PERFTOOLS_FOUND, If false, do not try to use Google perftools.
+# also defined for general use are
+#  TCMALLOC_LIBRARIES, where to find the tcmalloc library.
+#  STACKTRACE_LIBRARIES, where to find the stacktrace library.
+#  PROFILER_LIBRARIES, where to find the profiler library.
+
+FIND_PATH(GOOGLE_PERFTOOLS_INCLUDE_DIR google/heap-profiler.h
+/usr/local/include
+/usr/include
+)
+
+SET(TCMALLOC_NAMES ${TCMALLOC_NAMES} tcmalloc)
+FIND_LIBRARY(TCMALLOC_LIBRARY
+  NAMES ${TCMALLOC_NAMES}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+    SET(TCMALLOC_LIBRARIES ${TCMALLOC_LIBRARY})
+    SET(GOOGLE_PERFTOOLS_FOUND "YES")
+ELSE (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+  SET(GOOGLE_PERFTOOLS_FOUND "NO")
+ENDIF (TCMALLOC_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+
+SET(STACKTRACE_NAMES ${STACKTRACE_NAMES} stacktrace)
+FIND_LIBRARY(STACKTRACE_LIBRARY
+  NAMES ${STACKTRACE_LIBRARY}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+    SET(STACKTRACE_LIBRARIES ${STACKTRACE_LIBRARY})
+ENDIF (STACKTRACE_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+
+SET(PROFILER_NAMES ${PROFILER_NAMES} profiler)
+FIND_LIBRARY(PROFILER_LIBRARY
+  NAMES ${PROFILER_LIBRARY}
+  PATHS /usr/lib /usr/local/lib
+  )
+
+IF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+    SET(PROFILER_LIBRARIES ${PROFILER_LIBRARY})
+ENDIF (PROFILER_LIBRARY AND GOOGLE_PERFTOOLS_INCLUDE_DIR)
+
+IF (GOOGLE_PERFTOOLS_FOUND)
+   IF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY)
+      MESSAGE(STATUS "Found Google perftools: ${GOOGLE_PERFTOOLS_LIBRARIES}")
+   ENDIF (NOT GOOGLE_PERFTOOLS_FIND_QUIETLY)
+ELSE (GOOGLE_PERFTOOLS_FOUND)
+   IF (GOOGLE_PERFTOOLS_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "Could not find Google perftools library")
+   ENDIF (GOOGLE_PERFTOOLS_FIND_REQUIRED)
+ENDIF (GOOGLE_PERFTOOLS_FOUND)
+
+MARK_AS_ADVANCED(
+  TCMALLOC_LIBRARY
+  STACKTRACE_LIBRARY
+  PROFILER_LIBRARY
+  GOOGLE_PERFTOOLS_INCLUDE_DIR
+  )
diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt
index d3fc203..5cadc1c 100644
--- a/src/Main/CMakeLists.txt
+++ b/src/Main/CMakeLists.txt
@@ -91,6 +91,11 @@ endif()
 include_directories(${PROJECT_SOURCE_DIR}/src/Canvas/ShivaVG/include)
 add_definitions(-DVG_API_EXPORT)
 
+if (GOOGLE_PERFTOOLS_FOUND)
+  target_link_libraries(fgfs profiler)
+endif(GOOGLE_PERFTOOLS_FOUND)
+
+
 target_link_libraries(fgfs
    ${SIMGEAR_LIBRARIES}
    ${OPENSCENEGRAPH_LIBRARIES}
diff --git a/src/Main/fg_commands.cxx b/src/Main/fg_commands.cxx
index f9efa5b..f6d4707 100644
--- a/src/Main/fg_commands.cxx
+++ b/src/Main/fg_commands.cxx
@@ -53,12 +53,15 @@
 
 #include <boost/scoped_array.hpp>
 
+#if GOOGLE_PERFTOOLS_FOUND==YES
+  #include <google/profiler.h>
+#endif
+
 using std::string;
 using std::ifstream;
 using std::ofstream;
 
 
-
 ////////////////////////////////////////////////////////////////////////
 // Static helper functions.
 ////////////////////////////////////////////////////////////////////////
@@ -1503,6 +1506,39 @@ do_release_cockpit_button (const SGPropertyNode *arg)
 
   return true;
 }
+
+// http://code.google.com/p/gperftools/
+
+#if GOOGLE_PERFTOOLS_FOUND != YES
+static void
+no_profiling_support() {
+  SG_LOG(SG_GENERAL, SG_ALERT, "Google Performance Tools not found during configuration (reconfigure/rebuild needed)!");
+}
+#endif
+
+static bool
+do_profiler_start(const SGPropertyNode *arg) {
+#if GOOGLE_PERFTOOLS_FOUND == YES
+  const char *filename = arg->getStringValue("filename", "fgfs.profile"); 
+  ProfilerStart(filename);
+  return true;
+#else
+  no_profiling_support();
+  return false;
+#endif
+
+}
+
+static bool
+do_profiler_stop(const SGPropertyNode *arg) {
+#if GOOGLE_PERFTOOLS_FOUND == YES
+  ProfilerStop();
+  return true;
+#else
+  no_profiling_support();
+  return false;
+#endif
+}
   
 ////////////////////////////////////////////////////////////////////////
 // Command setup.
@@ -1578,7 +1614,11 @@ static struct {
     { "print-visible-scene", do_print_visible_scene_info },
     { "reload-shaders", do_reload_shaders },
     { "reload-materials", do_materials_reload },
-
+   /* Starts/stops the Google PerfTools: http://code.google.com/p/gperftools/ */
+#if GOOGLE_PERFTOOLS_FOUND==YES
+    { "profiler-start", do_profiler_start },
+    { "profiler-stop",  do_profiler_stop },
+#endif
     { 0, 0 }         // zero-terminated
 };


To test it, apply this patch (base package):
Code: Select all
diff --git a/Nasal/canvas/map.nas b/Nasal/canvas/map.nas
index 8aaeab8..c293cde 100644
--- a/Nasal/canvas/map.nas
+++ b/Nasal/canvas/map.nas
@@ -56,7 +56,7 @@ var AirportMap = {
   # @param park  Whether to display parking positions (default = 1)
   # @param twr   Whether to display tower positions (default = 1)
   new: func(apt, rwy=1, taxi=1, park=1, twr=1)
-  {
+  { fgcommand("profiler-start");
     return {
       parents: [AirportMap],
       _apt: apt,

diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml
index 623c93d..0a9df79 100644
--- a/gui/dialogs/airports.xml
+++ b/gui/dialogs/airports.xml
@@ -582,11 +582,12 @@
           ]]>
           </load>
           <close><![CDATA[
-            foreach (var listener, listeners)
+            foreach (var listener; listeners)
             {
               removelistener(listener);     
             
-            }         
+            }
+      fgcommand("profiler-stop");         
           ]]>
           </close>
         </nasal>

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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby stuart » Fri Sep 21, 2012 9:01 am

Hi Guys,

FYI, I checked in a fix to chang the zoom function to a listener last night.

I've also got a fix to create all the taxiways as a single Node which I hope to check in tonight. This improves p

-Stuart
G-MWLX
User avatar
stuart
Moderator
 
Posts: 1469
Joined: Wed Nov 29, 2006 9:56 am
Location: Edinburgh
Callsign: G-MWLX

Re: Performance issues

Postby Hooray » Fri Sep 21, 2012 10:16 am

re-doing the way taxiways are drawn, only touches a single place - right?

Please see the patch here, where drawing of all elements has been moved to separate functions to prepare things for a real OOP design. You'll find that you can easily copy your changes and replace the function body of the "draw_taxiways" function in map_layers.nas with the conditional block , i.e. :

Code: Select all
if (me._display_taxiways)
{
}


You don't even need to replace the variables used, because the me reference is simply passed to the helper for the time being.

I have now changed the code such that it uses different layers (groups) for each type of feature (runways, parking, tower, taxiways) - this makes it trivial to assign a specific listener to handle updating a certain layer, instead of sharing a single "updateMap" function (and canvas group) for all features - which also speeds up things - not during instantiation, but during use.
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Re: Performance issues

Postby Hooray » Fri Sep 21, 2012 11:27 am

Here's another profiling run using the latest changes in git (i.e. no more timer-based updateZoom):

Image

This is based on keeping fgfs running for 8 hrs with the airport selection dialog open and showing KNUQ (with taxiways).
The profiler is set up such that it only shows the overhead caused by files in $FG_SRC/Canvas (i.e. including ShivaVG).

So, with the current implementation, we still see ~65% time spent in shPaintArrayFind and ~16% in shPaintPathFind, i.e. 80% is spent in Shiva alone.
But even without looking at the ShivaVG implementation, this is something where "lazy" rendering would obviously improve things significantly because the texture would only need to be redrawn once it gets updated.

On the other hand, that wouldn't help us much when rendering dynamic maps - such as the Map dialog, showing AI/MP traffic etc.
So reducing the amount of nodes that we write to the property tree, but also the amount of work done by Shiva would seem like a good idea.

As a next test case, it would be interesting to see how much of an effect zooming has. And once we use different layers, we can also check how long it takes to update the map once layers get continously toggled as a stress test (which is easy enough to do in Nasal).
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: 11376
Joined: Tue Mar 25, 2008 8:40 am

Next

Return to Canvas

Who is online

Users browsing this forum: No registered users and 1 guest