Archived

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

Russell

pointer overhead

Recommended Posts

Could pointer overhead (the this pointer, to be specific) cause about a 3% slowdown in code, for a variable that is used frequently? It was previously just an int that was accessed directly, and I stuffed it in a class, and I want to know if this slowdown is because of the extra pointer indirection, or if I''m doing something wrong with my class.
class Color {
private:
    unsigned int color;
public:
    Color () { }
    Color (unsigned int c) : color(c) { }
    void change () { color ^= 1; }
    const unsigned int & to_i () const { return color; }
};
I don''t see any reason why this should be any slower than using an int and working with that directly, other than accessing it through the this pointer.

Share this post


Link to post
Share on other sites
Hello Russell,

If it now a class member and the only way you can change it is with a class member method then there could be the problem.

Even though you have change() as a short method it is not decleared inline. And I belive compiler will create a function call there.

Try declearing it inline, also inline to_i and see it that speeds up your processing.

Lord Bart

Share this post


Link to post
Share on other sites
How do you pass objects of Color around? By value or reference? It''s got a trivial copy constructor (generated by the compiler), but it will be invoked every time you pass a Color object to a function by value:

void processColor(Color c);

Use a const reference instead:

void processColor(const Color & c);

Just a guess.

--
Dave Mikesell Software & Consulting

Share this post


Link to post
Share on other sites
Also, I would make to_i() return just an int, not a const & int. Evil programmers can still get around the const & by casting:


int main()
{
Color c(5);
cout << c.to_i() << endl;
unsigned int & ss = const_cast<unsigned int &>(c.to_i());
ss = 3;
cout << c.to_i() << endl;
}


Prints 5, then 3. By casting away the constness of the reference to your member data, it can now be modified. Returning an int is no more overhead than returning a reference.

--
Dave Mikesell Software & Consulting

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by dmikesell
Also, I would make to_i() return just an int, not a const & int.

Indeed.
quote:
Evil programmers can still get around the const & by casting:
But that''s not the reason! Evil programmers can do a lot of nasty stuff even if you return by value. I hope you were joking.
quote:
Returning an int is no more overhead than returning a reference.
Returning an int is *less* overhead, and that''s the reason to use them. Const references are accessed indirectly (and implicitely) through pointers, but if colour is returned by value, you gain direct access.
quote:
Original post by dmikesell
How do you pass objects of Color around? By value or reference? It''s got a trivial copy constructor (generated by the compiler), but it will be invoked every time you pass a Color object to a function by value:

void processColor(Color c);

Use a const reference instead:

void processColor(const Color & c);

Just a guess.
And then you''ll pass a 4-byte pointer instead of a 4-byte int, and get the slowness of indirect access.

Share this post


Link to post
Share on other sites
As far as I know,

If to_i is not decleared as inline return of a & it should have the same overhead as if return by value beacuse the code should work out to load the value form the address of color into into the reg used for the return. Which is what is happen of coping the value into the reg to return on a return by value.
Both have to copy color value into return reg and return.

But if it inline it works out to a mere assign of color to what it is assign to. Agian in inline both & and vlaue should work out at same overhead.

const is just a compile time check so does not effect runtime.

Now if it remain a function call istead of inline yes ther could be a extra indirection over the return by value.

Lord Bart

[edited by - lord bart on October 24, 2003 9:47:33 AM]

Share this post


Link to post
Share on other sites
quote:

quote:
--------------------------------------------------------------------------------
Original post by dmikesell
How do you pass objects of Color around? By value or reference? It''s got a trivial copy constructor (generated by the compiler), but it will be invoked every time you pass a Color object to a function by value:

void processColor(Color c);

Use a const reference instead:

void processColor(const Color & c);

Just a guess.
--------------------------------------------------------------------------------

And then you''ll pass a 4-byte pointer instead of a 4-byte int, and get the slowness of indirect access.


What? Color is a class, which has a copy constructor. If you pass a Color object by value, the copy constructor gets called. If you pass by const reference, it does not.

