Squared all dist_vec() based comparisons and other dist_vec() operations where sensible.
Review Request #199 - Created March 10, 2011 and submitted
Cron Stardust | Reviewers | ||
viewer | |||
VWR-25126 | |||
None | viewer-development |
I looking at the code, trying to find out where/how to add a new feature, when I tripped across one of these and it lit my mental warning bells off. Vector distance comparisons should, IMHO, always be done squared. So I did some greppin, manual analysis, and some careful modification, and here's the result.
Compiled a test viewer and used it, undertaking some of my normal activities. Results felt good, but are currently anecdotal. Any suggestions on how to properly measure this (or even some actual measurement from those already instrumented to measure these things,) would be great!
Posted (March 11, 2011, 3:53 a.m.)
Good idea. Off course, the two main rules of optimization are: 1. Don't optimize. 2. Don't optimize yet (experts only). Though, comparing squared distances instead of actual distances can probably be considered standard practice and both the proposed change as well as the resulting code are still easy to understand. Also, you already measured the operations in isolation and it's unlikely we'll have hardware that calculates square roots faster than it multiplies in the foreseeable future, so this is different than, say, bit-shifting with addition to replace integer multiplication. Still, it'd be nice to have some measurements of how this affects in-viewer performance. Some comments about the actual code:
-
indra/newview/llnetmap.cpp (Diff revision 1) -
Maybe add a short comment here, that this value is meant to be overwritten in the loop below it.
-
indra/newview/llpanelpeople.cpp (Diff revision 1) -
For clarity, please rename these variables to dist1_squared and dist2_squared, too. Or eliminate them by calling dist_vec_squared right in the return statement: return dist_vec_squared(item1_pos, me_pos) < dist_vec_squared(item2_pos, me_pos); (A bit long, but still shorter than the lines right above it.)
-
indra/newview/llselectmgr.cpp (Diff revision 1) -
This should probably start at 1e60f, now. Though ... if there is no specific reason for the previous 1e30f value, just make it F32_MAX, I guess. Might also be worth a comment, that it will be overwritten in the loop below.
-
indra/newview/llselectmgr.cpp (Diff revision 1) -
Memory reuse is good, I guess, but having variable names that only describe the variable's content correctly part of the time bothers me.
-
indra/newview/llselectmgr.cpp (Diff revision 1) -
Off course, this variable already changed meaning during execution before your change, so ... meh.
Review request changed
Updated (March 12, 2011, 6:33 a.m.)
-
- removed https://jira.secondlife.com/browse/VWR-25126
- added VWR-25126
corrected the jira link - just put the id in, not the url
Posted (March 12, 2011, 7:16 a.m.)
If the comments here are addressed, I think this is probably a good idea. I agree that making changes that might make code less clear is usually not justified by claims of performance benefit, but done carefully this change can almost certainly be beneficial and not cost any real clarity.
-
indra/llcharacter/llbvhloader.cpp (Diff revision 1) -
I think it would be clearer to either add a new constant POSITION_MOTION_THRESHOLD_SQUARED or to write these like ... < (POSTION_MOTION_THRESHOLD*POSITION_MOTION_THRESHOLD). (and same convention elsewhere)
Review request changed
Updated (March 12, 2011, 11:54 p.m.)
-
- added Diff r2
Switched to using *_SQUARED constants instead of multiplied constants, and cleaned up a few other minor issues noted during review.
Posted (March 13, 2011, 5:34 a.m.)
Thanks for the changes. Some more comments from me:
-
indra/newview/llselectmgr.cpp (Diff revisions 1 - 2) -
While were at it, the original author probably meant "factor into" when they wrote "factor inside". And although the comment doesn't begin with a *complete* sentence, I'd start it with a capital letter when further sentences follow. So make this // Factor the distance into the displacement vector. This will get us // equally visible movements for both close and far away selections.
-
indra/newview/llselectmgr.cpp (Diff revisions 1 - 2) -
Notwithstanding the comment above this code, I don't think the notion of a "factored minimal distance" makes any sense at all. (I might be mistaken, as I'm not a native speaker of English.) If we can't think of a better name (e.g. based on the actual geometric meaning of this intermediary result), just describe what we're storing here, e.g. with an ugly name like half_sqrt_of_min_dist. Because the variable is only used very locally and the computation of its value isn't too complicated, just naming it "tmp" or similar might also be acceptable, and still better than a name purporting a wrong or confusing meaning.
-
indra/llmath/tests/llbbox_test.cpp (Diff revision 2) -
While we're changing this anyway, braces around the assigned define value probably won't hurt: #define APPROX_EQUAL(a, b) (dist_vec_squared((a),(b)) < 1e-10) They protect the define from unexpected operator precedence issues when used in certain contexts, so that it acts more similar to a function. Though, one has to wonder anyway, why a define is used here rather than a function. (Which could be declared inline, if really, really necessary.)
-
indra/newview/llfloaterchat.cpp (Diff revision 2) -
If storing return values of functions (or inline computations), just so we don't have to call the function (or perform the calculation) twice to get its square is a reoccurring pattern, we might want a helper function that'll save us from having to introduce extra variables just for this purpose: // Either F32 sqr(F32 base) { return (base * base); } // Isn't something like this already available in the standard library or llmath? Maybe even as a template? // and then here F32 distance_squared = dist_vec_squared(pos_agent, chat.mPosAgent); if (distance_squared > sqr(gAgent.getNearChatRadius())) // ... // or, if this mainly occurs comparisons between distances to other values bool dist_vec_leq( LLVector3 first_position, LLVector3 second_position, F32 distance) { return ( dist_vec_squared(first_position, second_position) <= (distance * distance) ); } // and then here if (!dist_vec_leq(pos_agent, chat.mPosAgent, gAgent.getNearChatRadius())) // ... Off course, where intermediary variables help readability or understandability, we should prefer them, but I don't think that's the case here.
Review request changed
Updated (April 4, 2011, 10:34 a.m.)
-
- added Diff r3
Following the review comments above, I parenthesized a #define to make it safer, adjusted some notes (and added a TODO) around some extremely obscure code that needs further attention but which is outside this scope.
Posted (April 4, 2011, 2:33 p.m.)
-
indra/newview/llselectmgr.cpp (Diff revisions 1 - 2) -
This comment only really makes sense to those aware of this change. Those reading the code later won't easily be able to make any sense of it. As a rule of thumb, in-code comments should relate to the resulting code and commit messages to the change. If you feel you have to deviate from that, make it explicit. E.g. here, we could write: // Replaces a call to dist_vec(), which uses fsqrtf. Thus that's what we use here, too. F32 min_dist = fsqrtf(min_dist_squared);
-
indra/newview/llselectmgr.cpp (Diff revisions 2 - 3) -
Even if we decided that it is out of scope to decide what "factor" might have meant here, we can avoid having to place a FIXME comment here by just using a variable name that avoids the term. half_sqrt_of_min_dist is admittedly an ugly name and doesn't tell the reader why we would calculate it, but it is at least truthful and not misleading, so I'd really go for that for now.
-
indra/newview/llselectmgr.cpp (Diff revisions 2 - 3) -
While we're touching this code anyway, put spaces around (i.e. on both sides of) the binary * operators (multiplication). That makes it easier to visually distinguish them from unary * operators (dereference).
Posted (April 4, 2011, 4:39 p.m.)
Other reviews