Archived

This topic is now archived and is closed to further replies.

taguilo

XML gauge processing, performance

Recommended Posts

Hi all. I'm pretty new to gauge design, and wanted to ask some questions regarding XML gauge code processing. 1) One of my fundamental assumptions about the way FS2004 processes XML gauge code is as follows: if an entire element is subject to a condition, and that condition is not met, then the code within the element is essentially ignored, and thus there should be no performance hit. Is this assumption of mine true? Could you have, say, 10 complex elements of this type, with only one in fact "visible" at a certain time, and expect it to run as efficiently as if the gauge had only the one element to begin with? Or is there a certain level (and what IS that level? ;-) of performance hit, just because the elements are there, whether or not in fact visible?2) If you have a long statement that incorporates many A: variables, and have to use that statement over and over, is it better (from a PERFORMANCE and not just ease of code writing standpoint) to use it in its "pure," A: variable only, form, or is it better to just simply put it all into an L:Variable? In other words, I have assumed an L:variable uses exactly the same amount of computer resources as its A:variable counterpart, and thus it makes no performance difference, but I am working on something now that has made me wonder if that is indeed correct.... There's been a performance hit from somewhere, and the only major change I did was really just tidy up the code by putting long strings of A:Var calculations into L:Vars.... It's driving me crazy, and I want to make sure it's not just faulty perception on my part. I could test it, but that would be a lot of work, and I'm guessing someone has already done this... So... anyone? ;-) Thanks!Scott

Share this post


Link to post
Share on other sites
Help AVSIM continue to serve you!
Please donate today!

Hi Scott,1: Yes, IMO your assumption correct (no performance hit if Visibility is False.2. Yes, if you have to repeat the calculation several times, do it once and store the result in a temp var. (L:, G: or local var so,s1, etc). It would improve performance (fps).BUT: if I were you, I wouldn't worry at all about the performance of an XML gauge. You would have to make a VERY complex XML gauge to see any noticeable difference in framerates. I have seen full-XML panels with HUNDREDS of XML gauges, and after changing the schedule rate of those gauges (from 18 times/sec to 1, so 18 times as slow), I didn't see any framerate gain at all !!So IF you want to start optimising at all, I'll advise you to optimise on code structure (makes debugging easier :-), or better: avoids coding errors in the first place), and NOT on performance. E.g. by using Macroes (a much underestimated feature in FS, IMO :-) )And IF you would see any noticeable impact on framerate, THEN it's time to optimise on performance. But I've made 1000+ XML gauges by now, and never saw the need to optimise on performance.About your described performance problem (when using LVars to store the result of complex calculations): I'm convinced there is another cause for that, unless you are using 10000+ L:vars for it :-)In fact, the only real "performance" hit I ever saw with XML gauges, is about load times. If you have a very large set of XML gauges/bitmaps and put them in a .cab file, the load time of that aircraft will be considerably longer (because of the unzipping process). In that case it's better to do the unzipping manually, and put all the files in a subfolder with the same name as the .cab file.At the expense of disk usage of course, but who cares about a few Mbyte HD space these days ??All of the above of course is true if you have a PC that's comfortable with FS2004; if you have a PC that's allready struggling with performance at the default aircraft/scenery, then any optimisation might help and could be important.Cheers, Rob Barendregt

Share this post


Link to post
Share on other sites

