> On Jan. 20, 2011, 10:57 p.m., Merov Linden wrote:
> > I fail to see how any of those changes "massively prevents object 
> > duplication". I don't disagree with any of them but I don't see much value 
> > in any either. Sure, there are different ways to skin a cat and some are 
> > better. Still, these changes will likely make upcoming merges conflict 
> > annoyingly and make the life of the maintainers (i.e. mine and Oz) horrid. 
> > It reminded me of this post by another (more famous) Open Source 
> > maintainer: http://tirania.org/blog/archive/2010/Dec-31.html

Hi Merov!

Firstly, I completely agree with the Open Source maintainer article, and I 
understand why this patch made you think it. However, being aware of this fact 
I don't think I made such changes to code that didn't already need change 
anyway. In fact, although certain styles used in the code are a horror in my 
eyes, I still don't change it-- even when I change those lines to fix a bug-- 
when the context around it all use the same style. A lot of style in the viewer 
code changes from file to file and even from function to function, but I try to 
preserve the style used at that point in the code.

But back to the subject at hand.

Surely you know most of the following already: I'm not writing this just for 
you but more in general for anyone reading this review (to produce some of the 
output below, I had to recompile the viewer several times, so I have some time 
to write this ;). Perhaps the two of us can talk about it on IRC, as well, if 
you want. In the line of the article that you linked to ;) ... you might just 
want to skip this long post to where it say ******START HERE******.

