SirPope Posted September 27, 2018 Report Share Posted September 27, 2018 I'm mainly making this post to see if I have the right ideal. I've seen some of the stuff while browsing the source / diff. Here's an example of something I made up but I'm sure the developers have already seen something similar... its overly crappy fake code btw function idkRectangle(arrayOfRects) { for(let rect of arrayOfRects) { const x0 = someMath on rect; //All of these are recreated each loop const y0 = someMath on rect; const x1 = someMath on rect; const y1 = someMath on rect; const v = new Vector(centerPoint...).rotate(someDegree/Rad); const newArrowFunction = (...) => {}; //extra bit I've seen elsewhere yata yata } }; //Isn't this faster and less data heavy? function idkRectangle(arrayOfRects) { let x0; //just created once let y0; let x1; let y1; //These could be moved to one line to save space. let v = new Vector(0,0); const newArrowFunction = (...) => {}; for(let rect of arrayOfRects) { x0 = someMath on rect; y0 = someMath on rect; x1 = someMath on rect; y1 = someMath on rect; v.set(centerPoint...).rotate(someDegree/Rad); newArrowFunction(...); yata yata } }; My guess is yes but: linting... and readability. The last one is kinda confusing. But it is faster and less data heavy right? I've seen this in area's where "speed is key". I got confused. 1 Quote Link to comment Share on other sites More sharing options...
Stan` Posted September 27, 2018 Report Share Posted September 27, 2018 Well it could be or not. Depending on how this is optimised it will or will not reuse the same address space. Which means instead of allocating and deallocating 1000000 times a 32 bits int it will only do it once. If you do that with objects it can be faster really quickly because allocation is costly. What's missing there is probably a comment saying it was tested inlining variables and it was way faster without doing so. This could also be an old C programmer habit. Some school teaches one to do it that way. The reason was at the beginning compilers couldn't use variables that were not declared at the top of the function. 1 Quote Link to comment Share on other sites More sharing options...
Guest Posted September 27, 2018 Report Share Posted September 27, 2018 (edited) I just did a simple experiment to see gcc behavior on this. int main() { for (int i = 0; i < 10; ++i) { int j = 100; } return 0; } and int main() { int i, j; for (i = 0; i < 10; ++i) { j = 100; } return 0; } Compiled to the exact same thing as expected. No difference at all. Compilers have become a *lot* smarter. This was a very simple test ofcourse and results might vary if for example, j was something like i * i (it does not vary). Not sure, I am still pretty inexperienced with these stuff. Edited September 27, 2018 by Guest Quote Link to comment Share on other sites More sharing options...
Stan` Posted September 27, 2018 Report Share Posted September 27, 2018 1 hour ago, (-_-) said: I just did a simple experiment to see gcc behavior on this. int main() { for (int i = 0; i < 10; ++i) { int j = 100; } return 0; } and int main() { int i, j; for (i = 0; i < 10; ++i) { j = 100; } return 0; } Compiled to the exact same thing as expected. No difference at all. Compilers have become a *lot* smarter. This was a very simple test ofcourse and results might vary if for example, j was something like i * i (it does not vary). Not sure, I am still pretty inexperienced with these stuff. Worth noting that inline declaration was not allowed before c99 The real question is the impact on JS Code. I also wonder if minifying it and obfuscating it would make it faster. Less bytes of code to read so faster loading in memory. 1 Quote Link to comment Share on other sites More sharing options...
SirPope Posted September 27, 2018 Author Report Share Posted September 27, 2018 (edited) Yes the JS Code is what I was wondering about. I'm pretty sure doing the below is faster as well. The array doesn't need to ask for/look up the value, it already has a reference to the data in memory. function some2dArrayFunc(arr2d) { const numberOfRows = arr2d.length; //avoid look up each condition check const numberOfColumns = arr2d[0].length; //same let row, j, i = 0; //avoid recreation each loop(?). for(; i < numberOfRows; i++) { row = arr2d[i]; //only look up and retrieve index i once. for(j = 0; j < numberOfColumns; j++) { //doStuff with row[j]; } } }; Something about not having to travel the prototype chain each time (or do error/sanity checking - if there is any internally). It somehow makes it a bit faster (but that was from some site a time ago). The speed up is probably small anyways but 0.0001 can equal a quadrillion if you add it together enough times. Poor point... So this really only applies to large amounts of operations that don't need to be 'felt' by the viewer. I don't really know if 0 ad does this, so this post could be pointless. Only thing that might be noticeably improved is map generation. I can almost say that the arrow function creation in a loop is slow. Sure, they've been sped up but you are still forcing a lot of stuff to happen each time. -- I thought minifying just lessened the load time, not necessarily the execution. If it just does that then, yeah it would technically be faster. I never looked it up or tried it. Edited September 27, 2018 by SirPope stuff about mini Quote Link to comment Share on other sites More sharing options...
SirPope Posted September 27, 2018 Author Report Share Posted September 27, 2018 (edited) 4 hours ago, stanislas69 said: This could also be an old C programmer habit. Some school teaches one to do it that way. The reason was at the beginning compilers couldn't use variables that were not declared at the top of the function. Some JavaScript interpreters 'lift' variables before the code is ran. Found a link. Seems like it doesn't apply here really. let and const are ignored so uh... 'hoist waiting' isn't an issue really. https://www.w3schools.com/js/js_hoisting.asp -- wasn't the old site I was talking about but apparently it is faster to do the .length outside the loop. I found that out at least. https://www.w3schools.com/js/js_performance.asp Edited September 27, 2018 by SirPope another link addition Quote Link to comment Share on other sites More sharing options...
Guest Posted September 27, 2018 Report Share Posted September 27, 2018 (edited) Since 0ad svn came with the source of spidermonkey, I decided to have some fun and got a debug build of it (which allows disassembling bytecode). The following js code: Spoiler function doStuff() { for (var i = 0; i < 10; ++i) { var j = i*i; } } function doStuff() { var i; var j; for (i = 0; i < 10; ++i) { j = i*i; } } Produced a somewhat different bytecode. (complete output from the js shell) Spoiler flags: loc op ----- -- main: 00000: zero 00001: setlocal 0 00005: pop 00006: goto 38 (+32) 00011: loophead 00012: getlocal 0 00016: getlocal 0 00020: mul 00021: setlocal 1 00025: pop 00026: getlocal 0 00030: pos 00031: one 00032: add 00033: setlocal 0 00037: pop 00038: loopentry 129 00040: getlocal 0 00044: int8 10 00046: lt 00047: ifne 11 (-36) 00052: retrval Source notes: ofs line pc delta desc args ---- ---- ----- ------ -------- ------ 0: 1 0 [ 0] newline 1: 2 0 [ 0] newline 2: 3 0 [ 0] colspan 5 4: 3 0 [ 0] colspan 4 6: 3 5 [ 5] for cond 32 update 20 tail 41 10: 3 11 [ 6] setline lineno 5 12: 5 11 [ 0] colspan 1 14: 5 12 [ 1] setline lineno 4 16: 4 12 [ 0] newline 17: 5 12 [ 0] colspan 5 19: 5 26 [ 14] xdelta 20: 5 26 [ 0] setline lineno 3 22: 3 26 [ 0] colspan 24 24: 3 38 [ 12] xdelta 25: 3 38 [ 0] setline lineno 5 27: 5 38 [ 0] setline lineno 3 29: 3 38 [ 0] colspan 16 31: 3 52 [ 14] xdelta 32: 3 52 [ 0] setline lineno 5 34: 5 52 [ 0] colspan 6 Exception table: kind stack start end loop 0 11 52 flags: loc op ----- -- main: 00000: getlocal 0 00004: pop 00005: getlocal 1 00009: pop 00010: zero 00011: setlocal 0 00015: pop 00016: goto 48 (+32) 00021: loophead 00022: getlocal 0 00026: getlocal 0 00030: mul 00031: setlocal 1 00035: pop 00036: getlocal 0 00040: pos 00041: one 00042: add 00043: setlocal 0 00047: pop 00048: loopentry 129 00050: getlocal 0 00054: int8 10 00056: lt 00057: ifne 21 (-36) 00062: retrval Source notes: ofs line pc delta desc args ---- ---- ----- ------ -------- ------ 0: 1 0 [ 0] newline 1: 2 0 [ 0] newline 2: 3 0 [ 0] colspan 4 4: 3 5 [ 5] newline 5: 4 5 [ 0] colspan 4 7: 4 10 [ 5] newline 8: 5 10 [ 0] colspan 5 10: 5 15 [ 5] for cond 32 update 20 tail 41 14: 5 21 [ 6] setline lineno 7 16: 7 21 [ 0] colspan 1 18: 7 22 [ 1] setline lineno 6 20: 6 22 [ 0] newline 21: 7 22 [ 0] colspan 1 23: 7 36 [ 14] xdelta 24: 7 36 [ 0] setline lineno 5 26: 5 36 [ 0] colspan 20 28: 5 48 [ 12] xdelta 29: 5 48 [ 0] setline lineno 7 31: 7 48 [ 0] setline lineno 5 33: 5 48 [ 0] colspan 12 35: 5 62 [ 14] xdelta 36: 5 62 [ 0] setline lineno 7 38: 7 62 [ 0] colspan 9 Exception table: kind stack start end loop 0 21 62 Although none of these would lead to a significant performance gain or anything, it was interesting to see the difference. Edited September 27, 2018 by Guest Quote Link to comment Share on other sites More sharing options...
Stan` Posted September 27, 2018 Report Share Posted September 27, 2018 What happens if you use let/consts ? Also a bigger loop like 1000000 Quote Link to comment Share on other sites More sharing options...
nani Posted September 27, 2018 Report Share Posted September 27, 2018 1 hour ago, (-_-) said: Since 0ad svn came with the source of spidermonkey, I decided to have some fun and got a debug build of it (which allows disassembling bytecode). The following js code: Reveal hidden contents function doStuff() { for (var i = 0; i < 10; ++i) { var j = i*i; } } function doStuff() { var i; var j; for (i = 0; i < 10; ++i) { j = i*i; } } Produced a somewhat different bytecode. (complete output from the js shell) Reveal hidden contents flags: loc op ----- -- main: 00000: zero 00001: setlocal 0 00005: pop 00006: goto 38 (+32) 00011: loophead 00012: getlocal 0 00016: getlocal 0 00020: mul 00021: setlocal 1 00025: pop 00026: getlocal 0 00030: pos 00031: one 00032: add 00033: setlocal 0 00037: pop 00038: loopentry 129 00040: getlocal 0 00044: int8 10 00046: lt 00047: ifne 11 (-36) 00052: retrval Source notes: ofs line pc delta desc args ---- ---- ----- ------ -------- ------ 0: 1 0 [ 0] newline 1: 2 0 [ 0] newline 2: 3 0 [ 0] colspan 5 4: 3 0 [ 0] colspan 4 6: 3 5 [ 5] for cond 32 update 20 tail 41 10: 3 11 [ 6] setline lineno 5 12: 5 11 [ 0] colspan 1 14: 5 12 [ 1] setline lineno 4 16: 4 12 [ 0] newline 17: 5 12 [ 0] colspan 5 19: 5 26 [ 14] xdelta 20: 5 26 [ 0] setline lineno 3 22: 3 26 [ 0] colspan 24 24: 3 38 [ 12] xdelta 25: 3 38 [ 0] setline lineno 5 27: 5 38 [ 0] setline lineno 3 29: 3 38 [ 0] colspan 16 31: 3 52 [ 14] xdelta 32: 3 52 [ 0] setline lineno 5 34: 5 52 [ 0] colspan 6 Exception table: kind stack start end loop 0 11 52 flags: loc op ----- -- main: 00000: getlocal 0 00004: pop 00005: getlocal 1 00009: pop 00010: zero 00011: setlocal 0 00015: pop 00016: goto 48 (+32) 00021: loophead 00022: getlocal 0 00026: getlocal 0 00030: mul 00031: setlocal 1 00035: pop 00036: getlocal 0 00040: pos 00041: one 00042: add 00043: setlocal 0 00047: pop 00048: loopentry 129 00050: getlocal 0 00054: int8 10 00056: lt 00057: ifne 21 (-36) 00062: retrval Source notes: ofs line pc delta desc args ---- ---- ----- ------ -------- ------ 0: 1 0 [ 0] newline 1: 2 0 [ 0] newline 2: 3 0 [ 0] colspan 4 4: 3 5 [ 5] newline 5: 4 5 [ 0] colspan 4 7: 4 10 [ 5] newline 8: 5 10 [ 0] colspan 5 10: 5 15 [ 5] for cond 32 update 20 tail 41 14: 5 21 [ 6] setline lineno 7 16: 7 21 [ 0] colspan 1 18: 7 22 [ 1] setline lineno 6 20: 6 22 [ 0] newline 21: 7 22 [ 0] colspan 1 23: 7 36 [ 14] xdelta 24: 7 36 [ 0] setline lineno 5 26: 5 36 [ 0] colspan 20 28: 5 48 [ 12] xdelta 29: 5 48 [ 0] setline lineno 7 31: 7 48 [ 0] setline lineno 5 33: 5 48 [ 0] colspan 12 35: 5 62 [ 14] xdelta 36: 5 62 [ 0] setline lineno 7 38: 7 62 [ 0] colspan 9 Exception table: kind stack start end loop 0 21 62 Although none of these would lead to a significant performance gain or anything, it was interesting to see the difference. How about making a mini profiler for JavaScript mag gen? Knowing functions times and number of calls would allow to know where are the bottle necks. Some functions are called millions times for each map gen. Quote Link to comment Share on other sites More sharing options...
Stan` Posted September 27, 2018 Report Share Posted September 27, 2018 I thought there were timers in RMGen. @elexis Quote Link to comment Share on other sites More sharing options...
Guest Posted September 27, 2018 Report Share Posted September 27, 2018 1 hour ago, nani said: How about making a mini profiler for JavaScript mag gen? Knowing functions times and number of calls would allow to know where are the bottle necks. Some functions are called millions times for each map gen. Briefly discussed with elexis and decided to have it some time ago. 25 minutes ago, stanislas69 said: I thought there were timers in RMGen. @elexis I guess it has it's limitations. Plus, it's not as precise as using JS_Now (GetMicroSeconds as exposed). Quote Link to comment Share on other sites More sharing options...
elexis Posted October 2, 2018 Report Share Posted October 2, 2018 On 9/27/2018 at 5:16 PM, (-_-) said: Briefly discussed with elexis and decided to have it some time ago. You either refer to some ticket that floats around somewhere on trac space or to the plot example over there somewhere. It allows finding the greatest bottlenecks in a specific mapgen too, (besides the textual / numeric stdout log). Quote Link to comment Share on other sites More sharing options...
Guest Posted October 2, 2018 Report Share Posted October 2, 2018 (edited) 10 minutes ago, elexis said: You either refer to some ticket that floats around somewhere on trac space or to the plot example over there somewhere. It allows finding the greatest bottlenecks in a specific mapgen too, (besides the textual / numeric stdout log). It's somewhere in the IRC logs. But you might very well be right. Regarding the support for seeing function calls and things, all that's needed would be to enable tracelogging in SM. Which can be done by editing some environment variables. More specifically (I think): TLLOG=Default TLOPTIONS = EnableActiveThread, EnableOffThread Can read the log and make a fancy graph after that. Edit:: Apparently, someone else here did the research a long time ago. https://trac.wildfiregames.com/wiki/EngineProfiling#SpiderMonkeyTracelogger (Trac page came up in a google search about Spidermonkey tracelogging) Edited October 2, 2018 by Guest Quote Link to comment Share on other sites More sharing options...
SirPope Posted October 3, 2018 Author Report Share Posted October 3, 2018 Off topic but on topic(?) I thinking: Initializing variables with values (that they are going to hold) could speed up the code. var x = 0.0; Only using x to store decimals. The JS Code is converted from untyped to typed values right? var x to float x and then to assembly. I was looking at that link and poking around on google. I found a comment about SpiderMonkeies inner workings. (misspelled but i like the way it's pronounced: Spider Monk-Easy) https://wiki.mozilla.org/IonMonkey/Overview Quote For example, consider an Ion-generated method having a 32-bit addition. If the addition operation overflows, or say it relies on an object access which happens to return a double, the compiled code is no longer valid. Guards check these assumptions, and when they fail, the method's execution resumes in the interpreter (and may later be recompiled). Not sure what it means but interpreters are usually slow. I'm not tech savvy. I'm just good at misspelligns. Quote Link to comment Share on other sites More sharing options...
Stan` Posted October 3, 2018 Report Share Posted October 3, 2018 Well technically what could speed up things is using integer arrays as opposed to object arrays. Unfortunately though I believe that needs at least SM45 support Quote Link to comment Share on other sites More sharing options...
SirPope Posted October 3, 2018 Author Report Share Posted October 3, 2018 I was a bit worried about that SM45 diff as I have an xp. It won't break the game for me. Greater than I think 52 will... Finding the 'best way to JavaScript' is kinda pointless. One browser (or version) might handle something better but the other not so much. I guess find places that would benefit having what is known to be faster and make a note of it. Attack types, maybe resources, and some other stuff comes to mind. About the byte code: Related to the typedarrays I think what's happening in the byte code is a bit of optimization. for(var i = 0; yata yate; i++) // i is an integer. I don't need to guess. Quote Link to comment Share on other sites More sharing options...
Guest Posted October 3, 2018 Report Share Posted October 3, 2018 2 hours ago, stanislas69 said: Well technically what could speed up things is using integer arrays as opposed to object arrays. Unfortunately though I believe that needs at least SM45 support The version 0AD uses support it. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.