Thanks Rob. Great reponse and info! I'm referring to my HUD gauge. Though it probably is a little more FPS intensive than most gauges, I have no problem at all deferring to your experience. ;-) (1,000+ gauges??? My goodness!! That's 999+ more than me, heheh. And I'm a big user of several of yours, by the way.) So now I'm wondering what's causing my problem. Maybe I did unintentionally introduce something else somewhere....(For those with time on their hands....) I'll tell you what I did. It relates to the velocity vector and the coordinate/degree system for FS's spherical world. For these very same performance reasons (or whatever I unintentionally did!) I've always settled for some weirdness with the way the vector and ladder behave near the zenith and nadir, above 80 degrees or so. I never worried too much about it, but of course now it's bugging the crap out of me.... Just because. ;-) So, obviously, the distance related to "1 degree" of azimuth/yaw/beta/or any horizontal variable should become much smaller as you get near the zenth/nadir, just as 1 degree of longitude on the Earth's surface becomes much smaller as you approach the North or South pole. So all I did was put it back like I originally had it (but abandoned because of performance), and modify the degree of horizontal vector displacement by multiplying the normal value (heading minus track, basically) by the cosine of the actual climb angle. (Not aircraft pitch.) I also then sent that whole long statement to an L: variable so I could more easily use it over and over again for all the ladder and vector elements. And it seems that performance has suffered.Here's the original:********(L:Cage switch,bool) if{ 0 } els{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor (A:PLANE HEADING DEGREES TRUE, radians) rnor - abs 0.5 < if{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor (A:PLANE HEADING DEGREES TRUE, radians) rnor - } els{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor (A:PLANE HEADING DEGREES TRUE, radians) rnor < if{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor 3.14159 + (A:PLANE HEADING DEGREES TRUE, radians) rnor - ) } els{ (A:PLANE HEADING DEGREES TRUE, radians) rnor 3.14159 + (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor - /-/ ) } } }********(By the way, if anyone knows of a way to shorten that, let me know. ;-) I've tried different ways of using modulus (%), etc., but see no way of getting around the fact that at some point the heading scale is going to instantaneously jump back down 360 degrees and lead to some weirdness when subtracting.....)And here's the modified:I put the value into the L:Var at the top:*********(L:Cage switch,bool) if{ 0 (>L:TrackDiff, radians) } els{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor (A:PLANE HEADING DEGREES TRUE, radians) rnor - abs 0.5 < if{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor (A:PLANE HEADING DEGREES TRUE, radians) rnor - (>L:TrackDiff, radians) } els{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor (A:PLANE HEADING DEGREES TRUE, radians) rnor < if{ (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor 3.14159 + (A:PLANE HEADING DEGREES TRUE, radians) rnor - (>L:TrackDiff, radians) ) } els{ (A:PLANE HEADING DEGREES TRUE, radians) rnor 3.14159 + (A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor - /-/ (>L:TrackDiff, radians) ) } } }*********Then down below I get the actual value for vector horizontal displacement by doing this:*********(L:ClimbAngle, radians) abs cos (L:TrackDiff, radians) * ("L:ClimbAngle" is merely "(A:VELOCITY WORLD Y, m/s) (A:GROUND VELOCITY, m/s) atg2 /-/", the way I have it set up.)*********That's all I've done. And there does seem to be a difference in performance. Any advice, hints, or suggestions here??? I have not done a strict test, testing performance from 1 version to the other, just because the difference seemed so obvious, but I may do that.

Share this post


Link to post
Share on other sites

Hi Scott,Well, 1000+ IS a bit too much, but I have stopped counting a while back :-)Yes, obviously "grafical" gauges like a HUD influence FPS more that just "calculating" gauges.I don't have the time right now to study your code, but how do you determine that there IS a substantial difference indeed ??I do know that above/below 86/-86 degrees Latitude, FS2004 has some "peculiarities", but I've never bothered to go into that.Rob

Share this post


Link to post
Share on other sites

Rob: It's okay, I didn't mean to imply that you're on the hook now!! Heheh. My question was for anyone who (like me) finds these little kinds of math problems "fun", but my eyes have looked at all of it for too long, and it's often good to let a new and fresh pair take a gander....As I said, I haven't tested the perfromance difference explicitly, but it was immediately noticable to me, and I've spent TONS of time just making/modifying/tweaking this 1 gauge. I can't see how simply multiplying by cos and sticking everything into an L:variable could make a diffence, so I'm now searching to see what else changed between file versions. I don't think anything else, but we'll see.... I'm inclined to agree with your assessment that it must be something else.... Thanks.Scott

Share this post


Link to post
Share on other sites