An important concept to understand this patch is what is called Plain Old Data 
(POD). All built-in types are POD, as well as struct's that that only have POD 
members (in particular, have no user-defined constructor or destructor, for the 
gory definition read http://en.wikipedia.org/wiki/Plain_old_data_structure) 
other then the ones generated by the compiler. Why does this matter?

Well, consider we have two .cpp source files, source1.cpp and source2.cpp, both 
of which include the same header:

source1.cpp:

#include "header.h"
//...
int main() { }

source2.cpp:

#include "header.h"
//...

Further more, assume that the header defines a few constants:

header.h:

typedef int POD1;
struct POD2 { POD1 i1; POD1 i2; };

POD1 const const1 = 1;
POD2 const const2 = { 2, 2 };

struct nonPOD { POD1 i; nonPOD(int i_) : i(i_) { } };

nonPOD const const3(3);


Here, the struct nonPOD is not a POD type because it
has a user defined constructor. Note that
'nonPOD const const3 = { 3 }' would not compile,
as such initialization is only allowed for POD types.


First we'd compile both source files:

g++ -o source1.o -c source1.cpp
g++ -o source2.o -c source2.cpp

And then link them:

g++ -o test source1.o source2.o

We can use the utility nm(1) to dump the symbols
of each object file:

$ nm -C ./source1.o | egrep '(const[0-9]|POD)'
0000000000000000 r const1
0000000000000004 r const2
0000000000000000 b const3
0000000000000000 W nonPOD::nonPOD(int)

Here, just showing the interesting stuff (symbols containing 'const' or 'POD'),
we see all three constants, and the constructor of nonPOD.
Note that const1 and const2 have an 'r' in front of them while const3 has a 'b'.
This means respectively 'read-only section' and 'uninitialized section'.
The uninitialized section is not part of the final executable, it is space
allocated in memory at the moment an executable is started and subsequently
initialized, so it doesn't contribute the size of the executable but it
does cause more memory to be used during run time.

The other object file, source2.o has of course the exact
same output:

$ nm -C ./source2.o | egrep '(const[0-9]|POD)'
0000000000000000 r const1
0000000000000004 r const2
0000000000000000 b const3
0000000000000000 W nonPOD::nonPOD(int)

Finally we can look at the end result, the linked executable:

$ nm -C test | egrep '(const[0-9]|POD)'
000000000040071c r const1
0000000000400724 r const1
0000000000400720 r const2
0000000000400728 r const2
0000000000600b10 b const3
0000000000600b14 b const3
00000000004005d2 W nonPOD::nonPOD(int)

And as you see all constants appear twice in the executable.
Nothing we can do about that (until we compile with optimization,
see below).

Note that nm uses certain debug information.
If we strip the executable, like so;

$ strip test
$ nm -C test | egrep '(const[0-9]|POD)'
nm: test: no symbols

So clearly this doesn't give the REAL picture, but
good enough for this explanation.

If now we compile with optimization, which should
be the case that concerns us most, then the
results becomes:

$ g++ -O -o source1.o -c source1.cpp
$ g++ -O -o source2.o -c source2.cpp
$ g++ -o test source1.o source2.o
00000000006009f0 b const3
00000000006009f4 b const3

In other words, optimizing is able to
get rid of POD constants, but not of
non-POD constants: the compiler doesn't
see or know that these will become
identical (and in fact, if we'd
take the pointer of them in yet
other source files, then those
_should_ be different).

This is why it's at least good practise
to put non-POD constants NOT in a header file:
You don't gain anything with it, except
creating duplicates.


Now lets have a look at these results for do-not-directly-run-secondlife-bin
(RELEASE mode, so with optimization).

Here we need to use a more elaborate command line in order to get rid
of not so interesting information: We dump all symbols, filter out only
the ones in the read-only section and the uninitialized section, strip
of all output except the mangled symbol name, then sort the symbol names
alphabetically (not removing duplicates) and pipe that into 'uniq -c'
which prints each symbol prepended with a count of how often it occurred.
That result is piped into sort -n to sort the this result by how often
each symbol (name) occurred (largest count last) and subsequencially
through c++filt to demangle the symbols. Finally we filter out non
interesting symbols: labels (starting with .LC), __FUNCTION__ symbols
with the name of functions, the '_site' variable that occurs in the
info and warning stream macro's, so although it's name is repeated
a lot, it's really a different symbol every time.

The result is of that is:

$ nm do-not-directly-run-secondlife-bin | egrep ' (r|b) ' | sed -e 's/.* //' | 
sort | uniq -c | sort -n | c++filt | egrep -v '( \.LC|::__FUNCTION__|::_site)' 
...lots of symbols only occuring once...
      2 CSWTCH.1781
      2 FTM_GEO_SKY
      2 PANEL_PICKS
      2 sTesterName
      2 PREVIEW_HPAD
      2 PANEL_PROFILE
      2 FTM_REBUILD_VBO
      2 LSCRIPTDataSize
      2 MANIPULATOR_IDS
      2 FTM_CULL_REBOUND
      2 LSCRIPTTypeNames
      2 COLLAPSED_BY_USER
      2 FTM_CREATE_OBJECT
      2 FTM_UPDATE_WLPARAM
      2 FTM_PROCESS_OBJECTS
      2 LSCRIPTStateBitField
      2 t_panel_group_general
      2 PREVIEW_TEXTURE_HEIGHT
      2 WEARABLE_NAME_COMPARATOR
      2 icon_m
      2 icon_r
      2 shader
      2 icon_pg
      2 NEW_LINE
      2 t_places
      2 (anonymous namespace)::gResponsePtr
      3 t_inventory
      3 empty_string
      3 gDirOpposite
      3 LLVORBIS_CLIP_MAX_SAMPLES
      3 LLVORBIS_CLIP_REJECT_SIZE
      3 LLVORBIS_CLIP_REJECT_SAMPLES
      3 LLVORBIS_CLIP_MAX_SAMPLE_DATA
      3 t2
      4 r3
      5 t1
      8 OGL_TO_CFR_ROTATION
      8 r2
     12 r1
     52 r
    795 std::__ioinit

The fact that std::__ioinit occurs 795 times is because it's
used in the llinfos and llwarns etc macros as well, in many
different places.

The t2, r3, t1, r2, r1 and r, are static variables (in .cpp
files) of that name used in several places in the code.
Different symbols really. In other words, nothing wrong here.
But, this is WITH this patch.

******START HERE******

Without the patch and leaving out the symbols from above,
the output becomes:

      8 VISIBILITY_HIDDEN
      8 VISIBILITY_DEFAULT
      8 VISIBILITY_VISIBLE
      8 VISIBILITY_INVISIBLE
     24 TEXTBOX_MAGIC_TOKEN
     49 AIR_SCA_AVG
     49 AIR_SCA_INTENS
     49 gAirScaSeaLevel
    351 DEFAULT_METRIC_NAME
    518 NEG_X_AXIS
    518 NEG_Y_AXIS
    518 NEG_Z_AXIS
    518 X_AXIS
    518 Y_AXIS
    518 Z_AXIS

Thus, these are the duplicates (and how often) that
are still in the code. Agreed, not many - but that is
because you already applied SNOW-800 in the past.

This should address your,
| I fail to see how any of those changes "massively prevents object 
duplication".

Next let me comment on,
| I don't disagree with any of them but I don't see much value in any either.

I completely agree with you, I don't see much value either. Not in terms
of FPS improvements, not in link or compile times, and not even in making
the code more robust. However, since I had to be SURE - and therefore had
to redo SNOW-800... I ended up with this patch, and even though a "code
clean up" and with the bonus of getting rid of several thousand duplicated
constants here and there... I saw no reason not to commit it.

| Sure, there are different ways to skin a cat and some are better.
| Still, these changes will likely make upcoming merges conflict
| annoyingly and make the life of the maintainers (i.e. mine and Oz)
| horrid.

Okaayyy.. now here is where we disagree ;). I think you're extremely
exaggerating with the 'horrid', more over, I'm willing to make a bet
that you will get no collision at all (ok, not really, because you
have internal-knowledge of what other people are working on ;).