--
Dave Mikesell Software & Consulting

Share this post


Link to post
Share on other sites
All this worry about return const & of internal members is mute.
Since as a programmer you are god and can chose to change anything you want. What stops you from change private to public in the header file, nothing we are gods remember.

Agian the const is there as a check at compile time to stop a mistake on the part of the god form doing something that might not be intended, but if realy require we can change it by a simple cast.

Ah I like being a god some times.

Lord Bart

Share this post


Link to post
Share on other sites
quote:
All this worry about return const & of internal members is mute.
Since as a programmer you are god and can chose to change anything you want. What stops you from change private to public in the header file, nothing we are gods remember.



What if you don't have access to the header file? Could be owned by another department, but you *really* want write access to that member variable. That's not "being evil" or "playing god". You really think that you have a good reason to change the value, and the class designer thinks he has an encapsulated class.

--
Dave Mikesell Software & Consulting

[edited by - dmikesell on October 24, 2003 9:59:51 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by dmikesell
quote:
As far as I know,

If to_i is not decleared as inline return of a & it should have t



If a function is defined in the class body -- as to_i() is -- then it is *implicitly* defined as inline.

--
Dave Mikesell Software & Consulting


It depends on the compiler( I don't think anything in the ANSI spec say it has to be inlined in defined at time of declearation in the header file, in fact inline is only a susgestion to compiler away if it can't inline it, it won't ), and if you every take the address of this function then it is not inline, ie pass to_i() to a function pointer, compiler is forced to make in non inlined.

[edited by - lord bart on October 24, 2003 10:01:03 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Russell
Could pointer overhead (the this pointer, to be specific) cause about a 3% slowdown in code...

1. No.
quote:
Original post by Russell ...I don't see any reason why this should be any slower than using an int and working with that directly, other than accessing it through the this pointer.

2. Every function call is expensive *compared* to a simple 'native' data type assignment operation. Infact, at it's best just calling a function can be ten times slower.
3. Functions defined within the scope of a class declaration are implicitly inline. But! most compilers do not inline when in *debug mode*.
4. Class calls are not just a *this* pointer dereference. Inside of a class instantiation the *this* member is used to access invoking object members invisibly and is used in confunction with a virtual table. *This is most likely where your overhead occurs .*
If you are using MS VC then RTFMSDN. Else, get a book on C++ as this will greatly enhance your understanding of classes.
5. And Most Important!
quote:
Original post by antareus
Instead of shooting in the dark and asking on Internet message boards go get a profiler and see if it does.
What you are trying to do is profile your code so your best bet is to get a profiler and hunt down your bottleneck the right way or don't encapsulate a color val into its own class?!

[edited by - citizen3019 on October 24, 2003 10:21:54 AM]

Share this post


Link to post
Share on other sites
Ok you don't have acces to header then I don't know how you would know what the data memebres were, but agian we are gods some if you know that at byte 8 is a float and you want to change it because you have a very good reason, like the department that owns the header is not very responsive to changes.
(I know about stuff like this)

So you can change it, it not evil or good it just some you need to do.

That is the whole problem about header files in C++ and the name managling. It does not take into account the access level of data members.

I can realse a header file with only a few pubic methods and all the rest private along with data memebrs and someone can come along and change private to public and poof they can call any method and access any data member.

It would be so easy to add in access level to data member and methods which would greatly reduce the power of us user gods form changing the tome of the library gods.

But for now it is good the be the god, Yes

Lord Bart

[edited by - lord bart on October 24, 2003 10:26:26 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by citizen3019

2. Every function call is expensive *compared* to a simple ''native'' data type assignment operation. Infact, at it''s best just calling a function can be ten times slower.
3. Functions defined within the scope of a class declaration are implicitly inline. But! most compilers do not inline when in *debug mode*.
4. Class calls are not just a *this* pointer dereference. Inside of a class instantiation the *this* member is used to access invoking object members invisibly and is used in confunction with a virtual table. *This is most likely where your overhead occurs .*
If you are using MS VC then RTFMSDN. Else, get a book on C++ as this will greatly enhance your understanding of classes.
5. And Most Important!
quote:
Original post by antareus
Instead of shooting in the dark and asking on Internet message boards go get a profiler and see if it does.
What you are trying to do is profile your code so your best bet is to get a profiler and hunt down your bottleneck the right way or don''t encapsulate a color val into its own class?!


Thanks for your comments. I am using g++, and upon profiling it, there is zero sign of the Color class, which leads me to believe that everything has been inlined.

I appreciate all of the suggestions. Those little gotchas are what I''m looking for. I believe Color is passed around by value some, so I will pass it by reference and see if that changes things.

Also, I am the only one working on this (just as a hobby), so I''m not worried about any evil programmers (besides myself) corrupting my data.

Share this post


Link to post
Share on other sites
I changed every place where a Color was passed by value to passing it by const reference, and it yielded a tiny speed increase. Now the version that uses classes is only 2.25% slower than the int version (as opposed to 3% previously). So that helped, but there is still some overhead.

Is this just something you have to live with if you use a class instead of dealing directly with your basic types? Or is there still something I might be doing incorrectly?

I think 2% for being able to know that my variables are valid is worth it, but 0% for the same thing is even better

Share this post


Link to post
Share on other sites
I tried an enum. It was slower than both the class and int approaches. Basically changing a color wasn''t fast enough. It either required a conditional or a table lookup, and neither of those were as fast as a single xor. I thought some compiler would be able to optimize a statement like color = (color == white) ? black : white; into an xor, but I haven''t seen it. None of these are that much slower. I''m just wondering what the reason is for any slowdown, because as far as I can tell, it should run at exactly the same speed as the int version. Everyone I''ve asked about this class says it should be just as fast as the int, but it''s not, which makes me think I''m doing something wrong.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by dmikesell
What? Color is a class, which has a copy constructor. If you pass a Color object by value, the copy constructor gets called. If you pass by const reference, it does not.
It''s a class which is a POD-type (plain old data). Copying such a class that contains a 4-byte member through a trivial copy constructor is as fast as copying a pointer. So the passing process is as fast for both. But using a const reference has the problem of slower access times.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by dmikesell
No, I really mean you should avoid returning handles to member data, because evil (or perhaps inexperienced) programmers might find a way to get around the constness, breaking your encapsulation.
If an inexperienced programmer does a const_cast, he''s very strangely inexperienced to know of const_cast but not know that it''s dangerous.. It''s silly to design a system for the dumbest people to use, and waste time for that. And an "evil" programmer can whenever he wishes, take the pointer of any object and change all it''s contents to arbitrary numbers! Aargh, encapsulation is broken in every object you''ve ever designed, what to do what to do. (sorry if I made you have nightmares now! but reality is painful it seems)

You should honestly try a language like Lisp or Python, where there aren''t even private members or constness, yet large systems with the typical level of encapsulation are constantly being done in those languages. The language isn''t exactly enforcing it, but the language relies on programmers having at least the slightest amount of common sense to NOT access an object''s privates. Just like C++ programmers don''t generally directly access the memory given by an object''s pointer.

Share this post


Link to post
Share on other sites
quote:
Original post by dmikesell
quote:
All this worry about return const & of internal members is mute.
Since as a programmer you are god and can chose to change anything you want. What stops you from change private to public in the header file, nothing we are gods remember.



What if you don''t have access to the header file? Could be owned by another department, but you *really* want write access to that member variable. That''s not "being evil" or "playing god". You really think that you have a good reason to change the value, and the class designer thinks he has an encapsulated class.

--
Dave Mikesell Software & Consulting

[edited by - dmikesell on October 24, 2003 9:59:51 AM]


You can break ANYTHING if you really want to, so encapsulation is never guaranteed. For example, even without the header file I could, with minimal effort, directly modify a private member inside of a class. Just cast the class pointer and shoot in the dark until you find the 4 bytes where the member is stored at. Boom, no more encapsulation.

Share this post


Link to post
Share on other sites