Hi Scott,>1) One of my fundamental assumptions about the way FS2004>processes XML gauge code is as follows: if an entire element>is subject to a condition, and that condition is not>met, then the code within the element is essentially ignored,>and thus there should be no performance hit. Is this>assumption of mine true? Not exactly. Only those tags that mean an output to FS, like , , etc are ignored (actually they are not displayed) but the rest of the code is executed. If you assign values to variables within the element, for example, they will be updated.>Could you have, say, 10 complex>elements of this type, with only one in fact "visible" at a>certain time, and expect it to run as efficiently as if the>gauge had only the one element to begin with? Or is there a>certain level (and what IS that level? ;-) of performance hit,>just because the elements are there, whether or not in fact>visible?XML execution of pure code is fast. In fact it is EXTREMELY fast. What makes a hit in fps performance is the display of bitmaps, vector drawings and text elements. The more complex and "heavy" they are, the bigger hit you'll notice, in general.For example if you have one in one case and say 20 in another, both on will give a "hit" in the second case, both off and there should be no difference in fps.>>2) If you have a long statement that incorporates many A:>variables, and have to use that statement over and over, is it>better (from a PERFORMANCE and not just ease of code writing>standpoint) to use it in its "pure," A: variable only, form,If you want PERFORMANCE then use the registers (s0, s1, etc) Instead of repeating AVars and/or LVars, assign them on top of an tag, then use the l0, l1, etc to reference them. And this is not a matter of writing less code, but a real processing eficiency (though I doubt it would be perceptible for 99+ of the gauges), because registers are accessed much faster than memory areas assigned to L and A vars.>or is it better to just simply put it all into an L:Variable?>In other words, I have assumed an L:variable uses exactly the>same amount of computer resources as its A:variable>counterpart, and thus it makes no performance difference, but>I am working on something now that has made me wonder if that>is indeed correct.... There's been a performance hit from>somewhere, and the only major change I did was really just>tidy up the code by putting long strings of A:Var calculations>into L:Vars.... It's driving me crazy, and I want to make sure>it's not just faulty perception on my part. I could test it,>but that would be a lot of work, and I'm guessing someone has>already done this... So... anyone? ;-) Thanks!>If you assing AVars values to LVars, just as a direct replacement, you are doing something unnecessary, that is, duplicating its value in memory. However, this shouldn't slow down your code in a noticeable way. Regards,Tom

Share this post


Link to post
Share on other sites

Scott,Maybe this "performances better" :-)(A:VELOCITY WORLD X, m/s) (A:VELOCITY WORLD Z, m/s) atg2 rnor(A:pLANE HEADING DEGREES TRUE, radians) s0(L:Cage switch,bool) if{ 0 } els{ @Macro1 l0 - abs 0.5 < if{ @Macro1 l0 - } els{ @Macro1 l0 < if{ @Macro1 3.14159 + l0 - } els{ l0 3.14159 + @Macro1 - /-/ } } }BTW, I have 3rd order polys in some of my gauges, and couldn't notice a hit in fps so far. As Rob stated, it is very difficult to measure such kind of loss in and objective way. I've been told, on the other hand, that trygo functions in XML may be resource-intensive, so perhaps you are truly noticing that :-)Tom

Share this post


Link to post
Share on other sites

Here is a little hint:For:"3.14159 +"use "pi +"Shorter, and you don't need to remember pi to 16 places (for max accuracy.Ron

Share this post


Link to post
Share on other sites

Thank you all for your responses! I've found the problem, and it was, indeed, something other than the modifications I'd mentioned above.... But hey, at least now I'll know how to use macros. ;-) Thanks again.

Share this post


Link to post
Share on other sites

>Hi Scott,>>>1) One of my fundamental assumptions about the way FS2004>>processes XML gauge code is as follows: if an entire element>>is subject to a condition, and that condition is>not met, then the code within the element is essentially>ignored, and thus there should be no performance hit. Is this>>assumption of mine true? >>Not exactly. Only those tags that mean an output to FS, like>, , etc are ignored (actually they are not>displayed) but the rest of the code is executed. If you assign>values to variables within the element, for example, they will>be updated. Which often means a lot of unnecesary XML calculations are being done all the time. I've wondered if something like: 'visible' if{ do calculations } Would eliminate that overhead. I'm not sure what bool should be used to indicate the calculations should be done.>XML execution of pure code is fast. In fact it is EXTREMELY>fast. >What makes a hit in fps performance is the display of bitmaps,>vector drawings and text elements. Yes, even expanding my Jet Test numerical display windows slows down fps at times. >If you want PERFORMANCE then use the registers (s0, s1, etc) >Instead of repeating AVars and/or LVars, assign them on top of>an tag, then use the l0, l1, etc to reference them. Also, one can use 'd' to duplicate a stack variable so it is still available after writing to an L:Variable. st d (>L:MyVar.number) (*stack top dup write*) 1 r / (>L:MyVar_inverse,number) (*load 1, rev, div, write *) I 'sn' and 'ln' all the time, but limit my usage to just a few registers. Otherwise it gets hard to remember what a register contains. 'r', reverse last two stack entries, is often useful for a reciprocal. ' 1 r / ' puts 1/st into st (top of the stack). Illustrated above also. >And this is not a matter of writing less code, but a real>processing eficiency (though I doubt it would be perceptible>for 99+ of the gauges), because registers are accessed much>faster than memory areas assigned to L and A vars. Here is a loop macro one can use to see how much a lot of looping slows down xml:@1 -- :1 ++ d @2 < if{ g1 } (* @Loop(Start,Stop) *) I had to set about 1,000,000 interations to see much slow down. It's not simply a drop in fps, more important is whether such calculations result in small pauses in the simulation. Note that is an empty loop, to do something useful in it requires another "@" argument and a s0, l0 in the loop, rather than the simple 'd'. However, when s0, etc. is used in a Macro, it can get mixed in with the same register in an internal macro. While using an L:Variable for the loop index is likely much slower. When I did try a Loop macro that allowed a string of internal calculaltions, "1 sin asin sin asin" didn't seem to slow it down that much. Note math operations on the MPX run 1 cycle for + and -, 4 cycles for *, but maybe 20 cycles for '/', and roughly 50 cycles for trig and other transcendentals. Expect 'd d * *' to do a cube much faster than ' 3 pow' Divison by 2 can potentially be done by ' ;) Note '>>' shifts st right by one bit: multiplication by 2. With loops, one might do powers and logs to base 2 more rapidly than the 'direct way'. Old time ASM programmers know the tricks. "Pentium Power" has reduced the need for efficient programming. >>it's not just faulty perception on my part. I could test it,>>but that would be a lot of work, and I'm guessing someone>has>>already done this... So... anyone? ;-) Thanks!>>If you assing AVars values to LVars, just as a direct>replacement, you are doing something unnecessary, that is,>duplicating its value in memory. However, this shouldn't slow>down your code in a noticeable way. >Tom I've been changing my "copy A:Variables to L:Variables" to A:Variable Macros. However, I think there are times when copying several A:Variables to L:Variables for latter processing is useful. Since the L:Variables are set over a short time, they don't change as A:Variables might in the middle of a string of calculations. Important when I take successive differences of something like 'TAS' to get a "Vdot" that quite stable. What we really need is an XML debugger; something that would let us step though the code and stop at breakpoints. As is available for real languages. Ron