The patch can be divided in three parts:
1) A single hunk of 139 lines in indra/llcharacter/llanimationstates.cpp
   that is merely a "style" fix (almost: it's 'bad coding' in that
   causes 139 times a call to a malloc, free and a copy constructor
   of LLUUID while utterly unnecessary.
   
   I ONLY added this to THIS patch, because this change was part
   of the *original* SNOW-800 patch (which is in snowglobe 1.x,
   where these lines were MOVED from a header to the .cpp file),
   but for some reason this change wasn't copied to viewer 2.

   I have no objections whatsoever if you decide not to apply
   this hunk, but seriously - how often is THAT part of the code
   changed by other people? It's a list of UUID's for crying out
   loud. It will NOT be changed for MONTHS to come. It will
   really not cause any collisions, or merge horror, because
   nobody else changes that code, ever.

2) Four lines in indra/llcommon/llavatarconstants.h that gets
   rid of the VISIBILITY_* duplications. Surely those four
   lines won't give you a merge problem either. It's extremely
   unlikely that, until everyone merged this, anyone will
   change code near those lines, and even if some person
   does - the fix of such collision would be extremely
   trivial.

   Likewise one line in indra/llcommon/lllslconstants.h for
   TEXTBOX_MAGIC_TOKEN. One line in
   indra/llcommon/llmetricperformancetester.h for
   DEFAULT_METRIC_NAME etc... minimal changes that in
   practise are very unlikely to even cause a collision
   before this is merged to everyone, and are faster to
   fix if it happens than it took you to read this post.

3) A serious code cleanup (and getting rid of the
   duplicates) regarding the AIR_SCA (AirSca) calculations.
   I say serious, because the old code is hardly
   "maintainable" and very unclear. If you have a hard
   time reviewing it then I'm sure that is because
   it nearly impossible to follow what the OLD code
   did... Again, yes, the old code worked... so why
   apply the patch when there is a risk for collisions?
   Well, in this case it's my opinion that the old
   code is SO bad-- that now the work of cleaning
   it up is done-- it's worth the risk... especially
   because in the end, it only changes things very
   locally (indra/newview/llvosky.cpp), again not
   likely at all that anyone else will be making
   changes to that code right now (especially since
   they'd need to understand the code first - heheh,
   highly unlikely!).


Let me know what your decision is, so I can adapt
my final test repository of the collection of
the VWR* jiras that I currently have pending on
the review board.

Thanks for reading (sorry it was so long),
Aleric

   


- Aleric


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
http://codereview.secondlife.com/r/81/#review221
-----------------------------------------------------------


On Jan. 16, 2011, 5:53 a.m., Aleric Inglewood wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> http://codereview.secondlife.com/r/81/
> -----------------------------------------------------------
> 
> (Updated Jan. 16, 2011, 5:53 a.m.)
> 
> 
> Review request for Viewer.
> 
> 
> Summary
> -------
> 
> Turns out that most of my SNOW-800 patch was included in Viewer 2 (albeit 
> without crediting me).
> However, not everything was used and some more cleaning up was possible.
> 
> After this patch, and when compiling with optimization, there are no 
> duplicates left
> anymore that shouldn't be there in the first place: apart from the debug 
> stream
> iostream guard variable, there are several static variables with the same 
> name (r, r1,
> r2, etc) but that indeed actually different symbol objects. Then there are a 
> few
> constant POD arrays that are duplicated a hand full of times because they are
> accessed with a variable index (so optimizing them away is not possible). I 
> left them
> like that (although defining those as extern as well would have been more 
> consistent
> and not slower; in fact it would be faster theoretically because those arrays 
> could
> share the same cache page then). 
> 
> 
> This addresses bug VWR-24312.
>     http://jira.secondlife.com/browse/VWR-24312
> 
> 
> Diffs
> -----
> 
>   doc/contributions.txt 422f636c3343 
>   indra/llcharacter/llanimationstates.cpp 422f636c3343 
>   indra/llcommon/llavatarconstants.h 422f636c3343 
>   indra/llcommon/lllslconstants.h 422f636c3343 
>   indra/llcommon/llmetricperformancetester.h 422f636c3343 
>   indra/llmath/llcamera.h 422f636c3343 
>   indra/llmath/llcamera.cpp 422f636c3343 
>   indra/newview/llviewerobject.cpp 422f636c3343 
>   indra/newview/llvoavatar.cpp 422f636c3343 
>   indra/newview/llvosky.h 422f636c3343 
>   indra/newview/llvosky.cpp 422f636c3343 
> 
> Diff: http://codereview.secondlife.com/r/81/diff
> 
> 
> Testing
> -------
> 
> Compiled with optimization and then running readelf on the executable to find 
> duplicated symbols.
> 
> 
> Thanks,
> 
> Aleric
> 
>

_______________________________________________
Policies and (un)subscribe information available here:
http://wiki.secondlife.com/wiki/OpenSource-Dev
Please read the policies before posting to keep unmoderated posting privileges

Reply via email to