Share this post


Link to post
Share on other sites

Hi,Did someone noticed a difference in performance when using:..All kinds of calcs.. Instead of:..All kinds of calcs..I use because it is so easy and you can put in everything you want like in the MS-GPS.Jan"Beatus Ille Procul Negotiis"

Share this post


Link to post
Share on other sites

>I've wondered if something like:>'visible'>if{ > do calculations> }>Would eliminate that overhead. I'm not sure what bool should be >used to indicate the calculations should be done.I don't think so. Whatever calculation made inside a will give 0 if the last stack value is different from 1, but that only means any kind of output not to be displayed, however the whole code will be completely executed. That's from what I've tested so far.>When I did try a Loop macro that allowed a string of internal >calculaltions, "1 sin asin sin asin" didn't seem to slow it down >that much. Note math operations on the MPX run 1 cycle for + and -, >4 cycles for *, but maybe 20 cycles for '/', and roughly 50 cycles >for trig and other transcendentals. Expect 'd d * *' to do a cube >much faster than ' 3 pow'Hey Ron, why we didn't discuss these findings of yours before? :-)I use quite a lot of "3 pow". Time to go for "d d * *" !>What we really need is an XML debugger; something that would let us >step though the code and stop at breakpoints. As is available for >real languages. Well, I don't think it would be possible to debug XML while FS is running.Maybe I am not totally right, but what I've found so far is, when loading an aircraf, FS compiles XML gauges directly into machine code. At that moment, logical structures are evaluated, macro code replaced "as is", and whatever dislikes FS will show here, it means, the gauge will be ignored, or the aircraft won't load. That's the reason why you probably won't see FS crash once the a/c is running. MS did a wonderful job whit XML RPN syntax; notice that it has an "assembler" style where you have a collection of stacks, registers, jumps, etc.; which also means it is not a "real", or "structured" language as we know of. Also is the reason to be so fast.Tom

Share this post


Link to post
Share on other sites

Jan,Never used as you describe here.I have some trouble handling which have complex macros inserted, where I often run out of stack space.I'm going to move the code in one of those elements to an section and see what happens.Tom

Share this post


Link to post
Share on other sites

>>I've wondered if something like:>>'visible'>>if{ >> do calculations>> }>>Would eliminate that overhead. I'm not sure what bool should>be >used to indicate the calculations should be done.>I don't think so. Whatever calculation made inside a >will give 0 if the last stack value is different from 1, but>that only means any kind of output not to be displayed,>however the whole code will be completely executed.>That's from what I've tested so far. There is also that panel_ID which might indicate a panel is open or closed. Regardless, I'm sure I could combine my Jet Test and Prop Test xml gauges and only calculate what is needed depending on '(A:Engine Type,enum)'. Which I already check, but don't branch on. Maybe I'll make a Macro so @EngType sets the number for the kind of powerplant. There are three, 'turbojet', 'reciprocating', and 'turboprop'. The last involves both turbine and prop calculations. -- For now, AFSD will have to do. Clearly, there are times no GPS calculations need be made. Or, they might be done every few seconds and only speeded up when necessary. >>When I did try a Loop macro that allowed a string of internal>>calculaltions, "1 sin asin sin asin" didn't seem to slow it>down >that much. Note math operations on the MPX run 1 cycle>for + and -, >4 cycles for *, but maybe 20 cycles for '/', and>roughly 50 cycles >for trig and other transcendentals. Expect>'d d * *' to do a cube >much faster than ' 3 pow'>>Hey Ron, why we didn't discuss these findings of yours before?>:-)>I use quite a lot of "3 pow". Time to go for "d d * *" ! Note a general 'power' is done with logs and 'anti-logs'. Each may take 50 cycles. A smart complier might note the integer power and do x^3 as I did. However, XML RPN is not smart. One should be able to check "@cube" vs "3 pow" in a loop. String several in 'series'. But, start with a very small number so a string of 'cubes' doesn't overflow. FP range may extend beyond 10^1024 to 10^1024, so you can cube a lot without an overflow. Note there is already 'sqr'. "@cube sqr" gives x^5. Add 'sqrt' before or after that string and one gets x^5/2. However, 'sqrt' takes some time, so so maybe even I'd use "2.5 pow". I found "1.1e5" was recognized as 110,000, but "1.1-e5" didn't work. Another rule: Always pre-calculate things that don't change in a Loop before the Loop. Early CPU's had no 'mult'. Or, it was slow. ASM programmers typically did "mult" by small integers with a series of shifts and add/subs. One could also make the code smaller by using half registers, AH was half of the 16-bit AX in an 8088. AL was the other 8 bit half. Good for 'ascii' strings. It appears the XML RPN is 'divide by zero' proof. I never had a problem I could blame on the divisor hitting zero at some iteration. Regardless, I added 'min 0.1', etc. in many places to avoid the possibility. The MS Developer's site shows what happens when standard library routines divide by zero, etc. The XML RPM may well call them and handle exceptions in a graceful way. >>What we really need is an XML debugger; something that would>let us >step though the code and stop at breakpoints. As is>available for >real languages. >Well, I don't think it would be possible to debug XML while FS>is running.>Maybe I am not totally right, but what I've found so far is,>when loading an aircraf, FS compiles XML gauges directly into>machine code. At that moment, logical structures are>evaluated, macro code replaced "as is", and whatever dislikes>FS will show here, it means, the gauge will be ignored, or the>aircraft won't load. That's the reason why you probably won't>see FS crash once the a/c is running. I'd think the RPN is only 'tokenized', as BASIC was tokenized when an ascii BASIC file was loaded. Similar for the scripts used in COM programs: 'compile' meant 'tokenize'. The stack oriented of XML RPN structure makes execution of tokenized code more efficient than other structures. But, not so easy to code. However, TurboPascal would actually compile in a second or so, and it did compile to real 'machine code'. So, it's not clear if XML RPN is just tokenized, or compiled. I'd still guess 'tokenized', since the RPN structure should make excution pretty fast even if it's left near it's original form. >MS did a wonderful job whit XML RPN syntax; notice that it has>an "assembler" style where you have a collection of stacks,>registers, jumps, etc.; which also means it is not a "real",>or "structured" language as we know of. Also is the reason to>be so fast.>Tom Now if one could only do indexed array's. ;) Note one can test some of his RPN code with an H-P RPN calculator. Which tyically supported 20 registers, r, d, and nearly the same set of math operations FS RPN does. Or, find a Desktop RPN calculator to check calculations with. Ron

Share this post


Link to post
Share on other sites

>The stack oriented of XML RPN structure makes execution of >tokenized code more efficient than other structures. But, not so >easy to code.Well, currently I find FS XML very easy to code. But it wasn't easy in the beginings...Once I got the core idea of RPN syntax, all started to clear up for me. >Now if one could only do indexed array's.Yes, we both tried that LVar:@macro but didn't work :-(Would have been a great solution.Now, my 3DTables do work fine, but the problem is they consume too much of an stack. That's the reason I need almost one element per table. I am going to try the option that Jan uses and see the result.Tom

Share this post


Link to post
Share on other sites